diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /web | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'web')
653 files changed, 78929 insertions, 0 deletions
diff --git a/web/INSTALL b/web/INSTALL new file mode 100644 index 00000000..62ce69d6 --- /dev/null +++ b/web/INSTALL @@ -0,0 +1,361 @@ +alpine.tar.z web/INSTALL +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +BUILDING AND INSTALLING WEB ALPINE +---------------------------------- + +This file provides brief instructions for building, installing and +configuring the Web Alpine application + +Web Alpine's binary components are built along with the other Alpine +Mail System components. If the build process completed, that is the +commands ./configure and make completed without error, then you are +nearly good to go. + +Unlike the other Alpine components, however, Web Alpine does not use +the "make install" method of installation. Between the various Web +Alpine pieces, web site layout and web server configuration, +variability and administrative preference is too great to be reliably +automated at this time. + +For more information on the how's and why's of Web Alpine consult the +somewhat more technically complete treatment in +web/cgi/alpine/help/tech-notes.html. + +At some point online FAQs and such may be available. If you find +anything missing, incomplete, or otherwise unclear please send a note +to <alpine-contact@cac.washington.edu>. + + +WEB ALPINE LAYOUT +----------------- + +The Web Alpine package is distributed as part of the Alpine Mail System. +The source for the various components can be found in the "web/" +directory arranged, for the most part, by function. + + src/ + alpined.d/ + source for Web Alpine's binary components: the + per-user/per-session serverette and the small library used for + inter-tcl script communication. + + pubcookie/ + sources for various components required to provide + pubcookie web-login support + + cgi.tcl-1.10/ + Tcl library used to help coordinate web page generation + + cgi/ + CGI scripts used to generate Web Alpine pages, typically synonymous + with the web server's document root. It, in turn, contains: + + alpine/ + Meat and potatoes of the Web Alpine Application. + + alpine-2.0/ + Meat and potatoes of the Web Alpine 2.0 Application + + session/ + Alpine session management scripts used to login, establish + an alpine session, logout and aquire IMAP server credentials + as needed. These scripts are distinct from the alpine/ + scripts in order to properly scope the session key. + + images/ + Various images and icons + + pub/ + Scripts that are accessed outside the scope of the Web Alpine + session key. + + sounds/ + Sounds files that might be referenced by Web Alpine + + config/ + general Web Alpine and default host configurations + + bin/ + binary executables providing services to the CGI scripts + + lib/ + binary and script routines used by both CGI scripts + and binary utilities + +For a more thorough discussion of the distribution's layout and +Web Alpine components see cgi/alpine/help/tech-notes.html. + + +BUILDING WEB ALPINE'S BINARY COMPONENTS +--------------------------------------- + +For the most part, Web Alpine's binary components were built +automatically along with the rest of the Alpine Mail System. + +If configure reports that it could not locate suitable TCL libraries +and header files, then it is likely that the components necessary for +Web Alpine were not built. Locating and installing a TCL development +environment appropriate for your system should get the build back on +track. Note, even though a tclsh interpreter may be available on the +command line, tools necessary to build TCL applications may need to be +installed separately. + +If you plan to use UW pubcookie for browser-based network login, +please review src/pubcookie/README. Be sure the Web Alpine Mail +System was configured with the "--with-pubcookie" AND --with-web-bin= +options set. The latter is set to the directory that will eventually +contain Web Alpine's binary components. For the example system +described in the next section, you would add: + + --with-pubcookie --with-web-bin=/usr/local/libexec/alpine/bin + +to the configure script's command line. + + +ACQUIRING EXTERNAL LIBRARIES +---------------------------- + +Web Alpine 2.0 makes heavy use of the functionality provided by the +The Yahoo! User Interface Library (YUI). By default, Web Alpine is +configured to generate pages that cause user's browser to request the +necessary library files directly from Yahoo servers. + +Web Alpine can be easily configured to generate pages with references +to a local copy of the YUI libraries. + +First, you will need to download the YUI libararies from: + + http://developer.yahoo.com/yui/download/ + +They are made available to Web Alpine 2.0 scripts thru the symbolic +link: + + web/cgi/alpine-2.0/lib/yui + +Simply install the downloaded library in the directory specified by +the symbolic link, or change the link to refer to the intalled +location. + +Second, you will need to change the _wp(yui) configuration setting +in + + web/config/alpine.tcl + +to reference the new location. + + +INSTALLING WEB ALPINE COMPONENTS +-------------------------------- + +Unfortunately, due to the variety of web server requirements and +configurations, Web Alpine installation must be done by hand and +requires several steps. To illustrate the procedure, a generic Fedora +Core 8 system with standard httpd package installed is used as an +example. On other systems, the general ideas are the same but the +specific file locations and server configuation settings will likely +vary. Note also that your system may have an additional security +layer installed, such as selinux, that may require extra configuration +that is beyond the scope of this explanation. + +The first step is to build and configure the tools Web Alpine needs to +generate pages and access mail data. The following commands will put +those tools where they need to be within the web/ directory structure. + + 1. % cd web/src + + 2. % make + + 3. % make install + +Second, the web/ directory tree needs to be made available to the web +server. On the example system, start by moving the web/ directory +tree into a more system-visible location. We'll also change the name +to reflect the current version number (for this example, 1.00) to help +keep future upgrades isolated. This command will likely require +elevated privileges using either sudo or after becoming root. + + 4. % cd ../.. + + 5. % sudo mv web /usr/local/libexec/alpine-2.00 + +Next, for simplicity, create a generically named symbolic link as a +synonym for the version-specific directory. + + 6. % cd /usr/local/libexec + + 7. % sudo ln -s alpine-2.00 alpine + +After that, make the scripts that actually generate the user visible +portion of Web Alpine available to the web server. + + 8. % cd /var/www + + 9. % sudo ln -s /usr/local/libexec/alpine/cgi ./alpine + +Now adjust the web server's configuration so that it can effectively +provide Web Alpine pages to connecting browsers by editing httpd's +configuration file. + + 10. % sudo vi /etc/httpd/conf/httpd.conf + + After the section that starts with <Directory /var/www/html> and ends + with </Directory>, add the lines: + + # + # This sets up Web Alpine + # + <Directory "/var/www/alpine"> + Options FollowSymLinks ExecCGI -Indexes + AllowOverride All + Order allow,deny + Allow from all + </Directory> + +If you intend for your web server to provide Web Alpine pages +exclusively, then simply edit the DocumentRoot to the directory +defined above: + + DocumentRoot /var/www/alpine + +If your web server offers pages other than Web Alpine, specify a +prefix the web server should use for referencing Web Alpine pages by +adding this line before the <Directory> entry specified above: + + Alias /webmail/ "/var/www/alpine/" + +After saving httpd.conf with these small additions, it's time to +adjust Web Alpine's configuration. + +First, be sure the symbolic link "/usr/local/libexec/alpine/bin/tclsh" +points to the tclsh interpreter for your system. The default should +work for the example system. + +Then edit the Web Alpine configuration file to configure appropriate +settings for your environment. + + 11. % sudo vi /usr/local/libexec/alpine/config/alpine.tcl + + The config file is itself a Tcl script, and the settings are + simply Tcl variable settings. Most are settings of elements + within the "_wp" array. + + Starting from the top, skim the various configuration + settings. The primary one's to be aware of include: + + admin email address offered in error pages + associated with problems that likely + require system administrator attention + + helpdesk email address offered in help pages and + some error pages as a place to report + problems or get more information + + comments email address offered in help pages + as place to send general comments on + web alpine + + urlprefix directory or path defined in the httpd.conf's + "Alias" setting. In example above, set this to + "webmail". If DocumentRoot set as above, set this + to {}. + + fileroot file system path to directory that contains cgi/, + config/, bin/, and lib/ directories. In example + above, set this to /usr/local/libexec/alpine. + + Continue scanning the list, and adjust as needed. Most defaults + should be fine. Until you come to: + + ispell full path to ispell application if installed + + ssl_safe_domains + a performance setting that allows for relatively + safe disabling of SSL for connections that we know + are reasonably safe from sniffing. For our campus + web alpine installation, browsers associated with the + campus dial-in pools connecting to our servers + offer this kind of connection. Be careful. + + flexserver + determines whether or not web alpine offers the option + of connecting to a user-defined IMAP server on + the greeting page. + + hosts an array of default configurations that + correspond to default web alpine config files + in the config/ directory. these are what + is offered on the greeting page as the option + list of servers to connect to. + + And, probably lastly: + + cgi_mail_relay + the server used to send out script errors that are + so heinous that no web page error could be generated + + +The final step is to restart httpd and give it a try! Using a browser +pointed to your server's https port, try connecting to the alpine/ +directory. + +If you run into problems, rest assured you have our sympathies. +Because of the various components that must be coordinated, errors can +be difficult to resolve. The good news is, once initially configured +and working the system is reasonably stable. As for debugging, with +luck, the error response reported in the browser will point in a +useful direction. If not, check httpd access and error logs to verify +paths and check for exceptional conditions. Next, check syslog's +maillog for any exceptional reports issued by the alpined serverette. +Depending on the type of error, you may also have to consult the IMAP +server's logs for clues. + + +COLLECTED GOTCHAS AND SO FORTH +------------------------------ + +First, it is strongly encourage that Web Alpine be run on a web server +that does not have general user accounts. The primary reason is to +maintain the privacy of the Web Alpine session key. Steps are taken +to minimize the risk and consequences of session key exposure, but +there are risks nonetheless. + +For the most part, the default Web Alpine application settings should +require little adjustment for your particular environment. These +settings are in the web/config/pine.conf file which uses the same +format as alpine's pinerc file. The most likely setting to adjust is +"smtp-server." + +By default, Web Alpine sends via SMTP to the localhost's SMTP port. +This setting can easily be adjusted by setting the smtp-server in +web/config/pine.conf to one or more external servers. Web Alpine can +also be directed to post to a local process by setting the +sendmail-path variable. Be aware, however, posting to a local process +(e.g., sendmail, postfix, etc), will likely require you to grant +trusted mail user privilege to the userid associated with the web +server process. Without such privilege, the SMTP envelope From will +be set to the web server's userid which causes all externally bounced +mail to be returned to the mailbox associated with the web server +userid. + + +FURTHER INFORMATION +------------------- + +See the Web Alpine technical notes for more detailed descriptions of +what's going on and why. If you have any questions or comments drop +us a note <alpine-contact@cac.washington.edu>. + +-- +$Id: INSTALL 1169 2008-08-27 06:42:06Z hubert@u.washington.edu $ diff --git a/web/README b/web/README new file mode 100644 index 00000000..64d19168 --- /dev/null +++ b/web/README @@ -0,0 +1,81 @@ +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +WEB ALPINE +---------- + +Web Alpine is the web-based component of the Alpine Mail System. It +rests on the same distributed email technology behind Alpine, but is +accessible from almost any browser on the World Wide Web. + +Web Alpine uses TCL to provide the programmatic interface between +the Alpine-provided message store and the cgi-served web pages. + + +REQUIRED SOFTWARE +----------------- + + Base system: + C compiler + Tcl scripting package and development tools + OpenSSL + Apache web server (though, presumably any CGI supporting + web server should work) + + Optional: + ispell application + Used to support composer spell check functinoality. + Featured not offered if ispell not present. + + openLDAP + Provides LDAP query services to support login + personalization and user-session LDAP query support. + + UW Pubcookie + Provides central web-login management. Note, additional + configuration and installation steps are required. See + src/pubcookie/INSTALL for specific instructions. + + Kerberos 5 + Required by UW-Pubcookie to provide authentication and + proxy authorization for IMAP server access. Proxy + authentication only tested under UW imapd. + + + +BUILING AND INSTALLING WEB ALPINE +--------------------------------- + +See the INSTALL file for basic instructions. + + +DOCUMENTATION +------------- + +User documentation is contained within the application and is +reasonably complete. Technical documentation is extremely rough and +likely unsatisfying. It's probably worth reading, but ultimately +configuration or other questions are best answered by reviewing the +source (which itself, while working reasonably, is somewhat spotilly +documented as well). + + +SUPPORT AND FEEDBACK +-------------------- + +Send comments and questions to <alpine-contact@cac.washington.edu>. + + +-- +alpine.tar.z web/README +$Id: README 890 2007-12-21 05:34:43Z hubert@u.washington.edu $ diff --git a/web/bin/README b/web/bin/README new file mode 100644 index 00000000..a6f5fa90 --- /dev/null +++ b/web/bin/README @@ -0,0 +1,20 @@ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + + this directory holds binaries for use by the web alpine cgi. + the alpined is the serverlet that provides mailbox + data and session management to the web alpine scripts. + + make sure alpined resides in this directory. + + make sure tclsh points to the tclsh binary for your system. + diff --git a/web/bin/alpine.tcl b/web/bin/alpine.tcl new file mode 120000 index 00000000..976166f1 --- /dev/null +++ b/web/bin/alpine.tcl @@ -0,0 +1 @@ +../config/alpine.tcl
\ No newline at end of file diff --git a/web/bin/launch.tcl b/web/bin/launch.tcl new file mode 100755 index 00000000..8751c33f --- /dev/null +++ b/web/bin/launch.tcl @@ -0,0 +1,51 @@ +#!./tclsh +# $Id: launch.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# Generate a session key, create the connection points (fifos), +# spawn the mail engine and then hand the session key to the +# caller + +# Source config information +source ./alpine.tcl + +# generate session id +WPValidId + +if {[info exists env(REMOTE_USER)]} { + set servlet $_wp(pc_servlet) + set env(LOGNAME) $env(REMOTE_USER) +} else { + set servlet $_wp(servlet) +} + +set cmd "exec -- echo $_wp(sockname) | [file join $_wp(bin) $servlet]" + +# set debug level and configure dmalloc +#append cmd " -d -d -d -d -d -d -d" +#set env(DMALLOC_OPTIONS) "check-fence,check-heap,check-blank,log=/tmp/logfile.%d" + +if {[catch {eval $cmd} errmsg]} { + puts stderr "Unable to Launch servlet: $errmsg" + exit 1 +} elseif {[info exists env(REMOTE_ADDR)] && [string length $env(REMOTE_ADDR)]} { + catch {WPCmd PEInfo set wp_client $env(REMOTE_ADDR)} +} elseif {[info exists env(REMOTE_HOST)] && [string length $env(REMOTE_HOST)]} { + catch {WPCmd PEInfo set wp_client $env(REMOTE_HOST)} +} + +if {$_wp(debug) > 0} { + WPCmd PEDebug level $_wp(debug) +} + +puts $_wp(sessid) +exit 0 diff --git a/web/bin/tclsh b/web/bin/tclsh new file mode 120000 index 00000000..89acb765 --- /dev/null +++ b/web/bin/tclsh @@ -0,0 +1 @@ +/usr/bin/tclsh
\ No newline at end of file diff --git a/web/bin/usage.tcl b/web/bin/usage.tcl new file mode 100755 index 00000000..8b597951 --- /dev/null +++ b/web/bin/usage.tcl @@ -0,0 +1,24 @@ +#!./tclsh +# $Id: usage.tcl 1169 2008-08-27 06:42:06Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# Return mail store usage numbers on stdout separated by a space +# First number is amount of usage +# Second is total amount of space available +# Integer values. Unit are megabytes (MB). + +set cmd "exec -- /usr/local/bin/dmq -u [lindex $argv 0]" +if {0 == [catch {eval $cmd} result]} { + if {[regexp {^[0-9]+[ \t]+([0-9]+)\.[0-9]*[ \t]+([0-9]+)$} $result dummy usage total]} { + puts stdout "$usage $total" + } +} diff --git a/web/cgi/.htaccess b/web/cgi/.htaccess new file mode 100644 index 00000000..b59de05b --- /dev/null +++ b/web/cgi/.htaccess @@ -0,0 +1,32 @@ +# +# Tweek server to encourage caching and set appropriate type for icons +# +DirectoryIndex greeting.tcl + +AddType image/x-icon .ico + +AddHandler cgi-script tcl + +<IfModule mod_headers.c> + +<Files *.gif> +Header append Cache-Control "public" +</Files> + +<Files *.jpg> +Header append Cache-Control "public" +</Files> + +<Files *.jpeg> +Header append Cache-Control "public" +</Files> + +<Files *.js> +Header append Cache-Control "public" +</Files> + +<Files *.css> +Header append Cache-Control "public" +</Files> + +</IfModule> diff --git a/web/cgi/alpine.tcl b/web/cgi/alpine.tcl new file mode 120000 index 00000000..976166f1 --- /dev/null +++ b/web/cgi/alpine.tcl @@ -0,0 +1 @@ +../config/alpine.tcl
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/addrbook.tcl b/web/cgi/alpine/1.0/addrbook.tcl new file mode 100755 index 00000000..fcaf4f04 --- /dev/null +++ b/web/cgi/alpine/1.0/addrbook.tcl @@ -0,0 +1,583 @@ +# $Id: addrbook.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# addrbook.tcl +# +# Purpose: CGI script to generate html output associated with address +# book entry and collection management +# +# Input: +set abook_vars { + {op {} "view"} + {field {} "none"} + {uid "" 0} + {oncancel "" "fr_main.tcl"} + {reload} +} + +# Output: +# +# HTML/CSS data representing the address book + + +# Command Menu definition for Message View Screen +set addr_menu { +} + +set common_menu { + { + {expr {$view}} + { + { + # * * * * Ubiquitous INBOX link * * * * + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_main.tcl target=_top class=navbar] + } + } + } + } + { + {expr {$view}} + { + { + # * * * * FOLDER LIST * * * * + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + } + { + {expr {$view}} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=addrbook&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {expr {$view}} + { + { + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=addrbook&cid=[WPCmd PEInfo key] class=navbar] + } + } + } + { + {expr {$browse}} + { + { + # * * * * USE ADDRESSES * * * * + cgi_submit_button "address=Address" class="navtext" + } + } + } + { + {expr {$browse}} + { + { + # * * * * CANCEL * * * * + cgi_submit_button "cancel=Cancel" class="navtext" + } + } + } + { + {expr {0 && $browse}} + { + { + # * * * * Address/Cancel * * * * + cgi_submit_button doit=Done class="navbar" + cgi_br + cgi_select addrop class=navtext { + cgi_option "Action..." value=null + cgi_option Address value=address + cgi_option Cancel value=cancel + } + } + } + } +} + + +## read vars +foreach item $abook_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +# perform any requested actions + +# preserve vars that my have been overridden with cgi parms + +set cid [WPCmd PEInfo key] +WPCmd PEAddress safecheck + +set view [expr {[string compare $op "view"] == 0}] +set browse [expr {[string compare $op "browse"] == 0}] + +if {$view} { + if {[catch {WPNewMail $reload} newmail]} { + error [list _action "new mail" $newmail] + } + + if {[WPCmd PEInfo ldapenabled] == 1} { + if {[catch {WPCmd PELdap directories} directories] || [llength $directories] <= 0} { + catch {unset directories} + } else { + for {set i 0} {$i < [llength $directories]} {incr i} { + lappend exclusions document.ldapsearch${i}.srchstr + } + } + } +} + +# paint the page +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + set onload "onLoad=" + set onunload "onUnload=" + + if {[info exists _wp(exitonclose)] && $view} { + WPExitOnClose + append onload "wpLoad();" + append onunload "wpUnLoad();" + } + + if {$view} { + set normalreload [cgi_buffer {WPHtmlHdrReload "[file join $_wp(appdir) $_wp(ui1dir) wp.tcl?page=addrbook]"}] + if {[info exists _wp(exitonclose)]} { + WPStdHtmlHdr "Address Book View" + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function indexReloadTimer(t){" + cgi_put " reloadtimer = window.setInterval('wpLink(); window.location.replace(\\'[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=addrbook&reload=1\\')', t * 1000);" + cgi_puts "}" + } + + append onload "indexReloadTimer($_wp(refresh));" + + cgi_noscript { + cgi_puts $normalreload + } + } else { + cgi_puts $normalreload + } + } + + WPStyleSheets + cgi_puts "<style type='text/css'>" + if {$browse} { + cgi_puts ".navbtn { color: white ; font-family: geneva, arial, sans-serif ; font-size: 9pt ; letter-spacing: 0pt ; text-decoration: underline ; background: transparent; border: 0 ; text-align: left }" + } elseif {$view} { + cgi_puts ".gradient { background-image: url('[WPimg indexhdr]') ; background-repeat: repeat-x }" + } + cgi_puts "</style>" + + if {$_wp(keybindings)} { + set kequiv { + {{i} {top.location = 'fr_main.tcl'}} + {{l} {top.location = 'wp.tcl?page=folders'}} + {{?} {top.location = 'wp.tcl?page=help&oncancel=addrbook'}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=addrbook&cid=$cid'"] + + if {![info exists exclusions]} { + set exclusions "" + } + + append onload [WPTFKeyEquiv $kequiv $exclusions] + } + } + + cgi_body bgcolor=$_wp(bordercolor) background=[file join $_wp(imagepath) logo $_wp(logodir) back.gif] "style=\"background-repeat: repeat-x\"" $onload $onunload { + + if {$view} { + catch {WPCmd PEInfo set help_context addrbook} + } else { + catch {WPCmd PEInfo set help_context addrbrowse} + } + + set books [WPCmd PEAddress books] + set entrylist {} + set entryexists 0 + foreach book $books { + set entries [WPCmd PEAddress list [lindex $book 0]] + if {[llength $entries] > 0} { + incr entryexists + } + lappend entrylist $entries + } + + if {$view} { + WPTFTitle "Address Books" $newmail 0 addrbook + } + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + if {$browse} { + cgi_puts "<form action=\"[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl\" name=addrchoice method=get target=_top>" + cgi_text "page=addrpick" type=hidden notab + cgi_text "field=$field" type=hidden notab + cgi_text "restore=1" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + } + cgi_table_row { + # + # next comes the menu down the left side + # + cgi_table_data valign=top rowspan=4 class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=0 width=112 { + if {!$browse} { + cgi_table_row { + cgi_table_data class=navbar "style=\"padding: 6 0 6 4\"" { + cgi_puts [cgi_span "style=font-weight: bold" "Current Folder"] + cgi_division align=center "style=\"margin-top:4;margin-bottom:4\"" { + set mbn [WPCmd PEMailbox mailboxname] + if {[string length $mbn] > 16} { + set mbn "[string range $mbn 0 14]..." + } + + cgi_put [cgi_url $mbn fr_main.tcl target=_top class=navbar] + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + #cgi_put [cgi_span "style=color: black; border: 1px solid red; background-color: pink; font-weight: bold" "Read Only"] + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + #cgi_put [cgi_span "style=color: black; border: 1px solid red; background-color: pink; font-weight: bold" "Closed"] + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + + cgi_br + } + + cgi_hr "width=75%" + } + } + } + + if {$view && [llength $books] == 1 && [lindex [lindex $books 0] 3]} { + cgi_table_row { + cgi_table_data class=navbar "style=\"padding-left: 4\"" { + # * * * * ADD ENTRY * * * * + cgi_puts [cgi_url "Add Entry" wp.tcl?page=addredit&add=1&book=0&cid=[WPCmd PEInfo key] class=navbar] + } + } + cgi_table_row { + cgi_table_data class=navbar { + cgi_put [cgi_nbspace] + } + } + } + + # next comes the menu down the left side, with suitable + cgi_table_row { + if {$view} { + lappend common_menu {{cgi_put [cgi_nbspace]}} + lappend common_menu [list {} [list {cgi_puts [cgi_url "Configure" wp.tcl?page=conf_process&newconf=1&oncancel=addrbook&cid=[WPCmd PEInfo key] class=navbar target=_top]}]] + lappend common_menu [list {} [list {cgi_puts [cgi_url "Get Help" wp.tcl?page=help&oncancel=addrbook target=_top class=navbar]}]] + lappend common_menu {{cgi_put [cgi_nbspace]}} + + if {[WPCmd PEInfo feature quit-without-confirm]} { + lappend common_menu [list {} [list {cgi_puts [cgi_url "Quit $_wp(appname)" $_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid class=navbar]}]] + } else { + lappend common_menu [list {} [list {cgi_puts [cgi_url "Quit $_wp(appname)" wp.tcl?page=quit&cid=[WPCmd PEInfo key] target=_top class=navbar]}]] + } + } + + + eval { + cgi_table_data $_wp(menuargs) class=navbar "style=\"padding: 0 0 10 2\"" { + WPTFCommandMenu addr_menu common_menu + } + } + } + } + } + + cgi_table_data valign=top width=100% class=dialog { + set n 1 + set bookno 0 + foreach book $books { + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" { + if {$browse} { + cgi_table_row { + cgi_table_data width="100%" colspan=16 class=dialog align=center valign=middle { + cgi_table cellpadding=4 width="70%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts "Check the box next to the addresses you'd like to add to the [cgi_bold "[string toupper [string range $field 0 0]][string range $field 1 end]:"] field, then click [cgi_italic Address] button." + } + } + } + } + } + } + + set format [WPCmd PEAddress format [lindex $book 0]] + set name [lindex $book 1] + set readwrite [lindex $book 3] + if {[llength $books] > 1} { + if {[string index $name 0] == "\{"} { + if {$readwrite} { + set name "Remote Address Book" + } else { + set name "Global Address Book" + } + } + + cgi_table_row { + cgi_table_data height=35 valign=middle colspan=[expr ([llength $format] + 1) * 2] nowrap { + if {$readwrite || $browse} { + cgi_puts "[cgi_font size=+1 [cgi_bold $name]]" + } else { + cgi_table border=0 cellspacing=0 cellpadding=0 width=100% { + cgi_table_row { + cgi_table_data align=left { + cgi_puts "[cgi_font size=+1 [cgi_bold $name]]" + } + cgi_table_data align=right { + cgi_puts "[cgi_bold "(Read Only)"]" + } + } + } + } + } + } + + if {$view && $readwrite} { + cgi_table_row { + cgi_table_data nowrap height=40 { + cgi_put [cgi_url "Add New Entry" wp.tcl?page=addredit&add=1&book=${bookno}&cid=[WPCmd PEInfo key]] + } + } + } + } + + cgi_table_row { + cgi_table_data { + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" { + set linenum 1 + set nonick 1 + set nfields [llength $format] + + if {$view} { + cgi_table_row class=\"gradient\" { + foreach f $format { + cgi_table_data { + cgi_put [cgi_img [WPimg dot2] border=0 width=3 height=24] + } + cgi_table_data align=left class=indexhdr { + switch [lindex $f 0] { + nick { + cgi_put "Nickname (Click to edit entry)" + } + full { + cgi_put "Full Name" + } + addr { + cgi_put "Address (Click to Compose To)" + } + } + } + } + } + } + + for {set i 0} {$i < $nfields && $nonick} {incr i} { + if {[string compare "nick" [lindex [lindex $format $i] 0]] == 0} { + set nonick 0 + } + } + set entries [lindex $entrylist [lindex $book 0]] + if {[llength $entries] == 0} { + cgi_table_row { + cgi_table_data colspan=16 align=center { + cgi_puts [cgi_italic "This address book is currently empty."] + } + } + } + set aindex 0 + foreach entry $entries { + if {[incr linenum] % 2} { + set bgcolor #ffffff + } else { + set bgcolor #eeeeee + } + cgi_table_row bgcolor=$bgcolor { + set nick [lindex [lindex $entry 0] 0] + set safenick [WPPercentQuote $nick] + + set nfields [llength $format] + if {$browse} { + cgi_table_data valign=top nowrap { + cgi_checkbox "nickList=[lindex $book 0].$aindex.[lindex [lindex $entry 0] 0]" style="background-color:$bgcolor" + } + } + for {set i 0} {$i < $nfields} {incr i} { + set field [lindex $format $i] + set data [lindex $entry [expr $i + 1]] + + if {$view} { + cgi_table_data nowrap { + if {$nonick && $i == 0} { + set data [cgi_url $data "wp.tcl?page=addredit&nick=${safenick}&book=${bookno}&ai=${aindex}"] + } + cgi_puts [cgi_nbspace][cgi_nbspace][cgi_nbspace][cgi_nbspace] + } + } + + cgi_table_data valign=top nowrap { + switch -- [lindex $field 0] { + addr { + switch -- [lindex [lindex $entry 0] 1] { + single { + regsub -all "<" $data "\\<" data + regsub -all ">" $data "\\>" data + if {$view} { + set data [cgi_url $data "wp.tcl?page=compose&nickto=${safenick}&book=${bookno}&ai=${aindex}&oncancel=addrbook&cid=[WPCmd PEInfo key]"] + } + cgi_puts [cgi_font size=-1 face=courier $data] + } + list { + cgi_table { + cgi_table_row { + cgi_table_data { + foreach addr $data { + regsub -all "<" $addr "\\<" addr + regsub -all ">" $addr "\\>" addr + if {$view} { + set addr [cgi_url $addr "wp.tcl?page=compose&nickto=${safenick}&book=${bookno}&ai=${aindex}&oncancel=addrbook&cid=[WPCmd PEInfo key]"] + } + cgi_puts [cgi_font size=-1 face=courier $addr] + cgi_br + } + if {$view} { + cgi_puts "</a>" + } + } + } + } + } + default { + cgi_puts "Unknown entry type" + } + } + } + nick { + regsub -all "<" $data "\\<" data + regsub -all ">" $data "\\>" data + if {$view} { + if {[string length $data]} { + set text "$data" + } else { + set text "\[Edit\]" + } + + cgi_puts [cgi_url $text "wp.tcl?page=addredit&nick=${safenick}&book=${bookno}&ai=${aindex}"] + } else { + if {![string length $nick]} { + set nick [cgi_nbspace] + } + + cgi_puts "$nick" + } + } + default { + regsub -all "<" $data "\\<" data + regsub -all ">" $data "\\>" data + if {[string compare "$data" ""] == 0} { + cgi_puts " " + } else { + cgi_puts "$data" + } + } + } + } + } + } + incr aindex + } + } + } + } + } + incr bookno + } + if {$browse} { + cgi_puts "</form>" + } + + if {[info exists directories]} { + cgi_table border=0 cellspacing=0 cellpadding=4 width="100%" "style=\"padding-top:10\"" { + for {set i 0} {$i < [llength $directories]} {incr i} { + set directory [lindex $directories $i] + set nick [lindex $directory 0] + set server [lindex $directory 1] + if {[string length $nick]} { + set ref $nick + } elseif {[string length $server]} { + set ref "<$server>" + } else { + set ref "some server" + } + + cgi_table_row { + cgi_table_data colspan=3 valign=middle nowrap { + cgi_puts "[cgi_font size=+1 [cgi_bold "Directory server [cgi_quote_html $ref]"]]" + } + } + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data name=ldapsearch${i} { + cgi_text "sessid=$_wp(sessid)" type=hidden notab + cgi_text "page=ldapquery" type=hidden notab + + cgi_text "searchtype=0" type=hidden notab + cgi_text "op=view" type=hidden notab + cgi_text "dir=$i" type=hidden notab + + cgi_table_row { + cgi_table_data class=dialog align=center valign=middle "style=\"background-color:white\"" { + cgi_puts "Search Directory :" + cgi_text "srchstr=" size=35 + cgi_submit_button "search=Search" + } + } + } + } + } + } + } + } + cgi_table_row { + cgi_table_data height=200 class=dialog { + cgi_puts [cgi_nbspace] + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/addredit.tcl b/web/cgi/alpine/1.0/addredit.tcl new file mode 100755 index 00000000..8aecda2e --- /dev/null +++ b/web/cgi/alpine/1.0/addredit.tcl @@ -0,0 +1,224 @@ +#!./tclsh +# $Id: addredit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# addredit.tcl +# +# Purpose: CGI script to generate html form used to view/set +# individual addressbook entries +# +# Input: +set ae_vars { + {book {} -1} + {nick {} ""} + {add {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {take {} 0} + {newnick {} ""} + {ai {} -1} +} + +set ae_fields { + {0 "newnick" "Nickname<sup class=notice>*</sup>"} + {1 "fn" "Full Name "} + {2 "addrs" "Addresses<sup class=notice>*</sup>"} + {3 "fcc" "Fcc "} + {4 "comment" "Comments "} +} + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +# Output: +# +# + +set ae_menu { + { + {} + { + { + cgi_image_button help=[WPimg help_trans] border=0 alt="Help" + } + } + } +} + +WPEval $ae_vars { + + if {$book < 0} { + if {[catch {WPCmd PEInfo set ae_help_state} ae_help_state] == 0} { + foreach v $ae_help_state { + eval set [lindex $v 0] [list [lindex $v 1]] + } + + set addrinfo [list "$newnick" "$fn" [list "$addrs"] "$fcc" "$comment"] + WPCmd PEInfo unset ae_help_state + } else { + return [list _action "Web Alpine" "Unspecified Address Book"] + } + } + + catch {WPCmd PEInfo unset ae_help_state} + + if {![info exists addrinfo]} { + if {$take != 0} { + set addrinfo [list "$newnick" "$fn" [list "$addrs"] "$fcc" "$comment"] + } elseif {$add == 0} { + if {[catch {WPCmd PEAddress fullentry $book $nick $ai} addrinfo]} { + if {[string length $addrinfo]} { + set entryerror "Address Error: $addrinfo" + } else { + set entryerror "Nickname $nick does not exist" + } + + set addrinfo [list "" "" [list ""] "" ""] + } + } else { + set addrinfo [list "" "" [list ""] "" ""] + } + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Addressbook Update" + WPStyleSheets + } + + if {$take == 1} { + set onload "onLoad=document.addredit.newnick.focus()" + } else { + set onload "" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" $onload { + set books [WPCmd PEAddress books] + set readwrite [lindex [lindex $books $book] 3] + + catch {WPCmd PEInfo set help_context addredit} + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data name=addredit target=_top { + cgi_table_row { + # + # next comes the menu down the left side + # + eval { + cgi_table_data $_wp(menuargs) rowspan=1000 { + WPTFCommandMenu ae_menu {} + } + } + + cgi_table_row { + cgi_table_data valign=top width="100%" class=dialog { + if {[info exists entryerror]} { + cgi_division class=notice align=center { + cgi_puts $entryerror + } + } + + + if {$take == 1} { + lappend tmptxt "Edit the new entry below as neccessary (note, some are required). To create a list entry, simply add each desired address to the [cgi_italic Addresses] field separated by a comma." + lappend tmptxt "When finished, click [cgi_italic Save] to update your address book, or [cgi_italic Cancel] to return to the message view." + } elseif {$add == 1} { + lappend tmptxt "The address book entry editor is used to create a new address book entry. Fill in the fields as desired below (note, some are required). To create a list entry, simply add each desired address to the [cgi_italic Addresses] field separated by a comma." + lappend tmptxt "When finished, click [cgi_italic Save] to update your address book, or [cgi_italic Cancel] to return to your unchanged address book." + } elseif {$readwrite == 0} { + set tmptxt "These are the current settings for the selected entry" + } else { + lappend tmptxt "The address book entry editor is used to edit an existing address book entry. Edit the fields as desired below (note, some are required)." + lappend tmptxt " then click [cgi_italic Save] to update your address book, or [cgi_italic Cancel] to return to your unchanged address book." + } + + cgi_table align=center width=75% cellpadding=10 border=0 { + foreach t $tmptxt { + cgi_table_row { + cgi_table_data align=center { + cgi_puts $t + } + } + } + } + + cgi_table border=0 cellspacing=0 cellpadding=5 align=center { + cgi_text "page=addrsave" type=hidden notab + + if {$take == 1} { + cgi_text "oncancel=main" type=hidden notab + cgi_text "take=1" type=hidden notab + } else { + cgi_text "oncancel=addrbook" type=hidden notab + } + + cgi_text "book=$book" type=hidden notab + if {$add == 0} {cgi_text "nick=$nick" type=hidden notab} + if {$add != 0} {cgi_text "add=1" type=hidden notab} + cgi_text "ai=${ai}" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + foreach fieldval $ae_fields { + cgi_table_row { + cgi_table_data valign=top align=right width="30%" class=dialog { + # cgi_puts [cgi_font face=tahoma,verdana,geneva size=+1 "[lindex $fieldval 2]:"] + cgi_puts [cgi_bold "[lindex $fieldval 2]:"] + } + cgi_table_data align=left { + switch -regexp [lindex $fieldval 1] { + ^addrs$ { + set addrvals [lindex $addrinfo [lindex $fieldval 0]] + set line [join $addrvals ", "] + cgi_text "[lindex $fieldval 1]=${line}" size=50 + } + default { + cgi_text "[lindex $fieldval 1]=[lindex $addrinfo [lindex $fieldval 0]]" size=50 + } + } + } + } + } + cgi_table_row { + cgi_table_data align=right { + cgi_puts [cgi_font class=notice size=-1 "* Required field"] + } + } + cgi_table_row { + cgi_table_data align=center colspan=2 { + if {$readwrite} { + cgi_submit_button "save=Save Entry" + cgi_put [cgi_img [WPimg dot2] border=0 alt="" width=10] + } + + if {$readwrite && $add == 0 && $take == 0} { + cgi_submit_button "delete=Delete Entry" + cgi_put [cgi_img [WPimg dot2] border=0 alt="" width=10] + } + + cgi_submit_button "cancel=Cancel" + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/addrpick.tcl b/web/cgi/alpine/1.0/addrpick.tcl new file mode 100755 index 00000000..a71f55d6 --- /dev/null +++ b/web/cgi/alpine/1.0/addrpick.tcl @@ -0,0 +1,134 @@ +# $Id: addrpick.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# addrpick.tcl +# +# Purpose: CGI script to handle address book choices from the +# via the addrbook browser generated form +# +# Input: +set pick_vars { + {cid "Missing Command ID"} + {field "Missing Field Name"} + {addrop {} ""} + {cancel {} 0} +} + +# Output: + + +# read vars +foreach item $pick_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} +} + +WPLoadCGIVarAs nickList listonicks +set usenewfcc 0 + +if {$cancel == 1 || [string compare cancel [string tolower $cancel]] == 0 || [string compare cancel [string tolower $addrop]] == 0} { +} elseif {[string length $listonicks] > 0} { + foreach nick $listonicks { + # determine which book + if {[regexp {^([0-9]+)\.([0-9]+)\.(.*)$} $nick dummy book ai nick]} { + if {[catch {WPCmd PEAddress entry $book $nick $ai} result]} { + regsub -all "'" $result "\\'" result + WPCmd PEInfo statmsg $result + } else { + set resaddr [lindex $result 0] + regsub -all "'" $resaddr "\\'" resaddr + if {[info exists newaddrs]} { + append newaddrs ", " + } + if {[string compare $field "to"] == 0 && [string length [lindex $result 1]]} { + # arbitrarily the last returned entry with an fcc wins + set fcc [lindex $result 1] + if {[string compare $fcc "\"\""] == 0} { + set fcc "" + } + regsub -all "'" $fcc "\\'" fcc + set usenewfcc 1 + } + + append newaddrs $resaddr + } + } else { + WPCmd PEInfo statmsg "Malformed entry request: $addr" + } + } + + if {[info exists newaddrs]} { + if {[catch {WPCmd PEInfo set suspended_composition} msgdata] == 0} { + for {set i 0} {$i < [llength $msgdata]} {incr i} { + if {[string compare [string tolower [lindex [lindex $msgdata $i] 0]] $field] == 0} { + if {[string length [lindex [lindex $msgdata $i] 1]]} { + set newfield [list $field "[lindex [lindex $msgdata $i] 1], $newaddrs"] + } else { + set newfield [list $field $newaddrs] + } + break + } + } + + if {$usenewfcc} { + for {set j 0} {$j < [llength $msgdata]} {incr j} { + if {[string compare fcc [string tolower [lindex [lindex $msgdata $j] 0]]] == 0} { + set fcc_index $j + break + } + } + + set savedef [WPTFSaveDefault 0] + set colid [lindex $savedef 0] + if {[info exists fcc_index]} { + if {[string compare $fcc [lindex [lindex [lindex $msgdata $fcc_index] 1] 1]]} { + lappend msgdata [list postoption [list fcc-set-by-addrbook 1]] + } + + set msgdata [lreplace $msgdata $fcc_index $fcc_index [list Fcc [list $colid $fcc]]] + } else { + lappend msgdata [list Fcc [list $colid $fcc]] + lappend msgdata [list postoption [list fcc-set-by-addrbook 1]] + } + } + + if {[info exists newfield]} { + set msgdata2 [lreplace $msgdata $i $i $newfield] + if {[catch {WPCmd PEInfo set suspended_composition $msgdata2} result] == 0} { + unset result + } + } else { + lappend msgdata [list $field $newaddrs] + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} result] == 0} { + unset result + } + } + + if {[info exists result]} { + WPCmd PEInfo statmsg "Cannot Update $field field: $result" + } + } else { + WPCmd PEInfo statmsg "Cannot change Message Data: $msgdata" + } + } +} + +source [WPTFScript compose] diff --git a/web/cgi/alpine/1.0/addrsave.tcl b/web/cgi/alpine/1.0/addrsave.tcl new file mode 100755 index 00000000..37a70ebe --- /dev/null +++ b/web/cgi/alpine/1.0/addrsave.tcl @@ -0,0 +1,244 @@ +# $Id: addrsave.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# addrsave.tcl +# +# Purpose: CGI script to handle address book change/save +# via addredit generated form +# +# Input: +set abs_vars { + {cid "Missing Command ID"} + {save {} 0} + {delete {} 0} + {replace {} 0} + {compose {} 0} + {take {} 0} + {help {} 0} + {cancel {} 0} + {oncancel {} ""} +} + +# Output: +# + +## read vars +foreach item $abs_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} +} + +if {$help != 0} { + set save_vars { + {book {} 0} + {newnick {} ""} + {nick {} ""} + {ai {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {add {} 0} + {take {} 0} + } + + foreach i $abs_vars { + lappend ae_help_state [list [lindex $i 0] [subst $[lindex $i 0]]] + } + + foreach i $save_vars { + eval WPImport $i + lappend ae_help_state [list [lindex $i 0] [subst $[lindex $i 0]]] + } + + WPCmd PEInfo set ae_help_state $ae_help_state + + set _cgi_uservar(topic) takeedit + set _cgi_uservar(oncancel) addredit + if {$take} { + set _cgi_uservar(index) none + } + + set src help + +} elseif {$save == 1 || [string compare [string tolower $save] "save entry"] == 0} { + WPLoadCGIVar book + WPLoadCGIVar newnick + WPLoadCGIVar ai + WPLoadCGIVar fn + WPLoadCGIVar addrs + WPLoadCGIVar fcc + WPLoadCGIVar comment + if {[catch {cgi_import_cookie add}] != 0} {set add 0} + if {[catch {cgi_import_cookie nick}] != 0} {set nick ""} + + if {![string length $newnick]} { + WPCmd PEInfo statmsg "No entry created. New entries must include a Nickname." + set src takeedit + } else { + if {!$take || [catch {WPCmd PEAddress entry $book $newnick $ai} result] || ![llength $result]} { + set result "" + if {[catch {WPCmd PEAddress edit $book $newnick $ai $fn $addrs $fcc $comment $add $nick} result]} { + catch {WPCmd PEInfo statmsg "Address Set Failure: $result"} + set adderr $result + } elseif {[string length $result]} { + catch {WPCmd PEInfo statmsg "$result"} + set adderr $result + } + + if {$take == 1} { + if {[info exists adderr]} { + WPCmd PEInfo statmsg "No address book entry changed: $adderr" + } else { + WPCmd PEInfo statmsg "New address book entry \"$newnick\" created." + } + } + } else { + set src takesame + } + + if {$take == 1 && ![info exists src]} { + set src $oncancel + } + } +} elseif {$delete == 1 || [string compare [string tolower $delete] "delete entry"] == 0} { + WPLoadCGIVar book + WPLoadCGIVar nick + WPLoadCGIVar ai + + set result "" + if {[catch {WPCmd PEAddress delete $book $nick $ai} result]} { + catch {WPCmd PEInfo statmsg "Address Set Failure $result"} + } elseif {[string compare $result ""]} { + catch {WPCmd PEInfo statmsg "$result"} + } +} elseif {[string compare [string tolower $replace] "replace entry"] == 0} { + + WPLoadCGIVar book + WPLoadCGIVar newnick + WPLoadCGIVar ai + WPLoadCGIVar fn + WPLoadCGIVar addrs + WPLoadCGIVar fcc + WPLoadCGIVar comment + if {[catch {cgi_import_cookie add}] != 0} {set add 0} + if {[catch {cgi_import_cookie nick}] != 0} {set nick ""} + + if {![string length $newnick]} { + WPCmd PEInfo statmsg "No entry created. New entries must include a Nickname." + set src takeedit + } else { + if {[catch {WPCmd PEAddress delete $book $newnick $ai} result]} { + set adderr $result + } else { + set result "" + if {[catch {WPCmd PEAddress edit $book $newnick $ai $fn $addrs $fcc $comment $add $nick} result]} { + catch {WPCmd PEInfo statmsg "Address Set Failure result"} + set adderr $result + } elseif {[string length $result]} { + catch {WPCmd PEInfo statmsg "$result"} + set adderr $result + } + } + + if {$take == 1} { + if {[info exists adderr]} { + WPCmd PEInfo statmsg "No address book entry changed: $adderr." + } else { + WPCmd PEInfo statmsg "Address book entry \"$newnick\" replaced." + } + + if {![info exists src]} { + set src $oncancel + } + } + } +} elseif {[string compare [string tolower $replace] "add to entry"] == 0} { + WPLoadCGIVar book + WPLoadCGIVar newnick + WPLoadCGIVar ai + WPLoadCGIVar fn + WPLoadCGIVar addrs + WPLoadCGIVar fcc + WPLoadCGIVar comment + if {[catch {cgi_import_cookie add}] != 0} {set add 0} + if {[catch {cgi_import_cookie nick}] != 0} {set nick ""} + + if {![string length $newnick]} { + WPCmd PEInfo statmsg "No entry created. New entries must include a Nickname." + set src takeedit + } else { + if {[catch {WPCmd PEAddress fullentry $book $newnick $ai} result] || ![llength $result]} { + if {[string length $result]} { + set adderr $result + } else { + set adderr "No pre-existing entry" + } + } else { + set fn [lindex $result 1] + set newaddrs [join [lindex $result 2] ","] + append newaddrs ", $addrs" + set fcc [lindex $result 3] + set comment [lindex $result 4] + set result "" + if {[catch {WPCmd PEAddress edit $book $newnick $ai $fn $newaddrs $fcc $comment 0 $newnick} result]} { + set adderr $result + } elseif {[string length $result]} { + catch {WPCmd PEInfo statmsg "$result"} + set adderr $result + } + } + + if {$take == 1} { + if {[info exists adderr]} { + WPCmd PEInfo statmsg "No address book entry created: $adderr." + } else { + WPCmd PEInfo statmsg "Address book entry \"$newnick\" appended" + } + + if {![info exists src]} { + set src $oncancel + } + } + } +} elseif {[string compare [string tolower $replace] edit] == 0} { + set src takeedit +} elseif {$compose == 1} { + set oncancel addrbook + set src compose +} elseif {$cancel == 1 || [string compare [string tolower $cancel] cancel] == 0} { + if {$take == 1} { + set act "Take Address" + } else { + set act "Address Edit" + } + + catch {WPCmd PEInfo statmsg "$act cancelled. Address book unchanged."} + set src $oncancel +} else { + catch {WPCmd PEInfo statmsg "Unknown Address Book Operation"} +} + +if {![info exists src]} { + set src addrbook +} + +source [WPTFScript $src] diff --git a/web/cgi/alpine/1.0/alpine.tcl b/web/cgi/alpine/1.0/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/alpine/1.0/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/attach.tcl b/web/cgi/alpine/1.0/attach.tcl new file mode 100755 index 00000000..e0423171 --- /dev/null +++ b/web/cgi/alpine/1.0/attach.tcl @@ -0,0 +1,96 @@ +# $Id: attach.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# attach.tcl +# +# Purpose: CGI script to handle attaching attachment +# to composition via queryattach generated form +# +# Input: +set attach_vars { + {cid "Missing Command ID"} + {file "Missing File Upload Data"} + {attachop "" ""} + {cancel "" ""} +} + +# Output: +# + +## read vars +foreach item $attach_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cancel == 1 || [string compare cancel [string tolower $cancel]] == 0 || [string compare cancel [string tolower $attachop]] == 0} { +} else { + + if {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} + } + + if {[string length [lindex $file 1]]} { + if {[catch {cgi_import description}]} { + set description "" + } + + # "file" is a list: local_file remote_file content-type/content-subtype + # trim path from file name on remote system + # since we can't be certain what the delimiter is, + # try the usual suspects + set delims [list "\\" "/" ":"] + set native [lindex $file 1] + if {[string length $native]} { + foreach delim $delims { + if {[set crop [string last $delim $native]] >= 0} { + set native [string range $native [expr {$crop + 1}] [string length $native]] + break; + } + } + + regsub -all "'" $native "\\'" jsnative + + if {0 == [string length [lindex $file 2]]} { + set conttype [list text plain] + } else { + set conttype [split [lindex $file 2] "/"] + } + + set id [WPCmd PECompose attach [lindex $file 0] [lindex $conttype 0] [lindex $conttype 1] $native $description] + + catch {unset style} + set restore 1 + + if {[catch {WPCmd PEInfo lappend suspended_composition [list attach $id]} result]} { + WPCmd PEInfo statmsg "Cannot append attachment info, nothing attached" + } + + set fsize [file size [lindex $file 0]] + if {$fsize <= 0} { + WPCmd PEInfo statmsg "Attachment $jsnative empty or nonexistant" + } + } else { + WPCmd PEInfo statmsg "Requested attachment does not exist" + } + } else { + catch {file delete [lindex $file 0]} + WPCmd PEInfo statmsg "Empty file name, nothing attached" + } +} + +source [WPTFScript compose] diff --git a/web/cgi/alpine/1.0/cledit.tcl b/web/cgi/alpine/1.0/cledit.tcl new file mode 100755 index 00000000..dabf6044 --- /dev/null +++ b/web/cgi/alpine/1.0/cledit.tcl @@ -0,0 +1,232 @@ +#!./tclsh +# $Id: cledit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# +# cledit.tcl +# +# Purpose: CGI script to generate html form editing of a single collection + +# read config +source ./alpine.tcl +source cmdfunc.tcl + +set cledit_vars { + {cid "Missing Command ID"} + {oncancel "Missing oncancel"} + {cl {} 0} + {add {} 0} + {errtext {} 0} + {nick {} ""} + {server {} ""} + {ssl {} 1} + {user {} ""} + {stype {} "imap"} + {path {} ""} + {view {} ""} + {onclecancel {} ""} +} + +## read vars +foreach item $cledit_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + if {[llength $item] > 2} { + set [lindex $item 0] [lindex $item 2] + } else { + error [list _action [lindex $item 1] $result] + } + } + } else { + set [lindex $item 0] 1 + } +} + +set cledit_menu { + { + {} + { + { + # * * * * OK * * * * + if {$add} { + cgi_image_button cle_save=[WPimg but_save] border=0 alt="Save Config" + } else { + cgi_image_button cle_save=[WPimg but_save] border=0 alt="Save Config" + } + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + if {[string length $onclecancel]} { + cgi_puts [WPMenuURL "wp.tcl?page=$onclecancel&cid=$cid&oncancel=$oncancel" "" [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] "" target=_top] + } else { + cgi_puts [WPMenuURL "wp.tcl?page=$oncancel&cid=$cid" "" [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] "" target=_top] + } + } + } + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "Collection List Configuration" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=clconfig target=_top { + cgi_text "cid=$cid" type=hidden notab + cgi_text "page=conf_process" type=hidden notab + cgi_text "cp_op=clconfig" type=hidden notab + cgi_text "oncancel=$oncancel" type=hidden notab + cgi_text "cl=$cl" type=hidden notab + cgi_text "add=$add" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + # + # next comes the menu down the left side + # + eval { + cgi_table_data $_wp(menuargs) rowspan=4 { + WPTFCommandMenu cledit_menu {} + } + } + } + + # + # In main body of screen goe confg list + # + cgi_table_row { + cgi_table_data valign=top width="100%" class=dialog { + if {$add == 0 && $errtext == 0} { + set item [WPCmd PEConfig clextended $cl] + set nick [lindex $item 0] + set server [lindex $item 2] + set path [lindex $item 3] + set view [lindex $item 4] + set user "" + set stype "imap" + set ssl 0 + } + set server_flags { + ssl + user + imap + } + # jpf: took out nntp, service, and pop3 + foreach flag $server_flags { + if {[regexp -nocase "^\[^/\]*(/\[^/\]*)*(/$flag\[^/\]*)(/\[^/\]*)*" $server match junk1 flagset junk2]} { + set regprob 1 + if {[regexp -nocase "^/$flag\$" $flagset]} { + set regprob 0 + if {[string compare [string tolower $flag] "ssl"] == 0} { + set ssl 1 + } elseif {[regexp -nocase "(imap|nntp|pop3)" $flag]} { + set stype "$flag" + } else { + set regprob 1 + } + } elseif {[regexp -nocase "^/user=(.*)\$" $flagset match tuser]} { + set user "$tuser" + set regprob 0 + } elseif {[regexp -nocase "^/service=(.*)\$" $flagset match tuser]} { + if {[regexp -nocase "(imap|nntp|pop3)" $tuser]} { + set stype "$stype" + } else {set regprob 1} + } else { + set regprob 1 + } + if {$regprob == 0} { + regsub -nocase "^(\[^/\]*)(/\[^/\]*)*(/$flag\[^/\]*)(/\[^/\]*)*" $server "\\1\\2\\4" server + } + } + } + cgi_table border=0 cellspacing=0 cellpadding=5 { + cgi_table_row { + cgi_table_data align=right { + cgi_puts "[cgi_font size=+1 "Nickname[cgi_nbspace]: "]" + } + cgi_table_data align=left { + cgi_text "nick=$nick" size=40 notab + } + } + cgi_table_row { + cgi_table_data align=right valign=top { + cgi_puts "[cgi_font size=+1 "Server[cgi_nbspace]: "]" + } + cgi_table_data align=left { + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" { + cgi_table_row { + cgi_table_data colspan=2 { + cgi_text "server=$server" size=40 notab + } + } + cgi_table_row { + cgi_table_data { + cgi_puts "[cgi_font size=-1 "SSL"]" + if {$ssl == 1} { + set checked checked + } else { + set checked "" + } + cgi_checkbox "ssl" style=background-color:$_wp(dialogcolor) $checked + } + cgi_table_data align=right { + cgi_puts "[cgi_font size=-1 "User:[cgi_nbspace]"]" + cgi_text "user=$user" size=10 notab + } + cgi_text "stype=imap" type=hidden notab + } + } + } + } + cgi_table_row { + cgi_table_data align=right { + cgi_puts "[cgi_font size=+1 "Path[cgi_nbspace]: "]" + } + if {[string compare "nntp" $stype] == 0 && [regexp -nocase {^#news\.(.*)$} $path match rempath]} { + set path "$rempath" + } + cgi_table_data align=left { + cgi_text "path=$path" size=40 notab + } + } + cgi_table_row { + cgi_table_data align=right { + cgi_puts "[cgi_font size=+1 "View[cgi_nbspace]: "]" + } + cgi_table_data align=left { + cgi_text "view=$view" size=40 notab + } + } + } + } + } + + cgi_table_row { + cgi_table_data height=200 class=dialog { + cgi_puts [cgi_nbspace] + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/cmdfunc.tcl b/web/cgi/alpine/1.0/cmdfunc.tcl new file mode 100755 index 00000000..949baf0f --- /dev/null +++ b/web/cgi/alpine/1.0/cmdfunc.tcl @@ -0,0 +1,639 @@ +#!./tclsh +# $Id: cmdfunc.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# cmdfunc.tcl +# +# Purpose: CGI script to serve as single location for menu/command +# function definitions +# +# OPTIMIZE: have servlet interpreter grok/exec these? +# +# Input: + +# Output: +# + +proc WPTFTitle {{context {some page}} {newmail {}} {nologo 0} {aboutcancel {}}} { + global _wp + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" class=title { + cgi_table_row { + if {!$nologo} { + cgi_table_data valign=top align=left height=$_wp(titleheight) { + + if {[string length $aboutcancel]} { + cgi_put [cgi_url [cgi_imglink smalllogo] wp.tcl?page=help&topic=about&oncancel=$aboutcancel class=navbar target=_top] + } else { + cgi_put [cgi_imglink smalllogo] + } + } + } + + # work in new mail here + if {[llength $newmail]} { + cgi_table_data align=center { + WPTFStatusTable $newmail + } + } + + cgi_table_data align=right valign=middle height=$_wp(titleheight) { + cgi_put [cgi_span "style=margin-right: 8; color: $_wp(titlecolor)" "$context"] + } + } + } +} + +proc WPTFStatusTable {msgs {iconlink {0}} {style {}}} { + global _wp + + cgi_table width=100% border=0 cellpadding=0 cellspacing=0 $style { + cgi_table_row align=right { + + if {[info exists _wp(statusicons)] && $_wp(statusicons)} { + set img [cgi_imglink bang] + set snd "" + foreach m $msgs { + if {[string length [lindex $m 1]]} { + set img [cgi_imglink [lindex $m 1]] + if {$iconlink && [string length [lindex $m 2]]} { + set img [cgi_url $img wp.tcl?page=view&uid=[lindex $m 2] target=body] + } + + set snd [lindex $m 3] + break + } + } + + cgi_table_data { + cgi_puts ${img}${snd} + } + } + + cgi_table_data align=center class="statustext" { + set i 0 + + foreach m $msgs { + + if {[array exists lastmsg] && [info exists lastmsg([lindex $m 0])]} { + incr lastmsg([lindex $m 0]) + continue + } + + if {0 == [string compare [string range [lindex $m 0] 0 20] "Alert received while "]} { + set style "style=border: 1px solid red ; background-color: pink; padding: 2; width: 80%;" + } elseif {!([info exists _wp(statusicons)] && $_wp(statusicons))} { + set style "style=color: white ; background-color: $_wp(menucolor); padding-left:8px; padding-right:8px; white-space: nowrap;" + } else { + set style + } + + if {$iconlink && [string length [lindex $m 2]] && !([info exists _wp(statusicons)] && $_wp(statusicons))} { + set txt [cgi_url [lindex $m 0] wp.tcl?page=fr_view&uid=[lindex $m 2] target=body "style=text-decoration: none; color: white"] + } else { + set txt [lindex $m 0] + } + + cgi_division "style=\"padding-bottom: 1px\"" { + cgi_puts [cgi_span $style $txt] + } + + set lastmsg([lindex $m 0]) 1 + } + } + + if {[info exists _wp(statusicons)] && $_wp(statusicons)} { + cgi_table_data align=left { + cgi_puts $img + } + } + } + } +} + + +proc WPTFImageButton {args} { + return [cgi_buffer {eval cgi_image_button $args border=0}] +} + +proc WPTFCommandMenu {s_menu c_menu} { + global _wp + + set clist {} + if {[string length $s_menu]} { + upvar $s_menu specificmenu + if {[llength $specificmenu]} { + lappend clist $specificmenu + } + } + + if {[string length $c_menu]} { + upvar $c_menu commonmenu + if {[llength $commonmenu]} { + if {[llength $clist]} { + lappend clist {} + } + lappend clist $commonmenu + } + } + + cgi_table border=0 bgcolor=$_wp(menucolor) cellpadding=0 cellspacing=0 width=112 "style=\"padding: 8 0 8 4\"" { + foreach menulist $clist { + switch [llength $menulist] { + 0 { + cgi_table_row { + cgi_table_data { + cgi_hr "width=75%" + } + } + } + default { + foreach item $menulist { + if {[llength $item] == 0} { + cgi_table_row { + cgi_table_data { + cgi_hr "width=75%" + } + } + continue + } + if {[llength $item] == 1} { + cgi_table_row { + cgi_table_data { + eval [lindex $item 0] + } + } + continue + } + if {[string length [lindex $item 0]]} { + if {[uplevel [lindex $item 0]] == 0} { + continue + } + } + + cgi_table_row { + foreach l [lindex $item 1] { + cgi_table_data align=left valign=middle class=navbar { + uplevel $l + } + } + } + } + } + } + } + } +} + +proc WPTFScript {scrpt {dflt ""}} { + global _wp + + switch -- $scrpt { + main { + set src main.tcl + } + index { + set src index.tcl + WPCmd PEInfo set wp_body_script $src + } + view { + set src view.tcl + WPCmd PEInfo set wp_body_script $src + } + body { + if {[catch {WPCmd PEInfo set wp_body_script} src]} { + set src index.tcl + catch {WPCmd PEInfo set wp_body_script $src} + } + } + fr_view { + set src do_view.tcl + } + quit { + set src fr_queryquit.tcl + } + folders { + set src folders.tcl + } + fldrbrowse { + set src fldrbrowse.tcl + } + fldrsavenew { + set src fldrsavenew.tcl + } + fldrdel { + set src fr_querydelfldr.tcl + } + compose { + set src fr_compose.tcl + } + addrbrowse { + set src fr_addrbrowse.tcl + } + savebrowse { + set src fr_fldrbrowse.tcl + } + savecreate { + set src fr_fldrsavenew.tcl + } + take { + set src fr_take.tcl + } + takeedit { + set src fr_takeedit.tcl + } + takesame { + set src fr_takesame.tcl + } + ldapbrowse { + set src fr_ldapbrowse.tcl + } + addrbook { + set src addrbook.tcl + } + tconfig { + set src tconfig.tcl + } + cledit { + set src cledit.tcl + } + filtedit { + set src filtedit.tcl + } + conf_process { + set src conf_process.tcl + } + resume { + set src fr_resume.tcl + } + spell { + set src fr_spellcheck.tcl + } + auth { + set src fr_queryauth.tcl + } + expunge { + set src fr_queryexpunge.tcl + } + askattach { + set src fr_queryattach.tcl + } + ldapquery { + set src fr_ldapquery.tcl + } + querycreate { + set src fr_querycreate.tcl + } + queryprune { + set src fr_queryprune.tcl + } + attach { + set src attach.tcl + } + dosend { + set src dosend.tcl + } + docancel { + set src docancel.tcl + } + help { + set src fr_help.tcl + } + split { + set src fr_split.tcl + } + default { + if {[regexp {.*\.tcl$} $scrpt s]} { + set src $scrpt + } elseif {[string length $dflt]} { + set src $dflt + } else { + error "Unrecognized script abbreviation: $scrpt" + } + } + } + + return [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) $src] +} + +proc WPTFSaveDefault {{uid 0}} { + # "size" rather than "number" to work around temporary alpined bug + if {$uid == 0 + || [catch {WPCmd PEMessage $uid size} n] + || $n == 0 + || [catch {WPCmd PEMessage $uid savedefault} savedefault]} { + if {[WPCmd PEFolder isincoming 0]} { + set colid 1 + } else { + set colid 0 + } + + return [list $colid "saved-messages"] + } + + return $savedefault +} + +if {$_wp(keybindings)} { + proc WPTFKeyEquiv {kl {exclusions {}} {frame window}} { + if {[llength $kl] > 0} { + WPStdScripts + + append js "function bindListener(o,f)\{" + if {[isW3C]} { + append js "o.addEventListener('keypress',f, false);\n" + set cancelkeystroke "e.preventDefault(); return false;" + } elseif {[isIE]} { + append js "o.onkeydown = f;\n" + set cancelkeystroke "return false;" + } else { + append js "o.onkeydown = f;" + append js "o.captureEvents(Event.KEYDOWN);\n" + set cancelkeystroke "return false;" + } + append js "\}\n" + + append js "function nobubble(e)\{" + if {[isW3C]} { + append js " e.stopPropagation();" + } elseif {[isIE]} { + append js " event.cancelBubble = true;" + } + append js "\}\n" + + append js "function keyed(e)\{" + if {[isW3C] && [llength $exclusions]} { + set ex "" + foreach o $exclusions { + if {[string length $ex]} { + append ex " || " + } + + append ex "e.target == $o" + } + append js "if (e.target && ($ex)) return true;" + } + append js " var c = getKeyStr(e);" + append js " if(getControlKey(e))\{" + append js " switch(c)\{" + append js " case 'n' : window.status = 'New window creation disabled in WebPine.' ; $cancelkeystroke" + append js " \}" + append js " \}" + append js " else" + append js " switch(c)\{" + foreach kb $kl { + append js " case '[lindex $kb 0]' : ${frame}.webpinelink = 1; [lindex $kb 1] ; $cancelkeystroke" + } + + append js " \}\}\n" + + set onload "bindListener(document,keyed);" + + if {![isW3C]} { + foreach o $exclusions { + append onload "bindListener($o,nobubble);" + } + } + + cgi_javascript { + cgi_puts $js + } + + return $onload + } + } +} + +# add given folder name to the cache of saved-to folders +proc WPTFAddSaveCache {f_name} { + global _wp + + if {[catch {WPSessionState save_cache} flist] == 0} { + if {[set i [lsearch -exact $flist $f_name]] < 0} { + set flist [lrange $flist 0 [expr {$_wp(save_cache_max) - 2}]] + } else { + set flist [lreplace $flist $i $i] + } + + set flist [linsert $flist 0 $f_name] + } else { + set flist [list $f_name] + } + + catch {WPSessionState save_cache $flist} +} + +# return the list of cached saved-to folders and make sure given +# default is somewhere in the list +proc WPTFGetSaveCache {{def_name ""}} { + + if {![string length $def_name]} { + set savedef [WPTFSaveDefault 0] + set def_name [lindex $savedef 1] + } + + set seen "" + + if {[catch {WPSessionState save_cache} flist] == 0} { + foreach f $flist { + if {[string compare $def_name $f] == 0} { + set def_listed 1 + } + + if {[string length $f] && [lsearch -exact $seen $f] < 0} { + lappend options $f + lappend options $f + lappend seen $f + } + } + } + + if {!([info exists options] && [info exists def_listed])} { + lappend options $def_name + lappend options $def_name + } + + if {[catch {WPCmd set wp_cache_folder} wp_cache_folder] + || [string compare $wp_cache_folder [WPCmd PEMailbox mailboxname]]} { + # move default to top on new folder + switch -- [set x [lsearch -exact $options $def_name]] { + 0 { } + default { + if {$x > 0} { + set options [lreplace $options $x [expr {$x + 1}]] + } + + set options [linsert $options 0 $def_name] + set options [linsert $options 0 $def_name] + } + } + + catch {WPCmd set wp_cache_folder [WPCmd PEMailbox mailboxname]} + } + + lappend options "\[ folder I type in \]" + lappend options "__folder__prompt__" + + lappend options "\[ folder in my folder list \]" + lappend options "__folder__list__" + + return $options +} + +# add given folder name to the visited folder cache +proc WPTFAddFolderCache {f_col f_name} { + global _wp + + if {$f_col != 0 || [string compare [string tolower $f_name] inbox]} { + if {0 == [catch {WPSessionState folder_cache} flist]} { + + if {[catch {WPSessionState left_column_folders} fln]} { + set fln $_wp(fldr_cache_def) + } + + for {set i 0} {$i < [llength $flist]} {incr i} { + set f [lindex $flist $i] + if {$f_col == [lindex $f 0] && 0 == [string compare [lindex $f 1] $f_name]} { + break + } + } + + if {$i >= [llength $flist]} { + set flist [lrange $flist 0 $fln] + } else { + set flist [lreplace $flist $i $i] + } + + set flist [linsert $flist 0 [list $f_col $f_name]] + # let users of data know it's changed (cheaper than hash) + WPScriptVersion common 1 + } else { + catch {unset flist} + lappend flist [list $f_col $f_name] [list [WPTFSaveDefault 0]] + # ditto + WPScriptVersion common 1 + } + + catch {WPSessionState folder_cache $flist} + } +} + +# return the list of cached visited folders and make sure given +# default is somewhere in the list +proc WPTFGetFolderCache {} { + if {[catch {WPSessionState folder_cache} flist]} { + catch {unset flist} + lappend flist [WPTFSaveDefault 0] + catch {WPSessionState folder_cache $flist} + } + + return $flist +} + +proc WPExitOnClose {{frame window}} { + global _wp + + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function wpLink(){" + cgi_put " ${frame}.webpinelink = 1;" + cgi_put " return true;" + cgi_puts "}" + cgi_put "function wpLoad(){" + cgi_put " ${frame}.webpinelink = 0;" + cgi_puts "}" + cgi_put "function wpUnLoad(){" + cgi_put " if(!${frame}.webpinelink){" + cgi_put " window.open('[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/ripcord.tcl?t=10&cid=[WPCmd PEInfo key]','Depart','width=350,height=200');" + cgi_put " }" + cgi_puts "}" + } + + uplevel 1 { + + # tweak some cgi_* procs for global effect + if {0 == [catch {rename cgi_url _wp_orig_cgi_url}]} { + proc cgi_url {args} { + lappend newargs [lindex $args 0] + foreach a [lrange $args 1 end] { + if {[regexp "^(onClick)=(.*)" $a dummy attr str]} { + set onclicked 1 + lappend newargs "${attr}=wpLink();${str}" + } else { + lappend newargs $a + } + } + + if {![info exists onclicked]} { + lappend newargs "onClick=wpLink();" + } + + return [eval "_wp_orig_cgi_url $newargs"] + } + } + + if {0 == [catch {rename cgi_area _wp_orig_cgi_area}]} { + proc cgi_area {args} { + lappend newargs [lindex $args 0] + foreach a [lrange $args 1 end] { + if {[regexp "^(onClick)=(.*)" $a dummy attr str]} { + set onclicked 1 + lappend newargs "${attr}=\"wpLink();${str}\"" + } else { + lappend newargs $a + } + } + + if {![info exists onclicked]} { + lappend newargs "onClick=\"return wpLink();\"" + } + + return [eval "_wp_orig_cgi_area $newargs"] + } + } + + if {0 == [catch {rename cgi_form _wp_orig_cgi_form}]} { + proc cgi_form {args} { + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp "^onSubmit=(.*)" $a dummy str]} { + set onsubmitted 1 + lappend newargs "onSubmit=wpLink(); ${str}" + } else { + lappend newargs $a + } + } + + if {![info exists onsubmitted]} { + lappend newargs "onSubmit=return wpLink();" + } + + lappend newargs [lindex $args end] + + uplevel 1 "_wp_orig_cgi_form $newargs" + } + } + } +} + +proc WPTFIndexWidthRatio {fields field} { + # should be formula based on total fields + # and number of "wider" fields + switch [string toupper $field] { + TO - + FROM - + FROMORTO - + FROMORTONOTNEWS - + RECIPS - + SENDER - + SUBJECT { return 1.25 } + default { return 1 } + } +} diff --git a/web/cgi/alpine/1.0/common.tcl b/web/cgi/alpine/1.0/common.tcl new file mode 100755 index 00000000..4a540cc8 --- /dev/null +++ b/web/cgi/alpine/1.0/common.tcl @@ -0,0 +1,289 @@ +#!./tclsh +# $Id: common.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# common.tcl +# +# Purpose: CGI script snippet to generate html output associated +# with the WebPine message view/index ops frame +# +# Input: +set ops_vars { +} + + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set padleft 3px + +# +# Command Menu definition for Message View Screen +# +set view_menu { +} + +set common_menu { + { + {expr {0}} + { + { + # * * * * UBIQUITOUS INBOX LINK * * * * + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_index.tcl target=spec class=navbar] + } + } + } + } + { + {expr {0}} + { + { + # * * * * FOLDER LIST * * * * + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=main.tcl&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * Addr books * * * * + cgi_puts [cgi_url "Address Book" wp.tcl?page=addrbook&oncancel=main.tcl target=_top class=navbar] + } + } + } +} + + +WPEval $ops_vars { + cgi_http_head { + WPStdHttpHdrs {} 60 + } + + cgi_html { + cgi_head { + if {[info exists _wp(exitonclose)]} { + WPExitOnClose top.spec.body + } + + WPStyleSheets + cgi_script type="text/javascript" language="JavaScript" { + cgi_puts "function flip(n){" + cgi_put " var d = top.spec.body.document;" + cgi_put " var f = d.index;" + cgi_put " if(f && document.implementation){" + cgi_put " var e = d.createElement('input');" + cgi_put " var ver = navigator.appVersion;" + cgi_put " if(!((ver.indexOf('MSIE')+1) && (ver.indexOf('Macintosh')+1))) e.type = 'hidden';" + cgi_put " e.name = 'bod_'+n;" + cgi_put " e.value = '1';" + cgi_put " f.appendChild(e);" + cgi_put " f.submit();" + cgi_put " return false;" + cgi_puts " }" + cgi_puts " return true;" + cgi_puts "}" + } + + if {$_wp(keybindings)} { + set kequiv { + {{l} {top.location = 'wp.tcl?page=folders'}} + {{a} {top.location = 'wp.tcl?page=addrbook'}} + {{?} {top.location = 'wp.tcl?page=help'}} + {{n} {if(flip('next')) top.spec.body.location = 'wp.tcl?page=body&bod_next=1'}} + {{p} {if(flip('prev')) top.spec.body.location = 'wp.tcl?page=body&bod_prev=1'}} + {{i} {if(top.spec.cmds) top.spec.location = 'fr_index.tcl'}} + {{s} {if(top.spec.cmds) top.spec.cmds.document.saveform.f_name.focus()}} + {{d} {if(top.spec.cmds) top.spec.cmds.document.delform.op[0].click()}} + {{u} {if(top.spec.cmds) top.spec.cmds.document.delform.op[1].click()}} + {{r} {if(top.spec.cmds) top.spec.cmds.document.replform.op.click()}} + {{f} {if(top.spec.cmds) top.spec.cmds.document.forwform.op.click()}} + {{ } {if(top.spec.body.document.index && flip('next')) top.spec.body.location = 'wp.tcl?page=body&bod_next=1'}} + {{-} {if(top.spec.body.document.index && flip('prev')) top.spec.body.location = 'wp.tcl?page=body&bod_prev=1'}} + {{z} {if(top.spec.body.document.index && top.spec.body.document.index.zoom) top.spec.body.document.index.zoom.click()}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key]'"] + + if {[WPCmd PEInfo feature enable-full-header-cmd]} { + lappend kequiv [list {h} "if(top.spec.cmds.document.saveform) top.spec.body.location = 'wp.tcl?page=view&fullhdr=flip'"] + } + + set onload "onLoad=[WPTFKeyEquiv $kequiv {} top.spec.body] top.gen.focus();" + } + } + + cgi_body bgcolor=$_wp(bordercolor) $onload { + + cgi_put [cgi_url [cgi_imglink smalllogo] wp.tcl?page=help&topic=about class=navbar target=_top] + + cgi_br + + cgi_division class=navbar "style=\"background-color: $_wp(menucolor)\"" { + cgi_division "style=\"padding: 8px 0 2px $padleft\"" { + cgi_puts [cgi_span "style=font-weight: bold" "Current Folder"] + } + + set mbn [WPCmd PEMailbox mailboxname] + if {[string length $mbn] > 16} { + set mbn "[string range $mbn 0 14]..." + } + + cgi_division align=center { + cgi_put [cgi_url $mbn fr_index.tcl target=spec class=navbar] + + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + cgi_put [cgi_span "style=color: yellow; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + cgi_put [cgi_span "style=color: yellow; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + } + + cgi_hr "width=75%" "style=\"margin-top:8px\"" + + # Common Navigation controls + cgi_division align=center "style=\"padding-bottom: 4px\"" { + cgi_put [cgi_img [WPimg but_rnd_block] border=0 "usemap=#nav" "alt=Navigation Controls"] + cgi_map nav { + cgi_area shape=rect coords=0,0,37,38 "href=wp.tcl?page=body&bod_prev=1" target=body "onClick=\"return flip('prev')\"" "alt=Previous" + cgi_area shape=rect coords=0,40,32,74 "href=wp.tcl?page=body&bod_next=1" target=body "onClick=\"return flip('next')\"" "alt=Next" + cgi_area shape=rect coords=50,0,82,38 "href=wp.tcl?page=body&bod_first=1" target=body "onClick=\"return flip('first')\"" "alt=First" + cgi_area shape=rect coords=50,40,82,74 "href=wp.tcl?page=body&bod_last=1" target=body "onClick=\"return flip('last')\"" "alt=Last" + } + + # Jump option + if {[WPCmd PEInfo feature enable-jump-cmd]} { + cgi_br + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=body name=goform "style=margin-top:6" { + cgi_text "page=body" type=hidden notab + cgi_text gonum= class=navtext size=4 maxlength=6 "onClick=this.select()" + if {0} { + cgi_br + cgi_submit_button "goto=Jump to Msg \#" class=navtext "style=margin-right:2;margin-top:6" + } else { + cgi_submit_button "goto=Jump" class=navtext "style=margin-right:2" + } + } + } + } + + cgi_hr "width=75%" + + cgi_division "style=\"padding: 0 0 6px $padleft\"" { + + if {[catch {WPSessionState left_column_folders} fln]} { + set fln $_wp(fldr_cache_def) + } + + if {$fln > 0} { + cgi_puts [cgi_span "style=font-weight: bold" "Folders"] + cgi_division "style=\"padding-left: 4px\"" { + # UBIQUITOUS INBOX LINK + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_index.tcl target=spec class=navbar] + } + + set n 0 + set fc [WPTFGetFolderCache] + for {set i 0} {$i < [llength $fc] && $i < $fln} {incr i} { + set f [lindex $fc $i] + + if {0 == [catch {WPCmd PEFolder exists [lindex $f 0] [lindex $f 1]} result] && $result} { + cgi_br + + set fn [lindex $f 1] + if {[string length $fn] > 15} { + set fn "...[string range $fn end-15 end]" + } + + if {[string compare [lindex $f 1] [WPCmd PEMailbox mailboxname]]} { + cgi_put [cgi_url $fn "open.tcl?folder=[lindex $f 1]&colid=[lindex $f 0]&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } else { + cgi_put [cgi_url $fn fr_index.tcl target=spec class=navbar] + } + + if {[incr n] >= $fln} { + break + } + } + } + + cgi_br + cgi_puts [cgi_url "More Folders..." "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } else { + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + + cgi_hr "width=75%" + + # Common Operations + cgi_division "style=\"padding: 0 0 0 $padleft\"" { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key] target=_top class=navbar] + cgi_br + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=main.tcl&cid=[WPCmd PEInfo key] target=_top class=navbar] + cgi_br + # * * * * Addr books * * * * + cgi_puts [cgi_url "Address Book" wp.tcl?page=addrbook&oncancel=main.tcl target=_top class=navbar] + } + + cgi_division "style=\"padding: 12px 0 0 $padleft\"" { + cgi_put [cgi_url "Configure" wp.tcl?page=conf_process&newconf=1&oncancel=main.tcl&cid=[WPCmd PEInfo key] class=navbar target=_top] + cgi_br + cgi_put [cgi_url "Get Help" wp.tcl?page=help class=navbar target=_top] + } + + cgi_division "style=\"padding: 12px 0 10px $padleft\"" { + if {[WPCmd PEInfo feature quit-without-confirm]} { + cgi_puts [cgi_url "Quit $_wp(appname)" $_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid target=_top class=navbar] + } else { + cgi_puts [cgi_url "Quit $_wp(appname)" wp.tcl?page=quit&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/compose.tcl b/web/cgi/alpine/1.0/compose.tcl new file mode 100755 index 00000000..d5a6af3d --- /dev/null +++ b/web/cgi/alpine/1.0/compose.tcl @@ -0,0 +1,804 @@ +#!./tclsh +# $Id: compose.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# compose.tcl +# +# Purpose: TCL script to generate html form representing +# a message composition. + +# Input: +set compose_vars { + {uid "" 0} + {style "" ""} + {nickto "" ""} + {book "" 0} + {ai "" -1} + {notice "" ""} + {repall "" 0} + {reptext "" 0} + {repqstr "" ""} + {f_name "" ""} + {f_colid "" 0} + {cid "Missing Command ID"} + {spell "" ""} + {oncancel "" "main.tcl"} +} + + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +# Output: +# + +set bgcolor $_wp(dialogcolor) +set buttoncolor "ffcc66" + +# set the default for the compose form. Modern browsers should submit +# in the character set of the HTML form. +set default_charset "UTF-8" + +#set cancelmsg "Really Cancel your Message (and destroy its text)" + +set msgs(cancel) "Cancel message (answering OK will abandon your mail message)" + +set msgs(noattach) {[ Message has no attachments ]} + +set defaultheaders {to cc subject attach} + +set fccname "" + +proc fieldname {name} { + regsub -all -- {-} [string tolower $name] {_} fieldname + return $fieldname +} + +proc default_fcc {itemval} { + global fccdefault f_name f_colid + + if {[catch {WPCmd PEFolder collections} collections]} { + set collections "" + } + + # fcc's itemval should be a list of collection-id and folder-name + if {[llength $itemval] == 2} { + set fcccol [lindex $itemval 0] + set fccname [lindex $itemval 1] + } elseif {[string length $f_name]} { + set fcccol $f_colid + set fccname $f_name + } elseif {[info exists fccdefault] || [catch {WPCmd PECompose fccdefault} fccdefault] == 0} { + set fcccol [lindex $fccdefault 0] + set fccname [lindex $fccdefault 1] + unset fccdefault + } else { + set fccname sent-mail + if {[llength $collections] > 1} { + set fcccol 1 + } else { + set fcccol 0 + } + } + + return [list $fccname $fcccol $collections] +} + +proc rowfield {item itemval style} { + global _wp msgs attachments bgcolor postoption fccname cols + + set litem [string tolower $item] + + if {$cols == 80} { + set textsize "60%" + } else { + set textsize $cols + } + + cgi_table_row class=body $style bgcolor="$bgcolor" { + cgi_table_data align=left class=comphdr width=60 { + switch -- [string tolower $item] { + attach { + #cgi_submit_button "queryattach=Attach" class="comphdrbtn" + cgi_put Attachments + } + x_fcc { + cgi_submit_button "br_fcc=Fcc" class=comphdrbtn + } + default { + cgi_put $item + } + } + } + + cgi_table_data align=center class=comphdr "style=\"padding: 0px 6px 0px 2px\"" { + cgi_put [cgi_bold ":"] + } + + cgi_table_data align=left valign=middle class=comptext "style=\"padding: 2px 0px\"" nowrap { + switch -- [string tolower $item] { + attach { + cgi_table border=0 cellpadding=0 cellspacing=0 width="100%" { + cgi_table_row { + set alist "" + cgi_table_data align=left { + if {[info exists attachments] && [set n [llength $attachments]]} { + cgi_table border=0 cellpadding=0 cellspacing=0 width="100%" { + # format: {ID TITLE SIZE TYPE} + set i 1 + foreach a $attachments { + cgi_table_row { + if {$n > 1} { + cgi_table_data { + cgi_puts [cgi_font face=Helvetica "$i)"] + } + incr i + } + cgi_table_data valign=middle align=left { + set id [lindex $a 0] + cgi_puts [cgi_font face=Helvetica "[lindex $a 1] ([lindex $a 2] bytes) [lindex $a 3]"] + lappend alist $id + } + cgi_table_data align=right height=23 width=23 { + cgi_image_button detach_${id}=[WPimg but_remove] border=0 align=right alt="Delete Attachment" + } + } + } + } + } else { + cgi_put [cgi_font size="-1" face=Helvetica $msgs(noattach)] + } + + cgi_text attachments=[join $alist ","] type=hidden notab + } + + cgi_table_data align=right width=70 { + cgi_submit_button "queryattach=Attach" class=compbtn "style=\"width:64\"" + } + } + } + } + cc - + bcc - + reply-to - + to { + set fn [fieldname $item] + cgi_text $fn=${itemval} size=$textsize "style=\"padding: 2px\"" + cgi_image_button "br_${fn}=[WPimg book]" class=compbtn "alt=Address Book" "style=\"vertical-align:text-bottom\"" + cgi_submit_button "ex_${fn}=Expand" class=compbtn "style=\"vertical-align:base-line\"" + } + fcc { + set deffcc [default_fcc $itemval] + + set fccname [lindex $deffcc 0] + set fcccol [lindex $deffcc 1] + set collections [lindex $deffcc 2] + + cgi_table border=0 cellpadding=0 cellspacing=0 width="100%" { + cgi_table_row { + cgi_table_data { + if {[llength $collections] > 1} { + cgi_text [fieldname $item]=$fccname size=38 onFocus=this.select() + #cgi_put [cgi_font face=Helvetica "in[cgi_nbspace]collection:[cgi_nbspace]"] + cgi_put [cgi_font class=comphdr in][cgi_nbspace] + cgi_select colid align=center { + for {set j 0} {$j < [llength $collections]} {incr j} { + if {$j == $fcccol} { + set selected selected + } else { + set selected {} + } + + set colname [lindex [lindex $collections $j] 1] + if {[string length $colname] > 15} { + set colname "[string range $colname 0 12]..." + } + + cgi_option $colname value=$j $selected + } + } + } else { + cgi_text [fieldname $item]=$fccname size=$textsize maxlength=1024 onFocus=this.select() + cgi_text "colid=0" type=hidden notab + } + } + + cgi_table_data align=right { + cgi_submit_button "br_fcc=Browse" class="compbtn" + } + } + } + } + default { + cgi_text [fieldname $item]=${itemval} size=$textsize maxlength=1024 + } + } + } + } + + switch -- [string tolower $item] { + attach { + cgi_table_row class=smallhdr { + cgi_table_data colspan=2 { + cgi_put [cgi_img [WPimg dot]] + } + + cgi_table_data { + cgi_table cellpadding=0 cellspacing=0 border=0 { + cgi_table_row { + cgi_table_data valign=middle class=smallhdr { + # complicated cause prompt and feature are reverse sense + if {[info exists postoption(fcc-without-attachments)]} { + if {$postoption(fcc-without-attachments)} { + set checked "" + } else { + set checked checked + } + } elseif {[WPCmd PEInfo feature "fcc-without-attachments"]} { + set checked "" + } else { + set checked checked + } + + cgi_checkbox fccattach=1 class=smallhdr id="fcccb" $checked + } + cgi_table_data valign=middle class=smallhdr { + set blurb "Include attachments in copy of message saved to Fcc" + if {[string length $fccname]} { + append blurb " (i.e., \"$fccname\")" + } + + cgi_put [cgi_span "style=cursor: pointer" onclick="flipCheck('fcccb')" $blurb] + } + } + } + } + } + } + default {} + } +} + +set compose_menu { + { + {expr [info exists _wp(ispell)] && [file executable $_wp(ispell)]} + { + { + # * * * * SPELLCHECK * * * * + cgi_put [cgi_img [WPimg dot] width=4] + cgi_submit_button "check=Spell Check" class=navtext "style=\"margin-top:8\"" + } + } + } + { + {} + { + { + # * * * * HELP * * * * + cgi_put [cgi_img [WPimg dot] width=4] + cgi_submit_button "help=Get Help" class=navtext "style=\"margin-top:8;margin-bottom:8\"" + } + } + } +} + +set compose2_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put [cgi_img [WPimg dot] width=4] + cgi_submit_button "help=Get Help" class=navtext + } + } + } +} + +WPEval $compose_vars { + + if {$cid != [WPCmd PEInfo key]} { + error [list _close "Invalid Command ID"] + } + + set cols [WPCmd PEConfig columns] + + switch -- $style { + Reply { + set title "Reply to Message [WPCmd PEMessage $uid number]" + + if {[catch {cgi_import part}]} { + set part "" + } + + foreach h [WPCmd PEMessage $uid replyheaders $part] { + set hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + if {!$repall} { + catch {unset hdrvals(cc)} + } + + if {[WPCmd PEInfo feature quell-format-flowed] == 0} { + set flowed 1 + } + + if {$reptext} { + set replytext [WPCmd PEMessage $uid replytext $repqstr $part] + set body [join [lindex $replytext 0] "\r\n"] + if {[WPCmd PEInfo feature include-attachments-in-reply]} { + set attachments [lindex $replytext 1] + } + } else { + set body "" + foreach line [WPCmd PEInfo signature] { + append body "$line\r\n" + } + } + + catch {WPCmd set help_context reply} + } + Forward { + set title "Forward Message [WPCmd PEMessage $uid number]" + + if {[catch {cgi_import part}]} { + set part "" + } + + foreach h [WPCmd PEMessage $uid forwardheaders $part] { + set hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + foreach line [WPCmd PEInfo signature] { + append body "$line\r\n" + } + + if {[WPCmd PEInfo feature quell-format-flowed] == 0} { + set flowed 1 + } + + set forwardtext [WPCmd PEMessage $uid forwardtext $part] + append body [join [lindex $forwardtext 0] "\r\n"] + + set attachments [lindex $forwardtext 1] + catch {WPCmd set help_context forward} + } + Postponed { + set title "Postponed Message" + set postponed [WPCmd PEPostpone extract $uid] + + foreach h [lindex $postponed 0] { + append hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + set body [join [lindex $postponed 1] "\r\n"] + set attachments [lindex $postponed 2] + + foreach opt [lindex $postponed 3] { + switch [lindex $opt 0] { + charset { + set charset [lindex $opt 1] + } + } + } + + unset postponed + catch {WPCmd set help_context compose} + } + default { + if {![info exists title]} { + set title "Compose New Message" + } + + if {[catch {cgi_import ldap}] == 0 + && [string compare $ldap 1] == 0 + && [catch {cgi_import qn}] == 0 + && [catch {cgi_import si}] == 0 + && [catch {cgi_import ni}] == 0 + && [catch {WPCmd PELdap ldapext $qn "${si}.${ni}"} leinfo] == 0} { + foreach item [lindex $leinfo 1] { + switch -- [string tolower [lindex $item 0]] { + "email address" { + if {[catch {cgi_import ei}] == 0} { + set ldap_email [lindex [lindex $item 1] $ei] + } else { + set ldap_email [lindex [lindex $item 1] 0] + } + } + name { + set ldap_name [lindex [lindex $item 1] 0] + } + "fax telephone" { + set ldap_fax [lindex [lindex $item 1] 0] + } + } + } + + # put it all together + if {[catch {cgi_import fax}] == 0 && [string compare $fax yes] == 0} { + set n {[0-9]} + set n3 $n$n$n + set n4 $n$n$n$n + if {[info exists ldap_name] + && [regexp "^\\\+1 ($n3) ($n3)-($n4)\$" $ldap_fax dummy areacode prefix number] + && [lsearch -exact {206 425} $areacode] >= 0} { + regsub -all { } $ldap_name {_} ldap_fax_name + set hdrvals(to) "\"Fax to ${ldap_name}\" <${ldap_fax_name}@${areacode}-${prefix}-${number}.fax.cac.washington.edu>" + set hdrvals(subject) "FAX: " + } + } elseif {[info exists ldap_email]} { + if {[info exists ldap_name]} { + set hdrvals(to) "\"$ldap_name\" <$ldap_email>" + } else { + set hdrvals(to) $ldap_email + } + } + } + + if {[WPCmd PEInfo feature quell-format-flowed] == 0} { + set flowed 1 + } + + if {![info exists body] || [string length $body] == 0} { + if {([info exists msgdata] && [llength $msgdata]) || [catch {WPCmd set suspended_composition} msgdata] == 0} { + set attachments {} + foreach e $msgdata { + switch -- [string tolower [lindex $e 0]] { + "" { + # do nothing, empty field + } + attach { + if {[catch {WPCmd PECompose attachinfo [lindex $e 1]} ai]} { + WPCmd PEInfo statmsg $ai + } else { + lappend attachments [list [lindex $e 1] [lindex $ai 0] [lindex $ai 1] [lindex $ai 2]] + # attachment description is in [lindex $ai 3] + } + } + body { + catch {unset body} + if {[string compare $style Spell] == 0} { + if {[catch {cgi_import_as spell spell} result] == 0} { + if {[string compare $spell Cancel] == 0} { + WPCmd PEInfo statmsg "Spell Check Cancelled" + } elseif {[catch {WPCmd set wp_spellresult} spellresult] == 0} { + set oldbody [lindex $e 1] + foreach l $spellresult { + set oldline [lindex $oldbody [lindex $l 0]] + set newline "" + set offset 0 + foreach w [lindex $l 1] { + set o [lindex $w 0] + append newline "[string range $oldline $offset [expr {$o - 1}]][lindex $w 2]" + set offset [expr {$o + [lindex $w 1]}] + } + + append newline [string range $oldline $offset end] + + set newlines([lindex $l 0]) $newline + } + + for {set n 0} {$n < [llength $oldbody]} {incr n} { + if {[info exists newlines($n)]} { + append body $newlines($n) + } else { + append body [lindex $oldbody $n] + } + + append body "\r\n" + } + } else { + WPCmd PEInfo statmsg "No corrections present, Nothing changed." + } + } + + catch {WPCmd PEInfo unset wp_spellresult} + } + + if {![info exists body]} { + set body [join [lindex $e 1] "\r\n"] + } + } + fcc { + if {[string length $f_name]} { + set hdrvals(fcc) [list $f_colid $f_name] + } else { + set hdrvals(fcc) [lindex $e 1] + } + } + postoption { + set opt [lindex $e 1] + switch -- [lindex $opt 0] { + charset { + set charset [lindex $opt 1] + } + default { + set postoption([lindex $opt 0]) [lindex $opt 1] + } + } + } + default { + set hdrvals([fieldname [lindex $e 0]]) [lindex $e 1] + } + } + } + + if {![info exists body]} { + set body "" + } + } else { + set body "" + foreach line [WPCmd PEInfo signature] { + append body "$line\r\n" + } + + if {[string length $nickto] != 0 || $ai != -1} { + if {[catch {WPCmd PEAddress entry $book $nickto $ai} entryval] == 0} { + set addrlist [lindex $entryval 0] + set newfcc [lindex $entryval 1] + if {[string length $newfcc]} { + global fccdefault + if {[string compare $newfcc "\"\""] == 0} { + set newfcc "" + } + if {[catch {WPCmd PEFolder collections} collections]} { + set collections "" + } + set fccdefault [list [expr {[llength $collections] > 1 ? 1 : 0}] $newfcc] + } + } else { + set addrlist $nickto + } + # bug: where's "to" supposed to come from? + if {0 && [string length $to]} { + append to ", ${addrlist}" + } else { + set to $addrlist + } + } + + WPCmd PECompose noattach + } + } + + catch {WPCmd set help_context compose} + } + } + + if {[catch {WPCmd PECompose userhdrs} headers]} { + error [list _action "Header Retrieval Failure" $headers] + } + + catch {fconfigure stdout -encoding binary} + + if {![info exists charset]} { + set charset $default_charset + } + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=\"$charset\"" + } + + cgi_html { + cgi_head { + cgi_http_equiv Content-Type "text/html; charset=$charset" + + WPStdHtmlHdr "Compose Message" + WPStdScripts + WPStyleSheets + + cgi_put "<style type='text/css'>" + cgi_put ".comptext { background-color: $bgcolor ; font-family: courier, serif ; font-size: 10pt }" + cgi_put ".comphdr { background-color: $bgcolor ; font-family: arial, sans-serif ; font-size: 10pt ; font-weight: bold }" + cgi_put ".comphdrbtn { background-color: $bgcolor ; font-family: arial, sans-serif ; font-size: 10pt ; font-weight: bold ; text-decoration: underline }" + cgi_put ".comphdrbtnx { background-color: $buttoncolor ; font-family: arial, sans-serif ; font-size: 10pt ; font-weight: bold ; text-decorationx: underline }" + cgi_put ".compbtn { font-family: arial, sans-serif ; font-size: 9pt }" + cgi_put ".attachlist { width: 300 }" + cgi_put ".smallhdr { background-color: $bgcolor ; font-family: arial, sans-serif ; font-size: 8pt }" + cgi_puts "</style>" + + cgi_javascript { + cgi_put "function setop(i){" + cgi_put " eval('document.compose.sendop\['+i+'\].checked = true');" + cgi_put " return false;" + cgi_put "}" + } + } + + cgi_body BGCOLOR="$_wp(bordercolor)" onLoad=document.compose.to.focus() { + if {[info exists comments]} { + cgi_puts "Diag: " + foreach c $comments { + cgi_html_comment $c + } + } + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post name=compose enctype=multipart/form-data target=_top { + cgi_table border=0 cellspacing=0 cellpadding=0 width=100% { + cgi_table_row { + lappend msglist [list $notice] + # next comes the menu down the left side + eval { + cgi_table_data $_wp(menuargs) rowspan=2 { + + cgi_division class=navbar "style=background-color:$_wp(menucolor)" { + # * * * * SEND * * * * + cgi_puts "<fieldset>" + set doneverb " OK " + + cgi_puts [cgi_span class=navtext "When finished, choose action below, then click [cgi_italic $doneverb].[cgi_nl][cgi_nl]"] + + cgi_radio_button sendop=send id="RB1" + cgi_put [cgi_span class=navtext "style=color:white; cursor: pointer" onclick=\"flipCheck('RB1')\" "Send"] + cgi_br + cgi_radio_button sendop=postpone id="RB2" + cgi_put [cgi_span class=navtext "style=color:white; cursor: pointer" onclick=\"flipCheck('RB2')\" "Postpone"] + cgi_br + cgi_radio_button sendop=cancel id="RB3" + cgi_put [cgi_span class=navtext "style=color:white; cursor: pointer" onclick=\"flipCheck('RB3')\" "Cancel"] + cgi_br + cgi_br + #cgi_image_button action=[WPimg but_s_do] border=0 alt="Do" + cgi_division "style=padding-bottom:4" align=center { + cgi_submit_button "action=$doneverb" class=navtext + } + cgi_puts "</fieldset>" + } + + WPTFCommandMenu compose_menu {} + } + } + } + + cgi_table_row { + cgi_table_data border=0 bgcolor=$bgcolor { + cgi_table { + cgi_table_row { + cgi_table_data { + cgi_table border=0 cellspacing=0 cellpadding=0 align=left { + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "sessid=$sessid" type=hidden notab + cgi_text "page=post" type=hidden notab + cgi_text "postpost=$oncancel" type=hidden notab + if {[string length $repqstr]} { + cgi_text "repqstr=$repqstr" type=hidden notab + } + + if {0 && [info exists charset]} { + cgi_text "form_charset=$charset" type=hidden notab + # character encoding suport: the idea is to plant a known + # char in the given charset and see what comes back to + # post.tcl from the browser. Why is it again the @#*$! + # browser can't just tell us? + foreach tc {#8364 #1066 thorn tcedil #65509} { + cgi_puts "<input name=\"ke_$tc\" value=&${tc}; type=hidden notab>" + } + } + + if {[info exists flowed]} { + cgi_text "form_flowed=yes" type=hidden notab + } + + foreach field [WPCmd PECompose syshdrs] { + set hdr [fieldname [lindex $field 0]] + if {[info exists hdrvals($hdr)]} { + cgi_text "${hdr}=$hdrvals($hdr)" type=hidden notab + } + } + + if {[catch {WPCmd set wp_extra_hdrs} extras] == 0 && $extras == 0} { + set extrahdrs {} + } + + foreach field $headers { + set item [lindex $field 0] + + if {[string length $item] == 0} { + continue + } + + set itemvaldef [lindex $field 1] + set litem [string tolower $item] + set fn [fieldname $item] + + if {[info exists hdrvals($fn)]} { + set itemval $hdrvals($fn) + } elseif {[info exists $litem] && [string length [subst $$litem]]} { + set itemval [subst $$litem] + } elseif {[string length $itemvaldef]} { + set itemval $itemvaldef + } else { + set itemval "" + } + + if {[catch {WPCmd PECompose composehdrs} h] == 0 && [llength $h] > 0} { + set display_headers [string tolower $h] + } else { + set display_headers $defaultheaders + } + + if {![info exists extrahdrs]} { + if {[info exists postoption(fcc-set-by-addrbook)]} { + if {[lsearch -exact $display_headers fcc] < 0} { + lappend display_headers fcc + } + } + } + + if {[info exists attachments] && [llength $attachments] + && [lsearch -exact $display_headers attach] < 0} { + lappend display_headers attach + } + + if {[lsearch -exact $display_headers [string tolower $item]] >= 0} { + rowfield $item $itemval $style + } elseif {[info exists extrahdrs]} { + lappend extrahdrs [list $item $itemval $style] + } else { + switch -- [string tolower $item] { + fcc { + set deffcc [default_fcc $itemval] + + set fccname [lindex $deffcc 0] + set fcccol [lindex $deffcc 1] + + cgi_text [fieldname $item]=$fccname type=hidden notab + cgi_text "colid=$fcccol" type=hidden notab + } + default { + cgi_text "[fieldname $item]=$itemval" type=hidden notab + } + } + } + } + + if {[info exists extrahdrs]} { + cgi_table_row class=body bgcolor="$bgcolor" { + cgi_table_data colspan=4 align=left class=comptext { + cgi_image_button extrahdrs=[WPimg hdrless] border=0 alt="Hide Extra Headers" + } + } + + foreach pb $extrahdrs { + rowfield [lindex $pb 0] [lindex $pb 1] [lindex $pb 2] + } + } else { + cgi_table_row class=body bgcolor="$bgcolor" { + cgi_table_data colspan=4 align=left class=comptext { + cgi_image_button extrahdrs=[WPimg hdrmore] border=0 alt="Show Extra Headers" + } + } + } + } + } + } + + cgi_table_row { + cgi_table_data { + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" { + cgi_table_row class=body bgcolor="$bgcolor" { + cgi_table_data colspan=4 align=center class=comptext { + cgi_textarea body=${body} rows=20 cols=$cols wrap=physical class=view "style=\"padding: 2px\"" + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/comview.tcl b/web/cgi/alpine/1.0/comview.tcl new file mode 100755 index 00000000..01e1af80 --- /dev/null +++ b/web/cgi/alpine/1.0/comview.tcl @@ -0,0 +1,184 @@ +#!./tclsh +# $Id: comview.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# comview.tcl +# +# Purpose: CGI script to produce the common view commands frame + +# Input: +set comview_vars { + {f_colid {} [WPCmd PEFolder isincoming 0]} + {f_name {} "saved-messages"} +} + +# inherit global config +source ./alpine.tcl +source ./cmdfunc.tcl + +WPEval $comview_vars { + cgi_http_head { + WPStdHttpHdrs {} 60 + } + + cgi_html { + cgi_head { + if {[info exists _wp(exitonclose)]} { + WPExitOnClose top.spec.body + } + + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".viewop { font-family: arial, sans-serif; font-size: 7pt }" + cgi_puts "</style>" + if {$_wp(keybindings)} { + set kequiv { + {{?} {top.location = 'wp.tcl?page=help'}} + {{l} {top.location = 'wp.tcl?page=folders'}} + {{a} {top.location = 'wp.tcl?page=addrbook'}} + {{n} {top.spec.body.location = 'wp.tcl?page=view&bod_next=1'}} + {{p} {top.spec.body.location = 'wp.tcl?page=view&bod_prev=1'}} + {{i} {top.spec.location = 'fr_index.tcl'}} + {{s} {document.saveform.f_name.focus()}} + {{d} {document.delform.op[0].click()}} + {{u} {document.delform.op[1].click()}} + {{r} {document.replform.op.click()}} + {{f} {document.forwform.op.click()}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key]'"] + + if {[WPCmd PEInfo feature enable-full-header-cmd]} { + lappend kequiv [list {h} "top.spec.body.location = 'wp.tcl?page=view&fullhdr=flip'"] + } + + set onload "onLoad=[WPTFKeyEquiv $kequiv document.saveform.f_name top.spec.body]" + } + } + + cgi_body bgcolor=$_wp(bordercolor) background=[file join $_wp(imagepath) logo $_wp(logodir) back.gif] "style=\"background-repeat: repeat-x\"" $onload { + cgi_table class=ops cellpadding=0 cellspacing=0 border=0 width="100%" height=24 { + cgi_table_row { + cgi_table_data valign=middle align=left nowrap class=viewop { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=_top name=replform { + cgi_text "page=view" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "oncancel=main.tcl" type=hidden notab + cgi_text "postpost=fr_main.tcl" type=hidden notab + + cgi_table border=0 class=ops cellpadding=0 cellspacing=0 class=viewop { + cgi_table_row { + cgi_table_data class=viewop rowspan=2 { + # * * * * REPLY * * * * + cgi_submit_button op=Reply class="viewop" "style=\"vertical-align: middle; margin-left: 4\"" + } + cgi_table_data class=viewop { + cgi_checkbox "repall=1" style=vertical-align:middle + cgi_put "To All[cgi_nbspace]" + } + } + cgi_table_row { + cgi_table_data class=viewop rowspan=2 { + cgi_checkbox "reptext=1" checked style=vertical-align:middle + cgi_put "Include text" + } + } + } + } + } + + cgi_table_data valign=middle align=center { + cgi_put [cgi_img [WPimg blackdot] width=1 height=26] + } + + cgi_table_data valign=middle align=center nowrap { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=_top name=forwform { + cgi_text "page=view" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "oncancel=main.tcl" type=hidden notab + cgi_text "postpost=fr_main.tcl" type=hidden notab + + # * * * * FORWARD * * * * + cgi_submit_button op=Forward class="viewop" + } + } + + cgi_table_data valign=middle align=center { + cgi_put [cgi_img [WPimg blackdot] width=1 height=26] + } + + cgi_table_data valign=middle align=center nowrap class=viewop { + cgi_table class=ops cellpadding=0 cellspacing=0 border=0 class=viewop { + cgi_table_row { + cgi_table_data class=viewop { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=spec name=saveform { + cgi_text "page=fr_view" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "sid=[clock seconds]" type=hidden notab + + # * * * * Save * * * * + cgi_submit_button "save=Save" class="viewop" + cgi_put "[cgi_nbspace]to " + + cgi_text f_colid=$f_colid type=hidden notab + cgi_text op=save type=hidden notab + + cgi_select f_name class=viewop style=vertical-align:middle "onchange=document.saveform.save.click(); return false;" { + foreach {oname oval} [WPTFGetSaveCache] { + cgi_option $oname value=$oval + } + } + } + } + } + } + } + + cgi_table_data valign=middle align=center { + cgi_put [cgi_img [WPimg blackdot] width=1 height=26] + } + + cgi_table_data valign=middle align=center nowrap { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=_top name=take { + cgi_text "page=view" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_submit_button op=Take class="viewop" + } + } + + cgi_table_data valign=middle align=center { + cgi_put [cgi_img [WPimg blackdot] width=1 height=26] + } + + cgi_table_data valign=middle align=right nowrap { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=body name=delform { + cgi_text "page=view" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + # * * * * UNDELETE * * * * + cgi_submit_button op=Delete class="viewop" + + # * * * * UNDELETE * * * * + cgi_submit_button op=Undelete class="viewop" "style=\"margin-right: 4\"" + + # * * * * ANTISPAM * * * * + if {([info exists _wp(spamaddr)] && [string length $_wp(spamaddr)]) + || ([info exists _wp(spamfolder)] && [string length $_wp(spamfolder)])} { + cgi_submit_button "op=Report Spam" class="viewop" "style=\"margin-right: 4; color: white; background-color: black\"" + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/conf_process.tcl b/web/cgi/alpine/1.0/conf_process.tcl new file mode 100755 index 00000000..a8170c4e --- /dev/null +++ b/web/cgi/alpine/1.0/conf_process.tcl @@ -0,0 +1,1358 @@ +#!./tclsh +# $Id: conf_process.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# conf_process.tcl +# +# Purpose: CGI script to perform various message/mailbox +# oriented operations + +source genvars.tcl +source filter.tcl + +set cfs_vars { + {cid "Missing Command ID"} + {oncancel "Missing oncancel"} + {cp_op {} noop} + {save {} 0} + {delete {} 0} + {compose {} 0} + {cancel {} 0} + {gtab {} 0} + {mltab {} 0} + {mvtab {} 0} + {ctab {} 0} + {abtab {} 0} + {ftab {} 0} + {rtab {} 0} + {wv {} ""} + {varlistadd {} ""} + {newconf {} 0} +} + +## read vars +foreach item $cfs_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Import Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +proc wpGetVar {_var {valid ""}} { + upvar $_var var + + if {[catch {cgi_import_as $_var var} result]} { + error [list _action "Import Var $_var" $result] + } + + if {[string length $valid]} { + switch -exact -- $valid { + _INTEGER_ { + if {[string is integer -strict $var] != 1} { + error [list _action "Invalid Input" "Non-Numeric Value for $_var"] + } + } + default { + if {[lsearch -exact $valid $var] < 0} { + error [list _action "Invalid Input" "Unrecognized Value $var for $_var"] + } + } + } + } +} + +proc wpGetVarAs {_var _varas} { + upvar $_varas varas + + if {[catch {cgi_import_as $_var varas} result]} { + set varas "" + } +} + +if {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} +} + +proc wpGetGoodVars {} { + global wv + global general_vars msglist_vars composer_vars folder_vars address_vars msgview_vars rule_vars + + switch -- $wv { + msgl { + set goodvars $msglist_vars + } + msgv { + set goodvars $msgview_vars + } + address { + set goodvars $address_vars + } + composer { + set goodvars $composer_vars + } + folder { + set goodvars $folder_vars + } + rule { + set goodvars $rule_vars + } + general { + set goodvars $general_vars + } + } + return $goodvars +} + +proc fieldPos {fmt field} { + for {set i 0} {$i < [llength $fmt]} {incr i} { + if {[string compare [string toupper [lindex [lindex $fmt $i] 0]] [string toupper $field]] == 0} { + return $i + } + } + + return -1 +} + +proc numberedVar {nvbase nvtotal} { + if {[catch {wpGetVarAs $nvtotal nvtot}] == 0} { + for {set i 0} {$i < $nvtot} {incr i} { + if {[catch {wpGetVar ${nvbase}${i}} nvval] == 0} { + return $i + } + } + } + + return -1 +} + +set op $cp_op +if {[catch {WPCmd set conf_page} conftype]} { + set conftype general +} +if {[string length $wv]} { + set conftype $wv + set op tab +} +if {$save == 1 || [string compare $save Save] == 0} { + set op tab + set subop save +} elseif {$newconf} { + set op noop +} elseif {$gtab} { + set op "tab" + set conftype "general" +} elseif {$mltab} { + set op "tab" + set conftype "msgl" +} elseif {$mvtab} { + set op "tab" + set conftype "msgv" +} elseif {$ctab} { + set op "tab" + set conftype "composer" +} elseif {$abtab} { + set op "tab" + set conftype "address" +} elseif {$ftab} { + set op "tab" + set conftype "folder" +} elseif {$rtab} { + set op "tab" + set conftype "rule" +} elseif {$cancel == 1 || [string compare $cancel Cancel] == 0} { + set op "cancel" +} + +proc wpGetRulePattern {} { + global pattern_fields + + set patlist {} + + foreach {patvar patfield} $pattern_fields { + wpGetVarAs $patvar tval + + switch $patvar { + headers { + # collect header fields/values into "headers" + set headers {} + if {[catch {wpGetVarAs header_total hcnt} res] == 0} { + for {set i 0} {$i < $hcnt} {incr i} { + if {[catch {wpGetVarAs hdrfld${i} fld}] == 0 + && [catch {wpGetVarAs hdrval${i} val}] == 0} { + lappend headers [list $fld $val] + } + } + } + + lappend patlist [list headers $headers] + } + default { + lappend patlist [list $patvar $tval] + } + } + } + + + return $patlist + +} + +proc wpGetRuleAction {tosave} { + set actlist {} + wpGetVar action + if {$tosave == 1} { + lappend actlist [list "action" $action] + } else { + switch -- $action { + move {lappend actlist [list "kill" 0]} + delete {lappend actlist [list "kill" 1]} + } + } + wpGetVar actionfolder + lappend actlist [list "folder" $actionfolder] + wpGetVarAs moind moind + if {[string compare $moind "on"] == 0} { + lappend actlist [list [expr {$tosave == 1 ? "moind" : "move_only_if_not_deleted"}] "1"] + } else { + lappend actlist [list [expr {$tosave == 1 ? "moind" : "move_only_if_not_deleted"}] "0"] + } +} + + # + # Meat and potatoes of processing goes on here. + # Errors are barfed up as they occur, + # otherwise the result is communicated below... + # + set setfeatures [WPCmd PEConfig featuresettings] + set script fr_tconfig.tcl + switch -- $op { + tab { + if {[info exists goodvars] == 0} { + set goodvars [wpGetGoodVars] + } + foreach goodvar $goodvars { + set vtypeinp [lindex $goodvar 0] + set varname [lindex $goodvar 1] + set hlpthisvar 0 + wpGetVarAs hlp.$varname.x thlp + if {[string length $thlp]} { + set hlpthisvar 1 + set helpcancelset conf_process + } + switch -- $vtypeinp { + special { + switch -- $varname { + wp-columns { + if {$hlpthisvar} { + set subop varhelp + set varhelpname wp-columns + } else { + wpGetVar columns + WPCmd PEConfig columns $columns + } + } + left-column-folders { + if {0 == [catch {wpGetVar fcachel}]} { + if {$fcachel <= $_wp(fldr_cache_max)} { + catch {WPSessionState left_column_folders $fcachel} + } + } + } + signature { + wpGetVar signature + set cursig [string trimright [join [WPCmd PEConfig rawsig] "\n"]] + set signature [string trimright $signature] + if {[string compare $cursig $signature]} { + WPCmd PEConfig rawsig [split $signature "\n"] + } + } + filters { + wpGetVarAs $varname-sz sz + wpGetVarAs vla.$varname.x fltadd + wpGetVarAs hlp.$varname.x do_help + if {[string length $do_help]} { + set subop varhelp + set varhelpname filtconf + } elseif {[string length $fltadd]} { + set script "fr_filtedit.tcl" + set filtedit_add 1 + set filtedit_onfiltcancel conf_process + } else { + if {[string length $sz] == 0} { + error [list _action "ERROR" "No size given for filters"] + } + for {set i 0} {$i < $sz} {incr i} { + wpGetVarAs vle.$varname.$i.x vle + wpGetVarAs vld.$varname.$i.x vld + wpGetVarAs vlsu.$varname.$i.x vlsu + wpGetVarAs vlsd.$varname.$i.x vlsd + set flt_ret 0 + set flt_res "" + if {[string length $vle]} { + set script "fr_filtedit.tcl" + set filtedit_fno $i + set filtedit_onfiltcancel conf_process + } elseif {[string length $vld]} { + set flt_ret [catch {WPCmd PEConfig ruleset filter delete $i} flt_res] + } elseif {[string length $vlsu]} { + set flt_ret [catch {WPCmd PEConfig ruleset filter shuffup $i} flt_res] + } elseif {[string length $vlsd]} { + set flt_ret [catch {WPCmd PEConfig ruleset filter shuffdown $i} flt_res] + } + if {$flt_ret} { + # error + } elseif {[string length $flt_res]} { + # something wrong here + } + } + } + } + scores { + wpGetVarAs $varname-sz sz + wpGetVarAs vla.$varname.x fltadd + wpGetVarAs hlp.$varname.x do_help + if {[string length $do_help]} { + set subop varhelp + set varhelpname filtconf + } elseif {[string length $fltadd]} { + set script "fr_filtedit.tcl" + set filtedit_add 1 + set filtedit_score 1 + set filtedit_onfiltcancel conf_process + } else { + if {[string length $sz] == 0} { + error [list _action "ERROR" "No size given for scores"] + } + for {set i 0} {$i < $sz} {incr i} { + wpGetVarAs vle.$varname.$i.x vle + wpGetVarAs vld.$varname.$i.x vld + wpGetVarAs vlsu.$varname.$i.x vlsu + wpGetVarAs vlsd.$varname.$i.x vlsd + set flt_ret 0 + set flt_res "" + if {[string length $vle]} { + set script "fr_filtedit.tcl" + set filtedit_score 1 + set filtedit_fno $i + set filtedit_onfiltcancel conf_process + } elseif {[string length $vld]} { + set flt_ret [catch {WPCmd PEConfig ruleset score delete $i} flt_res] + } elseif {[string length $vlsu]} { + set flt_ret [catch {WPCmd PEConfig ruleset score shuffup $i} flt_res] + } elseif {[string length $vlsd]} { + set flt_ret [catch {WPCmd PEConfig ruleset score shuffdown $i} flt_res] + } + if {$flt_ret} { + # error + } elseif {[string length $flt_res]} { + # something wrong here + } + } + } + } + indexcolor { + wpGetVarAs $varname-sz sz + wpGetVarAs vla.$varname.x fltadd + wpGetVarAs hlp.$varname.x do_help + if {[string length $do_help]} { + set subop varhelp + set varhelpname filtconf + } elseif {[string length $fltadd]} { + set script "fr_filtedit.tcl" + set filtedit_add 1 + set filtedit_indexcolor 1 + set filtedit_onfiltcancel conf_process + } else { + if {[string length $sz] == 0} { + error [list _action "ERROR" "No size given for index colors"] + } + for {set i 0} {$i < $sz} {incr i} { + wpGetVarAs vle.$varname.$i.x vle + wpGetVarAs vld.$varname.$i.x vld + wpGetVarAs vlsu.$varname.$i.x vlsu + wpGetVarAs vlsd.$varname.$i.x vlsd + set flt_ret 0 + set flt_res "" + if {[string length $vle]} { + set script "fr_filtedit.tcl" + set filtedit_indexcolor 1 + set filtedit_fno $i + set filtedit_onfiltcancel conf_process + } elseif {[string length $vld]} { + set flt_ret [catch {WPCmd PEConfig ruleset indexcolor delete $i} flt_res] + } elseif {[string length $vlsu]} { + set flt_ret [catch {WPCmd PEConfig ruleset indexcolor shuffup $i} flt_res] + } elseif {[string length $vlsd]} { + set flt_ret [catch {WPCmd PEConfig ruleset indexcolor shuffdown $i} flt_res] + } + if {$flt_ret} { + # error + } elseif {[string length $flt_res]} { + # something wrong here + } + } + } + } + collections { + wpGetVarAs $varname-sz sz + wpGetVarAs vla.$varname.x cladd + if {[string length $cladd]} { + set script "fr_cledit.tcl" + set cledit_add 1 + set cledit_onclecancel conf_process + } else { + if {[string length $sz] == 0} { + error [list _action "ERROR" "No size given for collections"] + } + for {set i 0} {$i < $sz} {incr i} { + wpGetVarAs vle.$varname.$i.x vle + wpGetVarAs vld.$varname.$i.x vld + wpGetVarAs vlsu.$varname.$i.x vlsu + wpGetVarAs vlsd.$varname.$i.x vlsd + set cle_ret 0 + set cle_res "" + if {[string length $vle]} { + set script "fr_cledit.tcl" + set cledit_cl $i + set cledit_onclecancel conf_process + } elseif {[string length $vld]} { + set cle_ret [catch {WPCmd PEConfig cldel $i} cle_res] + } elseif {[string length $vlsu]} { + set cle_ret [catch {WPCmd PEConfig clshuff up $i} cle_res] + } elseif {[string length $vlsd]} { + set cle_ret [catch {WPCmd PEConfig clshuff down $i} cle_res] + } + if {$cle_ret} { + # error + } elseif {[string length $cle_res]} { + WPCmd PEInfo statmsg $cle_res + # something wrong here + } + } + } + } + index-format { + wpGetVarAs index-format iformat + + set varchanged 0 + + if {$hlpthisvar} { + set subop varhelp + set varhelpname index-format + } elseif {[catch {cgi_import hlp.index_tokens.x} result] == 0} { + set subop secthelp + set topicclass plain + set feathelpname h_index_tokens + set varhelpname h_index_tokens + } + + if {[catch {cgi_import indexadd}] == 0 + && [string compare "Add Field" $indexadd] == 0 + && [catch {cgi_import indexaddfield}] == 0} { + if {[lsearch $iformat $indexaddfield] < 0} { + set iformat [linsert $iformat 0 $indexaddfield] + set varchanged 1 + } + } elseif {[catch {cgi_import adjust}] == 0 + && [string compare Change $adjust] == 0 + && [catch {cgi_import iop}] == 0 + && [catch {cgi_import ifield}] == 0 + && [set pos [fieldPos $iformat $ifield]] >= 0} { + switch $iop { + left { + set iformat [lreplace $iformat $pos $pos] + set iformat [linsert $iformat [incr pos -1] $ifield] + set varchanged 1 + } + right { + set iformat [lreplace $iformat $pos $pos] + set iformat [linsert $iformat [incr pos] $ifield] + set varchanged 1 + } + widen { + set f [lindex [lindex $iformat $pos] 0] + set w [lindex [lindex $iformat $pos] 1] + set dw [expr {round((100/[llength $iformat]) * [WPTFIndexWidthRatio $iformat $f])}] + + if {[regexp {([0123456789]+)[%]} $w dummy w] == 0} { + set w $dw + } + + if {$w < 95} { + incr w 5 + } else { + set w 99 + } + + if {$w == $dw} { + set ws "" + } else { + set ws "${w}%" + } + + set iformat [lreplace $iformat $pos $pos [list $f $ws]] + set varchanged 1 + } + narrow { + set f [lindex [lindex $iformat $pos] 0] + set w [lindex [lindex $iformat $pos] 1] + set dw [expr {round((100/[llength $iformat]) * [WPTFIndexWidthRatio $iformat $f])}] + + if {[regexp {([0123456789]+)[%]} $w dummy w] == 0} { + set w $dw + } + + if {$w > 5} { + incr w -5 + } else { + set w 1 + } + + if {$w == $dw} { + set ws "" + } else { + set ws "${w}%" + } + + set iformat [lreplace $iformat $pos $pos [list $f $ws]] + set varchanged 1 + } + remove { + set iformat [lreplace $iformat $pos $pos] + set varchanged 1 + } + } + } else { + foreach f $iformat { + if {[catch {cgi_import_as shrm.${f}.x shift} result] == 0} { + if {[set pos [fieldPos $iformat $f]] >= 0} { + set iformat [lreplace $iformat $pos $pos] + set varchanged 1 + } + } elseif {[catch {cgi_import_as shlf.${f}.x shift} result] == 0} { + if {[set pos [fieldPos $iformat $f]] > 0} { + set iformat [lreplace $iformat $pos $pos] + set iformat [linsert $iformat [incr pos -1] $f] + set varchanged 1 + } + } elseif {[catch {cgi_import_as shrt.${f}.x shift} result] == 0} { + if {[set pos [fieldPos $iformat $f]] >= 0} { + set iformat [lreplace $iformat $pos $pos] + set iformat [linsert $iformat [incr pos] $f] + set varchanged 1 + } + } + } + } + + if {$varchanged} { + foreach f $iformat { + if {[string length [lindex $f 1]]} { + lappend ifv "[lindex $f 0]([lindex $f 1])" + } else { + lappend ifv [lindex $f 0] + } + } + + WPCmd PEConfig varset index-format [list $ifv] + } + } + view-colors { + if {$hlpthisvar} { + set subop varhelp + set varhelpname index-format + } elseif {[catch {cgi_import_as colormap.x colx}] == 0 + && [catch {cgi_import_as colormap.y coly}] == 0} { + set rgbs {"000" "051" "102" "153" "204" "255"} + set xrgbs {"00" "33" "66" "99" "CC" "FF"} + set rgblen [llength $rgbs] + set imappixwidth 10 + + set colx [expr {${colx} / $imappixwidth}] + set coly [expr {${coly} / $imappixwidth}] + if {($coly >= 0 && $coly < $rgblen) + && ($colx >= 0 && $colx < [expr {$rgblen * $rgblen}])} { + set ired $coly + set igreen [expr {($colx / $rgblen) % $rgblen}] + set iblue [expr {$colx % $rgblen}] + set rgb "[lindex $rgbs $ired],[lindex $rgbs ${igreen}],[lindex $rgbs ${iblue}]" + set xrgb "[lindex $xrgbs $ired][lindex $xrgbs ${igreen}][lindex $xrgbs ${iblue}]" + + if {[catch {cgi_import_as text tt}] == 0} { + set type [split $tt .] + catch {WPCmd set config_deftext [lindex $type end]} + + if {[catch {cgi_import_as ground ground}] == 0} { + switch $ground { + f { + catch {WPCmd set config_defground f} + set fg $xrgb + } + b { + catch {WPCmd set config_defground b} + set bg $xrgb + } + } + + if {[info exists fg] || [info exists bg]} { + switch [lindex $type 0] { + hdr { + set type [lindex $type 1] + if {[catch {cgi_import_as add.${type} foo}] == 0} { + set colop add + } elseif {[catch {cgi_import_as hi.${type} hindex}] == 0} { + set colop change + } + + if {[info exists colop]} { + if {![info exists bg] && [catch {cgi_import_as dbg.$type bg} result]} { + WPCmd PEInfo statmsg "Can't import default background: $result" + } elseif {![info exists fg] && [catch {cgi_import_as dfg.$type fg} result]} { + WPCmd PEInfo statmsg "Can't import default foreground: $result" + } + + switch $colop { + change { + if {[catch {WPCmd PEConfig colorset viewer-hdr-colors update [list $hindex $type ""] [list $fg $bg]} result]} { + WPCmd PEInfo statmsg "Problem changing $type color: $result" + } + } + add { + if {[catch {WPCmd PEConfig colorset viewer-hdr-colors add [list $type ""] [list $fg $bg]} result]} { + WPCmd PEInfo statmsg "Problem adding $type color: $result" + } + } + } + + } + } + default { + if {![info exists bg] && [catch {cgi_import_as dbg.$type bg} result]} { + WPCmd PEInfo statmsg "Can't import default background: $result" + } elseif {![info exists fg] && [catch {cgi_import_as dfg.$type fg} result]} { + WPCmd PEInfo statmsg "Can't import default foreground: $result" + } elseif {[catch {WPCmd PEConfig colorset $type [list $fg $bg]} result]} { + WPCmd PEInfo statmsg "Can't set $type color: $result" + } + } + } + } else { + WPCmd PEInfo statmsg "Invalid fore/back ground input!" + } + } else { + WPCmd PEInfo statmsg "Choose foreground or background!" + } + } else { + WPCmd PEInfo statmsg "Choose the type of text to color!" + } + } else { + WPCmd PEInfo statmsg "Invalid RGB Input!" + } + } elseif {[catch {cgi_import addfield}] == 0 + && [string compare "add " [string tolower [string range $addfield 0 3]]] == 0 + && [catch {cgi_import newfield}] == 0 + && [string length [set newfield [string trim $newfield]]] + && [catch {cgi_import_as dfg.normal dfg}] == 0 + && [catch {cgi_import_as dbg.normal dbg}] == 0} { + if {[catch {WPCmd PEConfig colorset viewer-hdr-colors add [list $newfield ""] [list $dfg $dbg]} result]} { + WPCmd PEInfo statmsg "Problem adding $type color: $result" + } + } elseif {[catch {cgi_import reset}] == 0 + && [string compare "restore " [string tolower [string range $reset 0 7]]] == 0} { + if {[catch {cgi_import_as text tt}] == 0} { + if {[llength [set type [split $tt .]]] == 2 && [string compare [lindex $type 0] hdr] == 0} { + set hdr [lindex $type end] + if {[catch {cgi_import_as hi.$hdr hindex}] == 0} { + if {[catch {WPCmd PEConfig colorset viewer-hdr-colors delete $hindex} result]} { + # bug: reloads cause this error - need better way to report it + #WPCmd PEInfo statmsg "Can't reset $hdr ($hindex) text: $result!" + } else { + catch {WPCmd PEInfo unset config_deftext} + } + } + } elseif {[string compare normal $tt] == 0} { + if {[catch {WPCmd PEConfig varset normal-foreground-color ""} result] + || [catch {WPCmd PEConfig varset normal-background-color ""} result]} { + WPCmd PEInfo statmsg "Can't reset normal text: $result!" + } + } elseif {[catch {cgi_import_as dfg.normal dfg}] == 0 + && [catch {cgi_import_as dbg.normal dbg}] == 0} { + catch {WPCmd set config_deftext $tt} + if {[catch {WPCmd PEConfig colorset $tt [list $dfg $dbg]} result]} { + WPCmd PEInfo statmsg "Can't reset $tt text: $result!" + } + } + } else { + WPCmd PEInfo statmsg "Choose the type of text to color!" + } + } + } + } + } + var { + wpGetVarAs $varname formval + set varvals [WPCmd PEConfig varget $varname] + set vals [lindex $varvals 0] + set vartype [lindex $varvals 1] + set formvals [split $formval "\n"] + set varchanged 0 + + if {$hlpthisvar} { + set subop varhelp + set varhelpname $varname + } + + if {[string compare $vartype textarea] == 0} { + wpGetVarAs vla.$varname.x vlavar + wpGetVarAs $varname-sz sz + wpGetVarAs $varname-add valadd + if {[string length $vlavar]} { + set fr_tconfig_vlavar $varname + } + set formvals {} + if {[string length $valadd]} { + lappend formvals $valadd + } + if {[string length $sz]} { + set prevwassd 0 + for {set i 0} {$i < $sz} {incr i} { + wpGetVarAs vle.$varname.$i fval + wpGetVarAs vld.$varname.$i.x fvaldel + wpGetVarAs vlsu.$varname.$i.x fvalsu + wpGetVarAs vlsd.$varname.$i.x fvalsd + set fed 0 + set fdel 0 + set fsu 0 + set fsd 0 + if {[string length $fval]} { + set fed 1 + } + if {[string length $fvaldel]} { + set fdel 1 + } elseif {[string length $fvalsu]} { + set fsu 1 + } elseif {[string length $fvalsd]} { + set fsd 1 + } + if {$fed && $fdel == 0 && $prevwassd} { + set prevwassd 0 + set formvals [linsert $formvals [expr {[llength $formvals] - 1}] $fval] + } elseif {$fed && $fdel == 0 && $fsu == 0} { + lappend formvals $fval + if {$fsd} { + set prevwassd 1 + } + } elseif {$fed && $fdel == 0 && $fsu} { + set fvallen [llength $formvals] + if {$fvallen} { + set formvals [linsert $formvals [expr {$fvallen - 2}] $fval] + } else { + lappend formvals $fval + } + } + } + } + set len [llength $formvals] + if {$len != [llength $vals]} { + set varchanged 1 + } else { + for {set i 0} {$i < $len} {incr i} { + if {[string compare [lindex $formvals $i] [lindex $vals $i]]} { + set varchanged 1 + break + } + } + } + } elseif {[llength $formvals] != [llength $vals]} { + set varchanged 1 + } else { + set valslength [llength $vals] + for {set i 0} {$i < $valslength} {incr i} { + if {[string compare [lindex $vals $i] [lindex $formvals $i]]} { + set varchanged 1 + break + } + } + } + if {$varchanged} { + WPCmd PEConfig varset $varname $formvals + } + # what about wp-indexheight? + } + feat { + wpGetVarAs $varname tval + if {$hlpthisvar} { + set subop feathelp + set feathelpname $varname + } + set featset [expr {[lsearch $setfeatures $varname] >= 0}] + set formfeatset [expr {[string compare $tval on] == 0}] + if {$formfeatset != $featset} { + WPCmd PEConfig feature $varname $formfeatset + } + } + } + } + if {[info exists subop]} { + switch -- $subop { + varhelp { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + set help_vars [list topic topicclass] + set topic $varhelpname + set _cgi_uservar(topic) $varhelpname + set topicclass variable + set _cgi_uservar(topicclass) variable + set _cgi_uservar(oncancel) conf_process + set script help + } + feathelp { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + set help_vars [list topic topicclass oncancel] + set topic $feathelpname + set _cgi_uservar(topic) $feathelpname + set topicclass feature + set _cgi_uservar(topicclass) feature + set _cgi_uservar(oncancel) conf_process + set script help + } + secthelp { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + set help_vars [list topic topicclass oncancel] + set topic $feathelpname + set _cgi_uservar(topic) $feathelpname + set topicclass $topicclass + set _cgi_uservar(topicclass) $topicclass + set _cgi_uservar(oncancel) conf_process + set script help + } + save { + if {$cid != [WPCmd PEInfo key]} { + error [list _close "Invalid Operation ID"] + } + WPCmd PEConfig saveconf + set script $oncancel + catch {WPCmd PEInfo unset config_deftext} + } + } + } + } + filtconfig { + wpGetVar fno [list _INTEGER_] + wpGetVar subop [list edit add] + + if {[catch {wpGetVar filtcancel}]} { + if {[catch {wpGetVar filthelp}] == 0} { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + + set patlist [wpGetRulePattern] + set actlist [wpGetRuleAction 0] + # we have to save this exactly as it would look when getting it from alpined + set ftsadd [expr {[string compare $subop "add"] == 0 ? 1 : 0}] + set ftsform [list [list "pattern" $patlist] [list "filtaction" $actlist]] + catch {WPCmd set filttmpstate [list $ftsadd $fno $ftsform]} + + set help_vars [list topic] + set topic filtedit + set _cgi_uservar(topic) filtedit + + if {[string compare $subop "edit"] == 0} { + set fakeimg "vle.filters.$fno" + set fakesz [expr {$fno + 1}] + } else { + set fakeimg "vla.filters" + set fakesz 1 + } + + set _cgi_uservar(oncancel) [WPPercentQuote "conf_process&wv=rule&filters-sz=${fakesz}&${fakeimg}.x=1&${fakeimg}.y=1&oncancel=main.tcl"] + set script help + } elseif {[set nv [numberedVar rmheader header_total]] >= 0} { + + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + + if {[string compare headers [lindex $pat 0]] == 0} { + if {[llength $headers] > $nv} { + set headers [lreplace $headers $nv $nv] + } + } + } + + # load all the actions + foreach act [wpGetRuleAction 0] { + set [lindex $act 0] [lindex $act 1] + } + + # load other variables + wpGetVarAs nickname nickname + wpGetVarAs comment comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } elseif {[catch {wpGetVar addheader}] == 0} { + + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + if {[string compare headers [lindex $pat 0]] == 0} { + foreach h [set headers [lindex $pat 1]] { + if {0 == [string length [lindex $h 0]] + && 0 == [string length [lindex $h 1]]} { + set emptyheader 1 + } + } + + if {![info exists emptyheader]} { + lappend headers [list {} {}] + } + } + } + + # load all the actions + foreach act [wpGetRuleAction 0] { + set [lindex $act 0] [lindex $act 1] + } + + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } else { + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set patlist [wpGetRulePattern] + set actlist [wpGetRuleAction 1] + + lappend patlist [list nickname $nickname] + lappend patlist [list comment $comment] + + set ret [catch {WPCmd PEConfig ruleset filter $subop $fno $patlist $actlist} res] + if {$ret} { + error [list _action "Filter Set" $res] + } elseif {[string length $res]} { + WPCmd PEInfo statmsg "Filter setting failed: $res" + + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } + } + } + } + scoreconfig { + wpGetVar fno [list _INTEGER_] + wpGetVar subop [list edit add] + + if {[catch {wpGetVar filtcancel}]} { + if {[catch {wpGetVar filthelp}] == 0} { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + if {[string compare $subop "edit"] == 0 || [string compare $subop "add"] == 0} { + set patlist [wpGetRulePattern] + + # we have to save this exactly as it would look when getting it from alpined + set ftsadd [expr {[string compare $subop "add"] == 0 ? 1 : 0}] + set ftsform [list [list "pattern" $patlist] [list "filtaction" $actlist]] + catch {WPCmd set filttmpstate [list $ftsadd $fno $ftsform]} + } + set help_vars [list topic] + set topic scoreedit + set _cgi_uservar(topic) scoreedit + switch -- $subop { + edit { + set fakeimg "vle.scores.$fno" + set fakesz [expr {$fno + 1}] + } + add { + set fakeimg "vla.scores" + set fakesz 1 + } + } + + set _cgi_uservar(oncancel) [WPPercentQuote "conf_process&wv=rule&scores-sz=${fakesz}&${fakeimg}.x=1&${fakeimg}.y=1&oncancel=main.tcl"] + set script help + } elseif {[set nv [numberedVar rmheader header_total]] >= 0} { + + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + + if {[string compare headers [lindex $pat 0]] == 0} { + if {[llength $headers] > $nv} { + set headers [lreplace $headers $nv $nv] + } + } + } + + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_score 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } elseif {[catch {wpGetVar addheader}] == 0} { + + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + if {[string compare headers [lindex $pat 0]] == 0} { + foreach h [set headers [lindex $pat 1]] { + if {0 == [string length [lindex $h 0]] + && 0 == [string length [lindex $h 1]]} { + set emptyheader 1 + } + } + + if {![info exists emptyheader]} { + lappend headers [list {} {}] + } + } + } + + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_score 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } else { + switch -- $subop { + edit - + add { + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set patlist [wpGetRulePattern] + + lappend patlist [list nickname $nickname] + lappend patlist [list comment $comment] + + wpGetVar scoreval + lappend actlist [list "scoreval" $scoreval] + + wpGetVar scorehdr + lappend actlist [list "scorehdr" $scorehdr] + + set ret [catch {WPCmd PEConfig ruleset score $subop $fno $patlist $actlist} res] + + if {$ret} { + error [list _action "Score Set" $res] + } elseif {[string length $res]} { + WPCmd PEInfo statmsg "Score setting failed: $res" + + set filtedit_score 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } + } + } + } + } + } + indexcolorconfig { + wpGetVar fno [list _INTEGER_] + wpGetVar subop [list edit add] + + if {[catch {wpGetVar filtcancel}]} { + if {[catch {wpGetVar filthelp}] == 0} { + catch {WPCmd PEInfo unset help_context} + catch {WPCmd set oncancel $oncancel} + if {[string compare $subop "edit"] == 0 || [string compare $subop "add"] == 0} { + set patlist [wpGetRulePattern] + + # we have to save this exactly as it would look when getting it from alpined + set ftsadd [expr {[string compare $subop "add"] == 0 ? 1 : 0}] + set ftsform [list [list "pattern" $patlist] [list "filtaction" $actlist]] + catch {WPCmd set filttmpstate [list $ftsadd $fno $ftsform]} + } + set help_vars [list topic] + set topic indexcoloredit + set _cgi_uservar(topic) indexcoloredit + switch -- $subop { + edit { + set fakeimg "vle.indexcolor.$fno" + set fakesz [expr {$fno + 1}] + } + add { + set fakeimg "vla.indexcolor" + set fakesz 1 + } + } + + set _cgi_uservar(oncancel) [WPPercentQuote "conf_process&wv=rule&indexcolor-sz=${fakesz}&${fakeimg}.x=1&${fakeimg}.y=1&oncancel=main.tcl"] + set script help + } elseif {[set nv [numberedVar rmheader header_total]] >= 0} { + + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + + if {[string compare headers [lindex $pat 0]] == 0} { + if {[llength $headers] > $nv} { + set headers [lreplace $headers $nv $nv] + } + } + } + + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_indexcolor 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } elseif {[catch {wpGetVar addheader}] == 0} { + # load all the rules, process "headers" + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + if {[string compare headers [lindex $pat 0]] == 0} { + foreach h [set headers [lindex $pat 1]] { + if {0 == [string length [lindex $h 0]] + && 0 == [string length [lindex $h 1]]} { + set emptyheader 1 + } + } + + if {![info exists emptyheader]} { + lappend headers [list {} {}] + } + } + } + + # load other variables + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + + set filterrtext 1 + set filtedit_indexcolor 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } elseif {[catch {cgi_import_as colormap.x colx}] == 0 + && [catch {cgi_import_as colormap.y coly}] == 0} { + set rgbs {"000" "051" "102" "153" "204" "255"} + set xrgbs {"00" "33" "66" "99" "CC" "FF"} + set rgblen [llength $rgbs] + set imappixwidth 10 + + set colx [expr {${colx} / $imappixwidth}] + set coly [expr {${coly} / $imappixwidth}] + if {($coly >= 0 && $coly < $rgblen) + && ($colx >= 0 && $colx < [expr {$rgblen * $rgblen}])} { + set ired $coly + set igreen [expr {($colx / $rgblen) % $rgblen}] + set iblue [expr {$colx % $rgblen}] + set rgb "[lindex $rgbs $ired],[lindex $rgbs ${igreen}],[lindex $rgbs ${iblue}]" + set xrgb "[lindex $xrgbs $ired][lindex $xrgbs ${igreen}][lindex $xrgbs ${iblue}]" + + if {[catch {wpGetVar fgorbg [list fg bg]}]} { + WPCmd PEInfo statmsg "Invalid fore/back ground input!" + catch {unset xrgb} + } + } else { + WPCmd PEInfo statmsg "Invalid RGB Input!" + } + + # relay any other config changes + wpGetVar nickname + wpGetVar comment + wpGetVarAs folder folder + wpGetVarAs ftype ftype + foreach pat [wpGetRulePattern] { + set [lindex $pat 0] [lindex $pat 1] + } + + # import previous settings + wpGetVarAs fg fg + wpGetVarAs bg bg + + # set new value + if {[info exists xrgb]} { + set $fgorbg $xrgb + } + + set filterrtext 1 + set filtedit_indexcolor 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } else { + switch -- $subop { + edit - + add { + + wpGetVar nickname + wpGetVar comment + + set patlist [wpGetRulePattern] + + lappend patlist [list nickname $nickname] + lappend patlist [list comment $comment] + + # save config? + set actlist {} + if {[catch {wpGetVar fg}] == 0 && [catch {wpGetVar bg}] == 0} { + lappend actlist [list fg $fg] + lappend actlist [list bg $bg] + + # save rule + set ret [catch {WPCmd PEConfig ruleset indexcolor $subop $fno $patlist $actlist} res] + if {$ret} { + error [list _action "Color Set Error" $res] + } elseif {[string length $res]} { + WPCmd PEInfo statmsg "Index Color setting failed: $res" + + set filtedit_indexcolor 1 + set filtedit_fno $fno + set filtedit_add [expr {[string compare $subop add] == 0 ? 1 : 0}] + set filtedit_onfiltcancel conf_process + set script "fr_filtedit.tcl" + } + } else { + error [list _action "Unset FG/BG" "Internal Error: Unset Color Variables"] + } + } + } + } + } + } + clconfig { + wpGetVar cl + wpGetVar nick + wpGetVar server + wpGetVar user + wpGetVar stype + wpGetVar path + wpGetVar view + wpGetVar add + wpGetVarAs cle_cancel.x cle_cancel + wpGetVarAs cle_save.x cle_save + + set cledit_add $add + set cledit_cl $cl + set cledit_onclecancel conf_process + if {[string length $cle_save]} { + if {[catch {cgi_import_as "ssl" sslval}]} { + set ssl 0 + } else { + if {[string compare $sslval on] == 0} { + set ssl 1 + } else { + set ssl 0 + } + } + regexp "\{?(\[^\}\]*)\}?(.*)" $server match serverb serverrem + if {[string length $serverb]} { + if {$ssl == 1} { + set serverb "$serverb/ssl" + } + if {[string compare "" "$user"]} { + set serverb "$serverb/user=$user" + } + if {[string compare "imap" [string tolower $stype]]} { + set serverb "$serverb/[string tolower $stype]" + } + if {[string compare "nntp" [string tolower $stype]] == 0} { + regsub -nocase {^(#news\.)?(.*)$} "$path" "#news.\\2" path + if {[string compare "" $path] == 0} { + set path "#news." + } + } + set result "" + set ret 0 + set servera "\{$serverb\}$serverrem" + if {$add} { + set ret [catch {WPCmd PEConfig cladd $cl $nick $servera $path $view} result] + } else { + set ret [catch {WPCmd PEConfig cledit $cl $nick $servera $path $view} result] + } + if {$ret != 0} { + error [list _action "Collection List Set" $result] + } elseif {[string compare "" $result]} { + if {$add} { + set clerrtext "Add failed: $result" + } else { + set clerrtext "Edit failed: $result" + } + WPCmd PEInfo statmsg $clerrtext + set script "fr_cledit.tcl" + } + } else { + set clerrtext "Bad data: Nothing defined for Server" + WPCmd PEInfo statmsg $clerrtext + set script "fr_cledit.tcl" + } + } + } + noop { + catch {WPCmd PEInfo noop} + } + cancel { + set script $oncancel + catch {WPCmd unset conf_page} res + } + default { + error [list _close "Unknown process operation: $op"] + } + } + +source [WPTFScript $script] diff --git a/web/cgi/alpine/1.0/detach.tcl b/web/cgi/alpine/1.0/detach.tcl new file mode 100755 index 00000000..d53ef313 --- /dev/null +++ b/web/cgi/alpine/1.0/detach.tcl @@ -0,0 +1,183 @@ +#!./tclsh +# $Id: detach.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006-2007 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# detach.tcl +# +# Purpose: CGI script to retrieve requested attachment +# +# Input: +set detach_vars { + {uid "Unknown Message UID"} + {part "Unknown Message Part"} + {download "" 0} +} + +#set detach_via_ip_address 1 +#set detach_via_local_hostname 1 + +# inherit global config +source ./alpine.tcl + +proc WPServerIP {} { + global _wp + + catch { + set ip 127.0.0.1 + set sid [socket -async [info hostname] [expr {([string length $_wp(serverport)]) ? $_wp(serverport) : 80}]] + set ip [lindex [ fconfigure $sid -sockname ] 0] + close $sid + } + + return $ip +} + +WPEval $detach_vars { + if {[info exists env(PATH_INFO)]} { + if {[string index $env(PATH_INFO) 0] == "/"} { + set s [string range $env(PATH_INFO) 1 end] + if {[set i [string first "/" $s]] >= 0} { + set uid [string range $s 0 [expr {$i - 1}]] + set s [string range $s [incr i] end] + if {[set i [string first "/" $s]] >= 0} { + set part [string range $s 0 [expr {$i - 1}]] + } + } + } + } + + if {[info exists uid] == 0 || [info exists part] == 0} { + error [list _action "Unspecified attachment UID or Part" "Please close this window."] + } + + # generate big random string to reference the thing + + # generate filenames to hold detached data and control file + for {set n 0} {1} {incr n} { + + set rhandle [WPCmd PESession random 64] + set cfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-control] + set dfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-data] + + if {[file exists $cfile] == 0 && [file exists $dfile] == 0} { + if {[catch {open $cfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} cfd]} { + error [list _action Detach "Cannot create control file: [cgi_quote_html $cfd]" "Please close this window"] + } else { + exec echo ${rhandle}-control | [file join $_wp(cgipath) $_wp(appdir) whackatch.tcl] >& /dev/null & + } + + if {[catch {open $dfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} dfd]} { + catch {close $cfd} + error [list _action Detach "Cannot create command file: [cgi_quote_html $dfd]" "Please close this window"] + } else { + exec echo ${rhandle}-data | [file join $_wp(cgipath) $_wp(appdir) whackatch.tcl] >& /dev/null & + } + + # exec chmod [cgi_tmpfile_permissions] $cfile + # exec chmod [cgi_tmpfile_permissions] $dfile + break + } elseif {$n > 4} { + error [list _action Detach "Command file creation limit" "Please close this window"] + } + } + + if {[catch {WPCmd PEMessage $uid detach $part $dfile} attachdata]} { + error [list _action Detach $attachdata "Please close this window"] + } + + if {[info exists detach_via_ip_address]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[WPServerIP]\]\\2" redirect] != 1} { + error [list _action Detach "Cannot determine server address" "Please close this window"] + } + } elseif {[info exists detach_via_local_hostname]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[info hostname]\]\\2" redirect] != 1} { + error [list _action Detach "Cannot determine server address" "Please close this window"] + } + } else { + set redirect "[cgi_root]/pub/getach.tcl" + } + + set mimetype [lindex $attachdata 0] + set mimesubtype [lindex $attachdata 1] + set contentlength [lindex $attachdata 2] + set givenname [lindex [lindex $attachdata 3] 0] + set tmpfile [lindex $attachdata 4] + + if {[string compare $tmpfile $dfile]} { + set straytmp "&straytmp=1" + } else { + set straytmp "" + } + + if {![string length $givenname]} { + set givenname "attachment" + switch -regexp $mimetype { + ^[Tt][Ee][Xx][Tt]$ { + switch -regexp $mimesubtype { + ^[Pp][Ll][Aa][Ii][Nn]$ { + set givenname "attached.txt" + } + ^[Hh][Tt][Mm][Ll]$ { + set givenname "attached.html" + } + } + } + } + } + + set safegivenname $givenname + regsub -all {[/]} $safegivenname {-} safegivenname + regsub -all {[ ]} $safegivenname {_} safegivenname + regsub -all {[\?]} $safegivenname {X} safegivenname + regsub -all {[&]} $safegivenname {X} safegivenname + regsub -all {[#]} $safegivenname {X} safegivenname + regsub -all {[=]} $safegivenname {X} safegivenname + set safegivenname "/[WPPercentQuote $safegivenname {.}]" + + if {$download == 1} { + puts $cfd "Content-type: Application/X-Download" + puts $cfd "Content-Disposition: attachment; filename=\"$givenname\"" + } else { + puts $cfd "Content-type: ${mimetype}/${mimesubtype}" + } + + # side-step the cgi_xxx stuff in this special case because + # we don't want to buffer up the downloading attachment... + + puts $cfd "Content-Length: $contentlength" + puts $cfd "Expires: [clock format [expr {[clock seconds] + 3600}] -f {%a, %d %b %Y %H:%M:%S GMT} -gmt true]" + puts $cfd "Cache-Control: max-age=3600" + puts $cfd "" + + puts $cfd $tmpfile + + # exec chmod [cgi_tmpfile_permissions] $tmpfile + + close $cfd + + # prepare to clean up if the brower never redirects + + cgi_http_head { + # redirect to the place we stuffed the detach info. use the ip address + # to foil spilling any session cookies or the like + #cgi_redirect ${redirect}${safegivenname}?h=${rhandle} + + if {[info exists env(SERVER_PROTOCOL)] && [regexp {[Hh][Tt][Tt][PP]/([0-9]+)\.([0-9]+)} $env(SERVER_PROTOCOL) m vmaj vmin] && $vmaj >= 1 && $vmin >= 1} { + cgi_puts "Status: 303 Temporary Redirect" + } else { + cgi_puts "Status: 302 Redirected" + } + + cgi_puts "URI: ${redirect}${safegivenname}?h=${rhandle}${straytmp}" + cgi_puts "Location: ${redirect}${safegivenname}?h=${rhandle}${straytmp}" + } +} diff --git a/web/cgi/alpine/1.0/do_help.tcl b/web/cgi/alpine/1.0/do_help.tcl new file mode 100644 index 00000000..400b3af2 --- /dev/null +++ b/web/cgi/alpine/1.0/do_help.tcl @@ -0,0 +1,48 @@ +# $Id: do_help.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + if {![string length $topic]} { + if {[catch {WPCmd PEInfo set help_context} s] == 0} { + set topic $s + catch {WPCmd PEInfo unset help_context} + } + } + + cgi_head { + cgi_title "Alpine Help" + } + + cgi_frameset "cols=112,*" frameborder=0 framespacing=0 border=0 { + set parms "" + + foreach v $help_vars { + set val [subst $[lindex $v 0]] + if {[string length $val]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=$val" + } + } + + cgi_frame bodindx=helpindex.tcl$parms title="Help Navigation" + cgi_frame bodtext=helpbody.tcl$parms title="Help Text" + } +} diff --git a/web/cgi/alpine/1.0/do_open.tcl b/web/cgi/alpine/1.0/do_open.tcl new file mode 100755 index 00000000..22599a97 --- /dev/null +++ b/web/cgi/alpine/1.0/do_open.tcl @@ -0,0 +1,126 @@ +# $Id: do_open.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +if {$cid != [WPCmd PEInfo key]} { + error [list _action open "Invalid Operation ID" "Click Back button to try again."] +} + +if {[catch {WPLoadCGIVar cancel}] == 0 && [string compare Cancel $cancel] == 0} { + catch {WPCmd PEInfo statmsg "Authentication Cancelled"} + cgi_http_head { + cgi_redirect [cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=${oncancel}.tcl + } +} else { + + if {[catch {WPLoadCGIVar path}]} { + WPLoadCGIVar colid + WPLoadCGIVar folder + set path [list $colid $folder] + } else { + set colid [lindex $path 0] + set folder [lrange $path 1 end] + } + + if {[info exists src] == 0 && [catch {eval WPCmd PEMailbox open $path} reason]} { + if {[string first ": no such folder" $reason] > 0} { + catch {WPCmd PEInfo statmsg "Folder [lrange $path 1 end] doesn't exist"} + set src $oncancel + } elseif {[string compare BADPASSWD [string range $reason 0 8]] == 0 || [string compare $reason "Login Error"] == 0} { + # control error messages + set statmsgs [WPCmd PEInfo statmsgs] + WPCmd PEMailbox newmailreset + if {[catch {WPCmd PESession creds $colid $folder} creds] == 0 && $creds != 0} { + catch { + WPCmd PEInfo statmsg "Invalid Username or Password" + WPCmd PESession nocred $colid $folder + } + } + + if {[catch {WPCmd PEFolder clextended} coln]} { + WPCmd set reason "Can't get Collection Info: $coln" + } else { + set coln [lindex $coln $colid] + if {[regexp {^([a-zA-Z\.]+).*\/user=([^ /]*)} [lindex $coln 4] dummy srvname authuser]} { + WPCmd set reason "Opening folder [cgi_bold $folder] first requires that you log in o the server [cgi_bold "$srvname"]." + WPCmd set authuser $authuser + } elseif {[WPCmd PEFolder isincoming $colid]} { + WPCmd set reason "Incoming folder [cgi_bold $folder] requires you log into the the server." + } else { + WPCmd set reason "Opening [cgi_bold $folder] in [cgi_bold [lindex $coln 1]] requires you log into the the server." + } + } + + WPCmd set cid [WPCmd PEInfo key] + WPCmd set authcol $colid + WPCmd set authfolder $folder + WPCmd set authpage [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/open.tcl?folder=${folder}&colid=${colid}"] + WPCmd set authcancel [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders"] + + set src [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_queryauth.tcl] + + } else { + catch {WPCmd PEInfo statmsg "Cannot open $path: $reason"} + set src folders + } + } else { + + # manage caching last folder opened + if {0 == [catch {WPCmd set wp_open_folder} last_folder]} { + WPTFAddFolderCache [lindex $last_folder 0] [lindex $last_folder 1] + } + + catch {WPCmd set wp_open_folder [list $colid $folder]} + + # start with the message indicated by the + # incoming-startup-rule' in the current index + set firstmsg 1 + if {![catch {WPCmd PEMailbox firstinteresting} firstint] && $firstint > 0} { + set messagecount [WPCmd PEMailbox messagecount] + if {[catch {WPCmd PEInfo indexlines} ppg] || $ppg == 0} { + set ppg $_wp(indexlines) + } + + for {set i 1} {$i < $messagecount} {incr i $ppg} { + if {$i >= $firstint} { + break + } + + set firstmsg $i + } + + # show whole last page + if {$firstmsg + $ppg > $messagecount} { + if {[set n [expr {($messagecount + 1) - $ppg}]] > 0} { + set firstmsg $n + } else { + set firstmsg 1 + } + } + } + + if {[catch {WPCmd PEMailbox uid $firstmsg} exp]} { + set exp 1 + } + + WPCmd set first $firstmsg + WPCmd set top $exp + WPCmd set uid $exp + + WPCmd set width $_wp(width) + WPCmd set wp_spec_script fr_index.tcl + set src main.tcl + } +} + +if {[info exists src]} { + source [WPTFScript $src] +} diff --git a/web/cgi/alpine/1.0/do_quit.tcl b/web/cgi/alpine/1.0/do_quit.tcl new file mode 100755 index 00000000..0c013e4b --- /dev/null +++ b/web/cgi/alpine/1.0/do_quit.tcl @@ -0,0 +1,98 @@ +#!./tclsh +# $Id: do_quit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryquit.tcl +# +# Purpose: CGI script to handle quit query, either redirecting +# to session logout or returning to message listn +# +# Input: +set quit_vars { + {cid "Command ID"} + {quit {} ""} + {expinbox {} 0} + {expcurrent {} 0} + {cancel {} ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $quit_vars { + if {$cid != [WPCmd PEInfo key]} { + error "Invalid Command ID" + } + + switch -regexp -- $quit { + "^Yes, .*" { + + set exps "" + + if {[string compare $expinbox "on"] == 0} { + append exps "&expinbox=1" + } + + if {[string compare $expcurrent "on"] == 0} { + append exps "&expcurrent=1" + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + cgi_http_equiv Refresh "0; url=$_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}${exps}" + } + + cgi_body { + cgi_table height="20%" { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_nbspace] + } + } + } + + cgi_center { + cgi_table border=0 width=500 cellpadding=3 { + cgi_table_row { + cgi_table_data align=center rowspan=2 { + cgi_put [cgi_imglink logo] + } + + cgi_table_data rowspan=2 { + put [nbspace] + put [nbspace] + } + + cgi_table_data { + cgi_puts [cgi_font size=+2 face=Helvetica "Quitting Alpine ..."] + } + } + } + } + } + } + } + default { + source [WPTFScript main] + } + } +} diff --git a/web/cgi/alpine/1.0/do_view.tcl b/web/cgi/alpine/1.0/do_view.tcl new file mode 100755 index 00000000..fb8c5af6 --- /dev/null +++ b/web/cgi/alpine/1.0/do_view.tcl @@ -0,0 +1,190 @@ +# $Id: do_view.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# do_view.tcl +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages +# +# Input: +set view_vars { + {uid {} 0} + {op {} ""} + {f_colid {} ""} + {f_name {} ""} + {savecancel {} ""} + {sid {} ""} + {auths {} 0} + {user {} ""} + {pass {} ""} + {create {} 0} +} + +## read vars +foreach item $view_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +WPCmd PEInfo set wp_spec_script fr_view.tcl + +proc statmsg {msg} { + catch {WPCmd PEInfo statmsg $msg} +} + +if {$uid} { + # commit to servlet, view will retrieve it + WPCmd set uid $uid +} + +set uidparm "" + +# If there's an "op" (meaning we got here from a comview.tcl +# reference) trust "uid" is set within alpined's interpreter. +if {[string length $op]} { +# Set "op" only after we've concluded the folder's ready +# for view.tcl to do the actual copy + if {[string compare save [string tolower $op]]} { + append uidparm "&op=$op" + } +} else { + append uidparm "&uid=$uid" +} + +if {[string length $savecancel]} { + append uidparm "&savecancel=$savecancel" +} + + +# handle doing the actual save mechanics here rather than +# view.tcl since the result will have to be reflected +# in comview.tcl's Save dropdown. +if {[string compare save [string tolower $op]] == 0} { + if {[string length $savecancel] == 0} { + if {[string length [set folder [string trim $f_name]]]} { + switch -exact -- $folder { + __folder__prompt__ { + set uid 0 + _cgi_set_uservar onselect {fr_view op=save} + _cgi_set_uservar oncancel fr_view + _cgi_set_uservar target spec + _cgi_set_uservar controls 0 + source [WPTFScript savecreate] + set nopage 1 + } + __folder__list__ { + set uid 0 + _cgi_set_uservar onselect {fr_view op=save} + _cgi_set_uservar oncancel fr_view + _cgi_set_uservar target spec + _cgi_set_uservar controls 0 + source [WPTFScript savebrowse] + set nopage 1 + } + default { + if {$uid > 0} { + if {$auths} { + catch {WPCmd PESession nocred $f_colid $folder} + if {[catch {WPCmd PESession creds $f_colid $folder $user $pass} result]} { + statmsg "Cannot set credentials ($f_colid) $folder: result" + } + } + + if {[catch {WPCmd PEFolder exists $f_colid $folder} reason]} { + if {[string compare BADPASSWD [string range $reason 0 8]] == 0} { + set oncancel "view.tcl&uid=$uid&savecancel=1" + set conftext "Create Folder '$folder'?" + lappend params [list page fr_view] + lappend params [list uid $uid] + lappend params [list op save] + lappend params [list f_name $folder] + lappend params [list f_colid $f_colid] + source [WPTFScript auth] + set nopage 1 + } else { + statmsg "Existance test failed: $reason" + } + } elseif {$reason == 0} { + if {$create == 1 || [string compare create [string tolower $create]] == 0} { + if {[catch {WPCmd PEFolder create $f_colid $folder} reason]} { + statmsg "Create failed: $reason" + } else { + set dosave 1 + } + } else { + #set oncancel "view&uid=$uid&savecancel=1" + set qstate [list $folder] + set params [list [list page fr_view]] + lappend params [list uid $uid] + lappend params [list sid [clock seconds]] + lappend params [list op save] + lappend params [list f_name $folder] + lappend params [list f_colid $f_colid] + lappend qstate $params + + if {[catch {WPCmd PEInfo set querycreate_state $qstate}] == 0} { + source [WPTFScript querycreate] + set nopage 1 + } else { + statmsg "Error saving creation state" + } + } + } else { + set dosave 1 + } + + if {[info exists dosave]} { + append uidparm "&op=save" + } + } else { + statmsg "Cannot Save unknown message ID" + } + } + } + } else { + statmsg "Cannot Save to emtpy folder name" + } + } +} + + +if {![info exists nopage]} { + cgi_http_head { + WPStdHttpHdrs {} 60 + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=38,*" border=0 frameborder=0 framespacing=0 { + + if {[string length $f_colid] && [string length $f_name]} { + set parms "&f_colid=${f_colid}&f_name=[WPPercentQuote ${f_name}]" + if {[string length $sid]} { + append parms "&sid=$sid" + } + } else { + set parms "" + } + + cgi_frame cmds=comview.tcl?c=[WPCmd PEInfo key]${parms} scrolling=no title="Message Commands" + cgi_frame body=wp.tcl?page=view${uidparm}${parms} title="Message Text" + } + } +} diff --git a/web/cgi/alpine/1.0/docancel.tcl b/web/cgi/alpine/1.0/docancel.tcl new file mode 100755 index 00000000..e3d0aab5 --- /dev/null +++ b/web/cgi/alpine/1.0/docancel.tcl @@ -0,0 +1,56 @@ +# $Id: docancel.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# post.tcl +# +# Purpose: CGI script to perform message posting via compose.tcl +# generated form +# +# Input: +set post_vars { + {cid "Missing Command ID"} + {postpost "" main} +} + +# Output: +# + +## read vars +foreach item $post_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + error [list _action Postpone "Invalid Operation ID" "Click Back button to try again."] +} + +# clean up attachments +WPCmd PEInfo statmsg "Message cancelled" +catch {WPCmd PEInfo unset suspended_composition} + +source [WPTFScript $postpost] diff --git a/web/cgi/alpine/1.0/dosend.tcl b/web/cgi/alpine/1.0/dosend.tcl new file mode 100755 index 00000000..44130572 --- /dev/null +++ b/web/cgi/alpine/1.0/dosend.tcl @@ -0,0 +1,99 @@ +# $Id: dosend.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# post.tcl +# +# Purpose: CGI script to perform message posting via compose.tcl +# generated form +# +# Input: +set post_vars { + {cid "Missing Command ID"} + {postpost "" "main.tcl"} + {user "" ""} + {pass "" ""} + {server "" ""} +} + +# Output: +# + +## read vars +foreach item $post_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + error [list _action Postpone "Invalid Operation ID" "Click Back button to try again."] +} + +if {[string length $user] && [string length $pass] && [string length $server]} { + set cclientname "\{$server\}" + catch {WPCmd PESession nocred 0 $cclientname} + if {[catch {WPCmd PESession creds 0 $cclientname $user $pass} result]} { + WPCmd PEInfo statmsg "Cannot set credentials for $server" + } +} + +if {[catch {WPCmd PEInfo set suspended_composition} msgdata] == 0} { + if {[catch {WPCmd PECompose post $msgdata} errstr]} { + if {[string compare BADPASSWD [string range $errstr 0 8]] == 0 + && [catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + set oncancel "page=compose&restore=1&cid=$cid" + set conftext "Send Messsage?" + set reason "The server used to send this message requires authentication.[cgi_nl][cgi_nl]Enter Username and Password to connect to $server" + _cgi_set_uservar params [WPPercentQuote [list [list server $server] [list page dosend] [list postpost $postpost]]] + set src auth + } else { + # regurgitate the compose window + _cgi_set_uservar style "" + #set style "" + set title "Send Error: [cgi_font class=notice "$errstr"]" + if {[string length $errstr]} { + set notice "Send FAILED: $errstr" + } else { + set notice "Send FAILED: [WPCmd PEInfo statmsg]" + } + WPCmd PEInfo statmsg "$notice" + + if {[info exists attachments]} { + set a [split $attachments ","] + unset attachments + foreach id $a { + # id file size type/subtype + if {[catch {WPCmd PECompose attachinfo $id} result]} { + WPCmd PEInfo statmsg $result + } else { + lappend attachments [list $id [lindex $result 0] [lindex $result 1] [lindex $result 2]] + } + } + } + + set src compose + } + } else { + catch {WPCmd PEInfo unset suspended_composition} + WPCmd PEInfo statmsg "Message Sent!" + set src $postpost + } +} else { + WPCmd PEInfo statmsg "Internal Error: $msgdata" + set src $postpost +} + +source [WPTFScript $src] diff --git a/web/cgi/alpine/1.0/export.tcl b/web/cgi/alpine/1.0/export.tcl new file mode 100755 index 00000000..338e928c --- /dev/null +++ b/web/cgi/alpine/1.0/export.tcl @@ -0,0 +1,165 @@ +#!./tclsh +# $Id: export.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# export.tcl +# +# Purpose: CGI script to download exported folder +# +# Input: +set export_vars { + {cid "Unknown Command ID"} + {fid "Unknown Collection ID"} +} + +#set export_via_ip_address 1 +#set export_via_local_hostname 1 + +# inherit global config +source ./alpine.tcl + +set mailextension ".mbx" + +proc WPServerIP {} { + global _wp + + catch { + set ip 127.0.0.1 + set sid [socket -async [info hostname] [expr {([string length $_wp(serverport)]) ? $_wp(serverport) : 80}]] + set ip [lindex [ fconfigure $sid -sockname ] 0] + close $sid + } + + return $ip +} + + +WPEval $export_vars { + # generate filenames to hold exported folder and control file + for {set n 0} {1} {incr n} { + + set rhandle [WPCmd PESession random 64] + set cfile [file join $_wp(detachpath) detach.${rhandle}.control] + set dfile [file join $_wp(detachpath) detach.${rhandle}.data] + + if {[file exists $cfile] == 0 && [file exists $dfile] == 0} { + if {[catch {open $cfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} cfd] + || [catch {open $dfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} dfd]} { + if {[info exists dfd]} { + catch {close $cfd} + catch {file delete -force $cfile} + set errstr $dfd + } else { + set errstr $cfd + } + + error [list _action Export "Cannot create command/control files: [cgi_quote_html $errstr]" "Please close this window"] + } else { + close $dfd + break + } + } elseif {$n > 4} { + error [list _action Export "Command file creation limit" "Please close this window"] + } + } + + set colid [lindex $fid 0] + set fldr [eval "file join [lrange $fid 1 end]"] + + catch {file delete $dfile} + + if {[catch {WPCmd PEFolder export $colid $fldr $dfile} result]} { + WPCmd PEInfo statmsg $result + } else { + if {[set dfilesize [file size $dfile]] > 0 + && ([info exists _wp(uplim_bytes)] && $_wp(uplim_bytes) > 0) + && $dfilesize > $_wp(uplim_bytes)} { + if {$_wp(uplim_bytes) > (1000000)} { + set dfs [format {%s.%.2s MB} [WPcomma [expr {$dfilesize / 1000000}]] [expr {$dfilesize % 1000000}]] + set esl [format {%s.%.2s MB} [WPcomma [expr {$_wp(uplim_bytes) / 1000000}]] [expr {$_wp(uplim_bytes) % 1000000}]] + } else { + set dfs "[WPcomma $dfs] KB" + set esl "[WPcomma $_wp(uplim_bytes)] KB" + } + + WPCmd PEInfo statmsg "Exported folder size ($dfs) exceeds the maximum ($esl) size that can be imported.<br>If you wish to import this folder back into Web Alpine at a later time,<br>you should break it up into smaller folders" + } + + if {[info exists export_via_ip_address]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[WPServerIP]\]\\2" redirect] != 1} { + WPCmd PEInfo statmsg "Cannot determine server address" + catch {unset redirect} + } + } elseif {[info exists export_via_local_hostname]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[info hostname]\]\\2" redirect] != 1} { + WPCmd PEInfo statmsg "Cannot determine server address" + catch {unset redirect} + } + } else { + set redirect "[cgi_root]/pub/getach.tcl" + } + + set givenname "[file tail $fldr]${mailextension}" + set safegivenname $givenname + regsub -all {[/]} $safegivenname {-} safegivenname + regsub -all {[ ]} $safegivenname {_} safegivenname + regsub -all {[\?]} $safegivenname {X} safegivenname + regsub -all {[&]} $safegivenname {X} safegivenname + regsub -all {[#]} $safegivenname {X} safegivenname + regsub -all {[=]} $safegivenname {X} safegivenname + set safegivenname "/$safegivenname" + + puts $cfd "Content-type: Application/X-Mail-Folder" + puts $cfd "Content-Disposition: attachment; filename=\"$givenname\"" + + # side-step the cgi_xxx stuff in this special case because + # we don't want to buffer up the downloading attachment... + + puts $cfd "Content-Length: $dfilesize" + puts $cfd "Expires: [clock format [expr {[clock seconds] + 3600}] -f {%a, %d %b %Y %H:%M:%S GMT} -gmt true]" + puts $cfd "Cache-Control: max-age=3600" + puts $cfd "Refresh: 0; URL=\"$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders\"" + puts $cfd "" + + puts $cfd $dfile + + # exec chmod [cgi_tmpfile_permissions] $dfile + + close $cfd + + exec /bin/chmod [cgi_tmpfile_permissions] $cfile + exec /bin/chmod [cgi_tmpfile_permissions] $dfile + } + + # prepare to clean up if the brower never redirects + if {[info exists redirect]} { + set redirect "${redirect}${safegivenname}?h=${rhandle}" + } else { + set redirect "wp.tcl?page=folders&cid=$cid" + } + + cgi_http_head { + # redirect to the place we stuffed the export info. use the ip address + # to foil spilling any session cookies or the like + + if {[info exists env(SERVER_PROTOCOL)] && [regexp {[Hh][Tt][Tt][PP]/([0-9]+)\.([0-9]+)} $env(SERVER_PROTOCOL) m vmaj vmin] && $vmaj >= 1 && $vmin >= 1} { + cgi_puts "Status: 303 Temporary Redirect" + } else { + cgi_puts "Status: 302 Redirected" + } + + cgi_puts "URI: $redirect" + cgi_puts "Location: $redirect" + } + + exec echo $rhandle | [file join $_wp(cgipath) [WPCmd PEInfo set wp_ver_dir] whackatch.tcl] >& /dev/null & +} diff --git a/web/cgi/alpine/1.0/exporting.tcl b/web/cgi/alpine/1.0/exporting.tcl new file mode 100644 index 00000000..b1242843 --- /dev/null +++ b/web/cgi/alpine/1.0/exporting.tcl @@ -0,0 +1,187 @@ +# $Id: exporting.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# exporting.tcl +# +# Purpose: CGI script to generate html output associated with folder +# exporting explanation text +# +# Input: +set export_vars { + {fid "Missing Collection ID"} + {cid "Missing Command ID"} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# Command Menu definition for Message View Screen +set export_menu { +} + +set common_menu { + { + {} + { + { + # * * * * Cancel * * * * + cgi_put [cgi_url "Folder List" wp.tcl?page=folders&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } +} + +## read vars +foreach item $export_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {[catch {WPCmd PEInfo key} key]} { + error [list _action "command ID" $key] +} + +# massage fid, strip leading "f_" +set fid [string range [lindex $fid 0] 2 end] +set digfid [cgi_unquote_input $fid] +set colid [lindex $digfid 0] +if {[set l [llength $digfid]] > 2} { + set fpath [eval "file join [lrange $digfid 1 [expr {[llength $digfid] - 1}]]"] +} else { + set fpath "" +} +set fldr [lindex $digfid end] + +# paint the page +cgi_http_head { + WPStdHttpHdrs text/html +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Exporting" + WPStyleSheets + cgi_http_equiv Refresh "0; url=$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/export.tcl?fid=${fid}&cid=$cid" + } + + cgi_body bgcolor=$_wp(bordercolor) { + + set mbox [WPCmd PEMailbox mailboxname] + + WPTFTitle "Folder Export" + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + + cgi_table_row { + cgi_table_data rowspan=2 valign=top class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=2 { + cgi_table_row { + cgi_table_data class=navbar style=padding-top:6 { + cgi_puts "Current Folder :" + cgi_division align=center "style=margin-top:4;margin-bottom:4" { + cgi_put [cgi_url [WPCmd PEMailbox mailboxname] fr_main.tcl target=_top class=navbar] + + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + + cgi_br + } + + cgi_hr "width=75%" + } + } + + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar style=padding-bottom:10 { + WPTFCommandMenu export_menu common_menu + } + } + } + } + } + + # down the right side of the table is the window's contents + cgi_table_data width="100%" valign=top class=dialog { + + cgi_division "style=\"margin-left: 12%; margin-right: 12%\"" { + + cgi_division align=center "style=\"padding: 18; font-size: bigger \"" { + cgi_puts "Export Folder" + } + + cgi_puts "WebPine is preparing the folder [cgi_bold $fldr] for download. " + cgi_puts "You should see your browser's File Open Dialog appear any momment." + + cgi_p + + cgi_puts "The exported file will contain all of the messages in the folder separated " + cgi_puts "by a traditional mail message delimiter, and should be recognizable by " + cgi_puts "a variety of desktop mail programs." + + cgi_p + + cgi_puts "Be sure to pick a good name for the downloaded mail folder." + cgi_puts "If you are sure the folder has been exported properly (that is, " + cgi_puts "there were no error messages or other such problems, you can " + if {[string compare inbox [string tolower $mbox]]} { + cgi_puts "delete the folder from the collection." + } else { + cgi_puts "delete and expunge the messages from your INBOX." + } + + cgi_p + + cgi_puts "WebPine's [cgi_span "style=font-weight: bold; font-style: italic" Import] command, found to the right of each collection and " + cgi_puts "directory entry in the folder list, can be used to transfer the exported " + cgi_puts "mail folder from your computer back into a folder collection " + cgi_puts "suitable for viewing within WebPine " + + cgi_p + + cgi_puts "If your browser does not automatically return to the Folder List page after the download is complete, click the button below." + + cgi_p + + cgi_division align=center { + cgi_form $_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/wp.tcl method=get { + cgi_text "page=folders" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + cgi_submit_button "done=Return to Folder List" + } + } + } + } + } + } + } + } + diff --git a/web/cgi/alpine/1.0/filtedit.tcl b/web/cgi/alpine/1.0/filtedit.tcl new file mode 100755 index 00000000..34b9bd0f --- /dev/null +++ b/web/cgi/alpine/1.0/filtedit.tcl @@ -0,0 +1,704 @@ +#!./tclsh +# $Id: filtedit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# filtedit.tcl +# +# Purpose: CGI script to generate html form editing of a single filter + +# +# include common filter info +source filter.tcl + +# +# Input: +set filtedit_vars { + {cid "No cid"} + {oncancel "No oncancel"} + {onfiltcancel {} ""} + {fno {} -1} + {add {} 0} + {filterrtext {} ""} + {filtedit_score {} 0} + {filtedit_indexcolor {} 0} + {fg {} ""} + {bg {} ""} +} + +# Output: +# + +## read vars +foreach item $filtedit_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + if {[llength $item] > 2} { + set [lindex $item 0] [lindex $item 2] + } else { + error [list _action [lindex $item 1] $result] + } + } + } else { + set [lindex $item 0] 1 + } +} + +if {$filtedit_score} { + set filttype score + set filttypename Score +} elseif {$filtedit_indexcolor} { + set filttype indexcolor + set filttypename "Index Color" +} else { + set filttype filt + set filttypename Filter +} + +if {[info exists filtedit_add]} { + set add $filtedit_add +} + +if {[info exists filtedit_fno]} { + set fno $filtedit_fno +} + +if {[info exists filtedit_onfiltcancel]} { + set onfiltcancel $filtedit_onfiltcancel +} + +if {[info exists filtedit_filterrtext]} { + set filterrtext $filtedit_filterrtext +} + +set filterr 0 +if {[string length $filterrtext]} { + set filterr 1 +} + +set filtedit_menu { + { + {} + { + { + # * * * * OK * * * * + #cgi_image_button filt_save=[WPimg but_save] border=0 alt="Save Config" + cgi_submit_button "${filttype}_save=Save" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_submit_button filtcancel=Cancel + } + } + } + { + {} + { + { + # * * * * HELP * * * * + cgi_submit_button "${filttype}help=Get Help" + } + } + } +} + + +proc wpGetVarAs {_var _varas} { + upvar $_varas varas + + if {[catch {cgi_import_as $_var varas} result]} { + set varas "" + } +} + +proc freetext_cell {intro varname varval} { + cgi_table_data align=right { + cgi_puts [cgi_bold "$intro :[cgi_nbspace][cgi_nbspace]"] + } + cgi_table_data align=left { + cgi_text "$varname=$varval" "style=margin:2" + } +} + + +array set idvarnames $pattern_id +array set idvarvals {} +array set patvarnames $pattern_fields +array set patvarvals {} +array set actionvarnames $pattern_actions +array set colvarnames $pattern_colors +array set scorevarnames $pattern_scores + +array set actionvals {} + +cgi_http_head { + cgi_content_type + cgi_pragma no-cache +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "$filttypename List Configuration" + WPStyleSheets + } + + if {$add == 0} { + if {$filtedit_score} { + set actions $pattern_scores + set fext [WPCmd PEConfig scoreextended $fno] + } elseif {$filtedit_indexcolor} { + set actions $pattern_colors + set fext [WPCmd PEConfig indexcolorextended $fno] + } else { + set actions $pattern_actions + set fext [WPCmd PEConfig filtextended $fno] + } + + foreach fvar $fext { + switch -- [lindex $fvar 0] { + id { + foreach idvar [lindex $fvar 1] { + set idname [lindex $idvar 0] + if {[info exists idvarnames($idname)]} { + set idvarvals($idname) [lindex $idvar 1] + } + } + } + pattern { + foreach patternvar [lindex $fvar 1] { + set patname [lindex $patternvar 0] + if {[info exists patvarnames($patname)]} { + set patvarvals($patname) [lindex $patternvar 1] + } + } + } + filtaction { + foreach actionvar [lindex $fvar 1] { + set actionname [lindex $actionvar 0] + if {[info exists actionvarnames($actionname)]} { + set actionvals($actionname) [lindex $actionvar 1] + } + } + } + indexcolors { + foreach colvar [lindex $fvar 1] { + set colname [lindex $colvar 0] + if {[info exists colvarnames($colname)]} { + set actionvals($colname) [lindex $colvar 1] + } + } + } + scores { + foreach colvar [lindex $fvar 1] { + set actionvals([lindex $colvar 0]) [lindex $colvar 1] + } + } + } + } + } else { + if {$filtedit_score} { + set actions $pattern_scores + } elseif {$filtedit_indexcolor} { + set actions $pattern_colors + } else { + set actions $pattern_actions + } + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=filtconfig target=_top { + cgi_text "page=conf_process" type=hidden notab + cgi_text "cp_op=${filttype}config" type=hidden notab + cgi_text "cid=$cid" type=hidden notab + cgi_text "oncancel=$oncancel" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + cgi_table_row { + # + # next comes the menu down the left side + # + eval { + cgi_table_data $_wp(menuargs) rowspan=4 { + WPTFCommandMenu filtedit_menu {} + } + } + + # + # In main body of screen goes confg list + # + cgi_table_data valign=top width="100%" class=dialog { + if {[string length $onfiltcancel]} { + cgi_text "onfiltcancel=$onfiltcancel" type=hidden notab + } + cgi_text "fno=$fno" type=hidden notab + cgi_text "subop=[expr {$add ? "add" : "edit"}]" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=0 { + # pattern title + cgi_table_row { + cgi_table_data { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"font-weight:bold;font-size:bigger\">$filttypename Identification</legend>" + cgi_table { + foreach {idname idtype} $pattern_id { + if {[info exists idvarvals($idname)]} { + set val $idvarvals($idname) + } else { + wpGetVarAs $idname val + } + cgi_table_row { + freetext_cell "$filttypename [lindex $idtype 0]" $idname $val + } + } + } + cgi_puts "</fieldset>" + } + } + + # Folder Conditions + wpGetVarAs folder folder + wpGetVarAs ftype ftype + cgi_table_row { + cgi_table_data colspan=2 { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"font-weight:bold;font-size:bigger\">Folder Conditions</legend>" + cgi_table { + cgi_table_row { + cgi_table_data align=right valign=top { + cgi_puts [cgi_bold "Current Folder Type :"] + } + cgi_table_data align=left { + cgi_table border=0 cellpadding=0 cellspacing=0 { + cgi_table_row { + cgi_table_data width=50 { + cgi_puts "[cgi_nbspace]" + } + cgi_table_data { + cgi_table border=0 cellpadding=0 cellspacing=0 { + foreach type {any news email specific} { + cgi_table_row { + cgi_table_data { + cgi_radio_button ftype=$type [expr {[string compare $ftype $type] == 0 ? "checked" : ""}] style="background-color:$_wp(dialogcolor)" + } + cgi_table_data { + switch -- $type { + any - + news - + email { + cgi_puts "[string toupper [string range $type 0 0]][string range $type 1 end]" + } + specific { + cgi_puts "Specific Folder List :" + cgi_text "folder=$folder" + } + } + } + } + } + } + } + } + } + } + } + } + cgi_puts "</fieldset>" + } + } + + # Message Conditions + + cgi_table_row { + cgi_table_data { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"font-weight:bold;font-size:bigger\">Message Conditions</legend>" + cgi_table border=0 { + foreach {pvarname parvarval} $pattern_fields { + + if {$filterr} { + wpGetVarAs $pvarname pvarval + } elseif {[info exists patvarvals($pvarname)]} { + set pvarval $patvarvals($pvarname) + } else { + set pvarval "" + } + + cgi_table_row { + switch -- [lindex $patvarnames($pvarname) 1] { + freetext { + freetext_cell [lindex $patvarnames($pvarname) 0] $pvarname $pvarval + } + status { + cgi_table_data align=right { + cgi_puts "[cgi_bold [lindex $patvarnames($pvarname) 0]] :[cgi_nbspace][cgi_nbspace]" + } + cgi_table_data align=left { + cgi_select $pvarname "style=margin:2" { + cgi_option "Don't care, always matches" "value=either" + cgi_option "Yes" "value=yes" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "No" "value=no" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + } + } + } + addrbook { + cgi_table_data align=right valign=top { + cgi_puts "[cgi_bold [lindex $patvarnames($pvarname) 0]] :[cgi_nbspace][cgi_nbspace]" + } + cgi_table_data align=left { + cgi_select addrbook "style=margin:2" { + cgi_option "Don't care, always matches" "value=either" [expr {[string compare $pvarval "either"] == 0 ? "selected" : ""}] + cgi_option "Yes, in any address book" "value=yes" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "No, not in any addressbook" "value=no" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + cgi_option "Yes, in specific address book" "value=yesspecific" [expr {[string compare $pvarval "yesspecific"] == 0 ? "selected" : ""}] + cgi_option "No, not in specific address book" "value=nospecific" [expr {[string compare $pvarval "nospecific"] == 0 ? "selected" : ""}] + } + cgi_br + cgi_puts "Specific Addressbook:" + cgi_text "specificabook=" "style=margin:4" + cgi_br + cgi_puts "Types of addresses to check for in address book:" + cgi_table style=margin-left:30 { + cgi_table_row { + cgi_table_data nowrap { + cgi_checkbox abookfrom [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + cgi_puts "From" + } + + cgi_table_data nowrap { + cgi_checkbox abookreplyto + cgi_puts "Reply-To" + } + } + cgi_table_row { + cgi_table_data nowrap { + cgi_checkbox abooksender + cgi_puts "Sender" + } + + cgi_table_data nowrap { + cgi_checkbox abookto + cgi_puts "To" + } + } + cgi_table_row { + cgi_table_data nowrap { + cgi_checkbox abookcc + cgi_puts "Cc" + } + } + } + } + } + headers { + cgi_table_data align=right valign=top { + cgi_put "[cgi_bold [lindex $patvarnames($pvarname) 0]] :[cgi_nbspace][cgi_nbspace]" + } + cgi_table_data align=left { + cgi_table { + set hdrnum 0 + + if {[llength $pvarval] > 0} { + for {set n 0} {$n < [llength $pvarval]} {incr n} { + cgi_table_row { + cgi_table_data align=left nowrap { + cgi_text "hdrfld${n}=[lindex [lindex $pvarval $n] 0]" "style=margin:2" + cgi_put ":" + cgi_text "hdrval${n}=[lindex [lindex $pvarval $n] 1]" "style=margin:2" + cgi_submit_button "rmheader${n}=Remove" + } + } + } + + cgi_text "header_total=$n" type=hidden notab + } + + cgi_table_row { + cgi_table_data align=left nowrap { + cgi_submit_button "addheader=Add Header" + } + } + } + } + } + } + } + } + } + cgi_puts "</fieldset>" + } + } + + cgi_table_row { + cgi_table_data "style=\"padding-bottom: 40\"" { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"font-weight:bold;font-size:bigger\">Filter Actions</legend>" + foreach {avarname patval} $actions { + switch -- $avarname { + indexcolor { + set ih [WPIndexLineHeight] + set iformat [WPCmd PEMailbox indexformat] + set num 0 + cgi_division "width=100%" align=center "style=\"font-size: bigger; font-weight: bold; margin: 0 0 12 0 \"" { + cgi_puts "Choose Index Line Colors" + } + + cgi_table width=100% align=center cellpadding=0 cellspacing=0 "style=\"font-family: geneva, arial, sans-serif; height: ${ih}pix; width: 90%; background-color: white ; border: 1px solid black\"" { + foreach l [list "Line One" "Sample Message" "Line Three"] { + set iclass [lindex {i0 i1} [expr ([incr num] % 2)]] + set istyle "" + if {$num == 2} { + wpGetVarAs fg fg + if {[string length $fg] == 0} { + if {[info exists actionvals($avarname)]} { + set fg [lindex $actionvals($avarname) 0] + } + } + + cgi_text "fg=$fg" type=hidden notab + append istyle "; color: $fg" + + wpGetVarAs bg bg + if {[string length $bg] == 0} { + if {[info exists actionvals($avarname)]} { + set bg [lindex $actionvals($avarname) 1] + } + } + + cgi_text "bg=$bg" type=hidden notab + append istyle "; background-color: $bg" + } + + cgi_table_row { + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + cgi_table_data height=${ih}pix class=$iclass "style=\"$istyle\"" { + cgi_checkbox bogus + } + } + + foreach fmt $iformat { + cgi_table_data height=${ih}pix width=[lindex $fmt 1]% nowrap class=$iclass "style=\"$istyle\"" { + switch -regex [string tolower [lindex $fmt 0]] { + number { + cgi_puts "$num" + } + status { + set n [expr {(int((10 * rand()))) % 5}] + cgi_puts [lindex {N D F A { }} $n] + } + .*size.* { + cgi_puts "([expr int((10000 * rand()))])" + } + from.* { + cgi_puts "Some Sender" + } + subject { + cgi_puts $l + } + date { + cgi_puts [clock format [clock seconds] -format "%d %b"] + } + default { + cgi_puts [lindex $fmt 0] + } + } + } + } + } + } + } + cgi_table width=80% align=center { + cgi_table_row { + cgi_table_data align=center { + cgi_table "style=\"background-color: #ffcc66\"" { + wpGetVarAs fgorbg fgorbg + cgi_table_row { + cgi_table_data { + if {[string length $fgorbg] == 0 || [string compare $fgorbg fg] == 0} { + set checked checked=1 + } else { + set checked "" + } + + cgi_radio_button fgorbg=fg $checked + } + cgi_table_data "style=\"align: left; padding-left: 12\"" { + cgi_puts "Foreground" + } + } + cgi_table_row { + cgi_table_data { + if {[string length $checked]} { + set checked "" + } else { + set checked checked=1 + } + + cgi_radio_button fgorbg=bg $checked + } + cgi_table_data "style=\"align: left; padding-left: 12\"" { + cgi_puts "Background" + } + } + } + } + cgi_table_data align=center { + cgi_image_button "colormap=[WPimg nondither10x10]" alt="Color Pattern" "style=\"border: 1px solid black\"" + } + } + } + } + folder { + if {[info exists actionvals(kill)]} { + set killit $actionvals(kill) + } else { + set killit 0 + } + + if {$filterr} { + wpGetVarAs action tval + set killit [expr {([string compare $tval "delete"] == 0) ? 1 : 0}] + } + cgi_table border=0 cellpadding=0 cellspacing=0 { + cgi_table_row { + cgi_table_data width=50 align=right valign=top { + cgi_puts [cgi_bold "Action:[cgi_nbspace]"] + } + cgi_table_data { + cgi_table border=0 cellpadding=0 cellspacing=0 { + cgi_table_row { + cgi_table_data valign=top { + cgi_radio_button action=status [expr {$killit ? "checked" : ""}] style="background-color:$_wp(dialogcolor)" + } + cgi_table_data { + cgi_puts "Set Message Status:" + cgi_division "style=\"margin-left: .5in\"" { + cgi_select actsetimp { + cgi_option "Don't change Important Status" "value=leave" [expr {[string compare $pvarval "either"] == 0 ? "selected" : ""}] + cgi_option "Set Important status" "value=set" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "Clear Important status" "value=clear" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + } + + cgi_br + + cgi_select actsetnew { + cgi_option "Don't change New Status" "value=leave" [expr {[string compare $pvarval "either"] == 0 ? "selected" : ""}] + cgi_option "Set New status" "value=set" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "Clear New status" "value=clear" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + } + + cgi_br + + cgi_select actsetdel { + cgi_option "Don't change Deleted Status" "value=leave" [expr {[string compare $pvarval "either"] == 0 ? "selected" : ""}] + cgi_option "Set Deleted status" "value=set" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "Clear Deleted status" "value=clear" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + } + + cgi_br + + cgi_select actsetans { + cgi_option "Don't change Answered Status" "value=leave" [expr {[string compare $pvarval "either"] == 0 ? "selected" : ""}] + cgi_option "Set Answered status" "value=set" [expr {[string compare $pvarval "yes"] == 0 ? "selected" : ""}] + cgi_option "Clear Answered status" "value=clear" [expr {[string compare $pvarval "no"] == 0 ? "selected" : ""}] + } + } + } + } + cgi_table_row { + cgi_table_data valign=top { + cgi_radio_button action=delete [expr {$killit ? "checked" : ""}] style="background-color:$_wp(dialogcolor)" + } + cgi_table_data { + cgi_puts "Delete" + } + } + cgi_table_row { + cgi_table_data valign=top { + cgi_radio_button action=move [expr {$killit == 0 ? "checked" : ""}] style="background-color:$_wp(dialogcolor)" + } + cgi_table_data { + cgi_puts "Move to Folder :" + if {$filterr} { + wpGetVarAs actionfolder tval + cgi_text "actionfolder=$tval" + } else { + if {[info exists actionvals($avarname)]} { + set av $actionvals($avarname) + } else { + set av 0 + } + + cgi_text "actionfolder=$av" + } + cgi_br + if {$filterr} { + wpGetVarAs moind moinval + set tval [expr {([string compare $moinval on] == 0) ? "checked" : ""}] + } else { + if {[info exists actionvals($avarname)] && $actionvals($avarname) == 1} { + set tval checked + } else { + set tval "" + } + } + cgi_checkbox moind $tval + cgi_puts "Move only if not deleted." + } + } + } + } + } + cgi_table_row { + wpGetVarAs setkeywords setkeywords + freetext_cell "Set these Keywoards" setkeywords $setkeywords + } + cgi_table_row { + wpGetVarAs clearkeywords clearkeywords + freetext_cell "Clear these Keywoards" clearkeywords $clearkeywords + } + } + } + scores { + cgi_table border=0 cellpadding=4 cellspacing=0 align=center { + cgi_table_row { + wpGetVarAs scoreval scoreval + if {[string length $scoreval] == 0} { + set scoreval $actionvals(scoreval) + } + + freetext_cell "Score Value" scoreval $scoreval + } + cgi_table_row { + wpGetVarAs scorehdr scorehdr + if {[string length $scorehdr] == 0} { + set scorehdr $actionvals(scorehdr) + } + + freetext_cell "Score Header" scorehdr $scorehdr + } + } + } + } + } + + cgi_puts "</fieldset>" + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/filter.tcl b/web/cgi/alpine/1.0/filter.tcl new file mode 100755 index 00000000..2974f6ca --- /dev/null +++ b/web/cgi/alpine/1.0/filter.tcl @@ -0,0 +1,63 @@ +# $Id: filter.tcl 391 2007-01-25 03:53:59Z mikes@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# filter.tcl +# +# Purpose: Common filter management data/routines + +set pattern_id { + nickname {"Nickname" freetext} + comment {"Comment" freetext} +} + +set pattern_fields { + to {"To" freetext} + from {"From" freetext} + sender {"Sender" freetext} + cc {"Cc" freetext} + recip {"Recipients" freetext} + partic {"Participants" freetext} + news {"Newsgroups" freetext} + subj {"Subject" freetext} + alltext {"All Text" freetext} + bodytext {"Body Text" freetext} + age {"Age Interval" freetext} + size {"Size Interval" freetext} + score {"Score Interval" freetext} + keyword {"Keyword" freetext} + charset {"Character Set" freetext} + headers {"Extra Headers" headers} + stat_new {"Message is New" status} + stat_rec {"Message is Recent" status} + stat_del {"Message is Deleted" status} + stat_imp {"Message is Important" status} + stat_ans {"Message is Answered" status} + stat_8bitsubj {"Subject contains raw 8bit characters" status} + stat_bom {"Beginning of Month" status} + stat_boy {"Beginning of Year" status} + addrbook {"Address in address book" addrbook} +} + + +set pattern_actions { + kill {"kill"} + folder {"Folder"} + move_only_if_not_deleted {"moind"} +} + +set pattern_colors { + indexcolor {indexcolor} +} + +set pattern_scores { + scores {scores} +} diff --git a/web/cgi/alpine/1.0/flags.tcl b/web/cgi/alpine/1.0/flags.tcl new file mode 100755 index 00000000..7cc83962 --- /dev/null +++ b/web/cgi/alpine/1.0/flags.tcl @@ -0,0 +1,112 @@ +#!./tclsh +# $Id: flags.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryexpunge.tcl +# +# Purpose: CGI script to generate html form used to confirm +# deleted message expunge +# +# Input: +set flag_vars { + {uid "Missing UID"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl + +WPEval $flag_vars { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Set Flags" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=body { + cgi_text "page=index" type=hidden notab + cgi_text "sessid=$sessid" type=hidden notab + cgi_text "uid=$uid" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="75%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_nl][cgi_nl] + cgi_puts "Status flags are attributes you can assign to messages that help you associate certain meanings (for example, [cgi_bold Important]) or indicate to Web Alpine" + cgi_puts "how you would like to operate on the message (for example, the [cgi_bold Deleted] flag tells WebPine to permanently remove the" + cgi_puts "message from the folder when you [cgi_bold Expunge])." + cgi_puts [cgi_nl][cgi_nl] + cgi_puts "Set or unset desired flags for message [WPCmd PEMessage $uid number] below then" + cgi_puts "click [cgi_italic "Set Flags"], or [cgi_italic Cancel] to return to the list of messages" + cgi_puts "in [WPCmd PEMailbox mailboxname]." + cgi_br + cgi_br + + set flaglist [WPCmd PEInfo flaglist] + set setflags [WPCmd PEMessage $uid status] + + cgi_table class=dialog { + foreach item $flaglist { + cgi_table_row { + cgi_table_data valign=top align=right width="30%" { + if {[lsearch $setflags $item] >= 0} { + set checked checked + } else { + set checked "" + } + + cgi_checkbox $item style="background-color:$_wp(dialogcolor)" $checked + } + + cgi_table_data valign=top align=left { + switch -- $item { + New { set text "New" } + Answered { set text "Answered" } + Deleted { set text "Deleted" } + default { set text $item } + } + cgi_puts $text + } + } + } + + cgi_table_row { + cgi_table_data colspan=2 height=50 { + cgi_br + cgi_submit_button "op=Set Flags" + cgi_submit_button cancel=Cancel + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/fldrbrowse.tcl b/web/cgi/alpine/1.0/fldrbrowse.tcl new file mode 100755 index 00000000..b9021a4d --- /dev/null +++ b/web/cgi/alpine/1.0/fldrbrowse.tcl @@ -0,0 +1,335 @@ +# $Id: fldrbrowse.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# folders.tcl +# +# Purpose: CGI script to generate html output associated with folder +# and collection management +# +# Input: +set folder_vars { + {uid {} 0} + {show {} ""} + {expand {} ""} + {contract {} ""} + {target {} ""} + {onselect {} "compose"} + {oncancel {} "index"} + {controls {} 1} + {reload} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# the name of this script +set me [file tail [info script]] + +set indention 18 + +proc pretty_folder_name {collections folder} { + set fcolid [lindex $folder 0] + for {set i 0} {$i < [llength $collections]} {incr i} { + set col [lindex $collections $i] + if {$fcolid == [lindex $col 0]} { + set coltext [lindex $col 1] + } + } + return "${coltext}:[join [lrange $folder 1 end] /]" +} + + +set key [WPCmd PEInfo key] + + +# +# Display the given folder list in a table (w/ mihodge mods) +# +proc blat_folder_list {colid flist shown path baseurl scroll anchorcntref onselect depth} { + + global key border indention _wp target + + set mbox [WPCmd PEMailbox mailboxname] + + upvar $anchorcntref anchorcnt + + set rownum 0 + + foreach folder $flist { + set t [lindex $folder 0] + set f [lindex $folder 1] + set ff [linsert $path [llength $path] $f] + set index -1 + + # initial pad=12, expand/contract control is 9px wide + set cellpad [expr {12 + ($depth * $indention)}] + + if {[string first F $t] >= 0} { + set delim [WPCmd PEFolder delimiter $colid] + set fullpath [join [lrange $ff 1 end] $delim] + regsub -all {(')} [lrange $ff 1 end] {\\\\\1} ef + set celldata [cgi_url $f wp.tcl?page=[join ${onselect} {&}]&f_colid=${colid}&f_name=[WPPercentQuote [join $ef $delim]]&target=${target}&cid=$key target=${target}] + } else { + set celldata $f + } + + if {[string first D $t] >= 0} { + + if {[set index [lsearch $shown $ff]] < 0} { + set control expand + } else { + set control contract + } + + set celldata "[cgi_url [cgi_imglink $control] "${baseurl}${control}=[WPPercentQuote $ff]#f_[WPPercentQuote $ff]" name=f_[WPPercentQuote $ff] "style=\"padding-right:10px\""]$celldata" + incr cellpad -19 + } + + cgi_table_row { + cgi_table_data { + cgi_put [cgi_img [WPimg dot2] height=1] + } + + cgi_table_data align=left "style=\"padding-left: ${cellpad}px\"" nowrap { + cgi_put $celldata + } + + cgi_table_data valign=top nowrap { + cgi_puts [cgi_nbspace] + } + } + + if {[string first D $t] >= 0 && $index >= 0} { + set nflist [eval WPCmd PEFolder list $ff] + set newpath $path + lappend newpath $f + blat_folder_list $colid $nflist $shown $newpath $baseurl $scroll anchorcnt $onselect [expr {$depth + 1}] + } + + catch {unset control} + } +} + +# +# Command Menu definition for Message View Screen +# +set folder_menu { +} + +set common_menu { + { + {expr {$controls == 1}} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url Cancel wp.tcl?page=$oncancel&cid=[WPCmd PEInfo key] class=navbar target=_top] + } + } + } + {} + { + {} + { + { + cgi_puts "Get Help" + } + } + } +} + + +## read vars +foreach item $folder_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {[catch {WPNewMail $reload} newmail]} { + error [list _action "new mail" $newmail] +} + + +# perform any requested actions + +# preserve vars that my have been overridden with cgi parms + +if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collectoin list" $collections] +} + +set shown [split $show ,] +set scroll {} +set anchorcnt 0 + +# mihodge: process actions +if {[llength $expand]} { + lappend shown $expand + set scroll $expand +} + +if {[llength $contract]} { + if {[set index [lsearch $shown $contract]] >= 0} { + set shown [lreplace $shown $index $index] + set scroll $contract + } +} + +set baseurl wp.tcl?page=fldrbrowse&onselect=[WPPercentQuote ${onselect}]&oncancel=${oncancel}&controls=${controls}&target=${target}& + +if {[llength $shown]} { + append baseurl "show=[WPPercentQuote [join $shown ,]]&" +} + + +# paint the page +cgi_http_head { + WPStdHttpHdrs text/html +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "Folder List" folders + if {$controls == 1} { + WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders" + } + + WPStyleSheets + } + + cgi_body bgcolor=$_wp(bordercolor) { + + catch {WPCmd PEInfo set help_context folders} + + # prepare context and navigation information + + set navops "" + + if {$controls == 1} { + WPTFTitle "Browse Folder" $newmail + } + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + cgi_table_row { + if {$controls > 0} { + cgi_table_data rowspan=2 valign=top class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=0 { + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar { + WPTFCommandMenu folder_menu common_menu + } + } + } + } + } + } + + # down the right side of the table is the window's contents + cgi_table_data width="100%" align=center valign=top class=dialog { + + # then the table representing the folders + cgi_table width=75% border=0 cellspacing=0 cellpadding=2 align=center { + + cgi_table_row { + cgi_table_data height=80 align=center valign=middle class=dialog { + switch $controls { + 0 - + 2 { set task "the Saved message" } + default { set task "your composition's [cgi_italic "File Carbon Copy"] (Fcc)" } + } + + cgi_puts "Click a folder name below to use it as the destination for $task, or click [cgi_italic Cancel]" + cgi_puts "to return without choosing anything." + } + } + + if {$controls != 1} { + cgi_table_row { + cgi_table_data align=center valign=top height=40 class=navbar { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=$target { + cgi_text page=$oncancel type=hidden notab + cgi_text cid=[WPCmd PEInfo key] type=hidden notab + cgi_submit_button cancel=Cancel + } + } + } + } + + cgi_table_row { + cgi_table_data { + cgi_table border=0 cellspacing=0 cellpadding=2 align=center { + for {set i 0} {$i < [llength $collections]} {incr i} { + set col [lindex $collections $i] + set colid [lindex $col 0] + + cgi_table_row { + cgi_table_data width=18 valign=top { + if {[llength $collections] > 1} { + if {[set index [lsearch $shown $colid]] < 0} { + cgi_puts [cgi_url [cgi_imglink expand] "${baseurl}expand=$colid"] + } else { + cgi_puts [cgi_url [cgi_imglink contract] "${baseurl}contract=$colid"] + } + } else { + cgi_puts [cgi_nbspace] + } + } + + cgi_table_data align=left { + if {[llength $collections] == 1} { + set menu "c" + set flist 1 + } else { + if {[set index [lsearch $shown $colid]] < 0} { + set menu "ce" + set flist {} + } else { + set menu "cc" + set flist 1 + } + } + + if {[llength $flist]} { + set flist [WPCmd PEFolder list $colid] + } + + if {$scroll == $colid} { + #cgi_javascript {cgi_puts {scroll = window.document.anchors.length;}} + } + + cgi_puts [cgi_font face=Helvetica size=+1 "[lindex $col 1]<A NAME=\"f_$colid\"> </A>"] + + incr anchorcnt + + if {[llength $flist]} { + blat_folder_list $colid $flist $shown $colid $baseurl $scroll anchorcnt $onselect 1 + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/fldrsavenew.tcl b/web/cgi/alpine/1.0/fldrsavenew.tcl new file mode 100755 index 00000000..a2a5f457 --- /dev/null +++ b/web/cgi/alpine/1.0/fldrsavenew.tcl @@ -0,0 +1,202 @@ +# $Id: fldrsavenew.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fldrsavenew.tcl +# +# Purpose: CGI script to generate html output associated with message +# Save to a new folder +# +# Input: +set folder_vars { + {onselect "" "index"} + {oncancel "" "index"} + {target "" ""} + {controls "" 1} + {reload} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +set key [WPCmd PEInfo key] + +# +# Command Menu definition for Message View Screen +# +set folder_menu { +} + +set common_menu { + { + {expr {$controls == 1}} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url Cancel wp.tcl?page=$oncancel&cid=[WPCmd PEInfo key] class=navbar target=_top] + } + } + } + {} + { + {} + { + { + cgi_puts "Get Help" + } + } + } +} + + +## read vars +foreach item $folder_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {[catch {WPNewMail $reload} newmail]} { + error [list _action "new mail" $newmail] +} + +# perform any requested actions + +# preserve vars that my have been overridden with cgi parms + +# paint the page +cgi_http_head { + WPStdHttpHdrs text/html +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Create for Save" folders + if {$controls == 1} { + WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=fldrsavenew" + } + + WPStyleSheets + } + + cgi_body onload=document.savepmt.f_name.focus() bgcolor=$_wp(bordercolor) { + + catch {WPCmd PEInfo set help_context fldrsave} + + # prepare context and navigation information + + set navops "" + + if {$controls == 1} { + WPTFTitle "Browse Folder" $newmail + } + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + if {$controls > 0} { + cgi_table_data rowspan=2 valign=top class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=2 { + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar { + WPTFCommandMenu folder_menu common_menu + } + } + } + } + } + } + + # down the right side of the table is the window's contents + cgi_table_data width="100%" align=center valign=top class=dialog { + + if {[string length $target] == 0} { + set target _top + } + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=$target name=savepmt { + cgi_text page=[lindex $onselect 0] type=hidden notab + for {set i 1} {$i < [llength $onselect]} {incr i} { + set a [split [lindex $onselect $i] {=}] + cgi_text [lindex $a 0]=[lindex $a 1] type=hidden notab + } + + cgi_text cid=[WPCmd PEInfo key] type=hidden notab + + # then the table representing the folders + cgi_table width=75% border=0 cellspacing=0 cellpadding=2 align=center { + + cgi_table_row { + cgi_table_data height=140 align=center valign=middle class=dialog { + cgi_p "Enter the name of the folder to save to below, and then click [cgi_italic OK]." + cgi_p "You may enter either the name of an existing folder, or the name of a new folder name to have it created. You may also specify a directory path in front of the folder name." + cgi_p "Click [cgi_italic Cancel] to return without saving (or creating) anything." + } + } + + if {[WPCmd PEFolder isincoming 0]} { + set f_colid 1 + } else { + set f_colid 0 + } + + cgi_table_row { + cgi_table_data align=center valign=top height=40 class=dialog { + cgi_put "Folder name : " + cgi_text f_name= type=text size=20 maxlength=256 style=vertical-align:middle onFocus=this.select() + + if {[catch {WPCmd PEFolder collections} collections] == 0 && [llength $collections] > 1} { + + cgi_put "within " + + cgi_select f_colid style=vertical-align:middle { + set j 0 + foreach i $collections { + if {$j == $f_colid} { + set selected selected + } else { + set selected {} + } + if {[string length [set f [lindex $i 1]]] > 12} { + set f "[string range $f 0 10]..." + } + + cgi_option $f value=$j $selected + incr j; + } + } + } else { + cgi_text f_colid=0 type=hidden notab + } + } + } + + cgi_table_row { + cgi_table_data align=center valign=middle height=60 class=dialog { + cgi_submit_button "ok= OK " + cgi_submit_button cancel=Cancel + } + } + } + } + } + } + } + } +} + diff --git a/web/cgi/alpine/1.0/folders.tcl b/web/cgi/alpine/1.0/folders.tcl new file mode 100755 index 00000000..a173b778 --- /dev/null +++ b/web/cgi/alpine/1.0/folders.tcl @@ -0,0 +1,727 @@ +# $Id: folders.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# folders.tcl +# +# Purpose: CGI script to generate html output associated with folder +# and collection management +# +# Input: +set folder_vars { + {uid "" 0} + {cid {} ""} + {show {} ""} + {expand {} ""} + {contract {} ""} + {oncancel "" main} + {frestore "" 0} + {delquery {} ""} + {dwnquery {} ""} + {delete {} ""} + {renquery {} ""} + {rename {} ""} + {newfolder {} ""} + {folder {} ""} + {newdir {} ""} + {directory {} ""} + {import {} ""} + {cancelled {} ""} + {fid {} ""} + {reload} +} + +set indention 18 + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +proc linecolor {linenum} { + if {$linenum % 2} { + return "#EEEEEE" + } else { + return "#FFFFFF" + } +} + +proc pretty_folder_name {collections folder} { + set fcolid [lindex $folder 0] + for {set i 0} {$i < [llength $collections]} {incr i} { + set col [lindex $collections $i] + if {$fcolid == [lindex $col 0]} { + set coltext [lindex $col 1] + } + } + return "${coltext}:[join [lrange $folder 1 end] /]" +} + +# +# Display the given folder list in a table (w/ mihodge mods) +# +proc blat_folder_list {colid flist shown path baseurl scroll anchorcntref depth} { + global key border indention mbox _wp + + upvar $anchorcntref anchorcnt + + set rownum 0 + + foreach folder $flist { + set t [lindex $folder 0] + set f [lindex $folder 1] + set ff [linsert $path [llength $path] $f] + set index -1 + + set bgcolor [linecolor [incr anchorcnt]] + + # initial pad=12, expand/contract control is 9px wide + set cellpad [expr {12 + ($depth * $indention)}] + set delim [WPCmd PEFolder delimiter $colid] + set fullpath [join [lrange $ff 1 end] $delim] + + if {[string first F $t] >= 0} { + regsub -all {(')} [lrange $ff 1 end] {\\\\\1} ef + set celldata [cgi_url $f open.tcl?colid=${colid}&folder=[WPPercentQuote $fullpath]&oncancel=folders&cid=$key target=_top] + } else { + set celldata $f + } + + if {[string first D $t] >= 0} { + + if {[set index [lsearch $shown $ff]] < 0} { + set control expand + } else { + set control contract + } + + set celldata "[cgi_url [cgi_imglink $control] "${baseurl}${control}=[WPPercentQuote $ff]#f_[WPPercentQuote $ff]" name=f_[WPPercentQuote $ff] "style=\"padding-right:10px\""]$celldata" + incr cellpad -19 + } + + cgi_table_row bgcolor=$bgcolor { + + cgi_table_data align=center { + if {[string first F $t] >= 0 || ([WPCmd PEFolder isincoming $colid] == 0 && [string compare $mbox $fullpath])} { + cgi_radio_button "fid=f_[WPPercentQuote $ff]" + } + } + + cgi_table_data align=left "style=\"padding-left: ${cellpad}px\"" nowrap { + cgi_put $celldata + } + + cgi_table_data valign=top nowrap { + if {[info exists control] && [string compare $control contract] == 0} { + cgi_submit_button "new_[WPPercentQuote $ff]=Create New..." + cgi_submit_button "imp_[WPPercentQuote $ff]=Import..." + } else { + cgi_puts [cgi_nbspace] + } + } + } + + if {[string first D $t] >= 0 && $index >= 0} { + set nflist [eval WPCmd PEFolder list $ff] + set newpath $path + lappend newpath $f + blat_folder_list $colid $nflist $shown $newpath $baseurl $scroll anchorcnt [expr {$depth + 1}] + } + + catch {unset control} + } +} + + +# +# Command Menu definition for Message View Screen +# +set folder_menu { +} + +set common_menu { + { + {} + { + { + # * * * * Ubiquitous INBOX link * * * * + if {[string compare inbox [string tolower $mbox]]} { + cgi_put [cgi_url INBOX [cgi_root]/$_wp(appdir)/$_wp(ui1dir)/open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_main.tcl target=_top class=navbar] + } + } + } + } + { + {} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=folders&cid=$key target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * RESUME * * * * + #set button [cgi_img [WPimg but_resume] border=0 alt="Resume"] + set button Resume + cgi_puts [cgi_url $button wp.tcl?page=resume&oncancel=folders&cid=$key class=navbar] + } + } + } + { + {} + { + { + # * * * * Addr books * * * * + #set button [cgi_img [WPimg but_abook] border=0 alt="Address Book"] + set button "Address Book" + cgi_puts [cgi_url $button wp.tcl?page=addrbook&oncancel=folders class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + cgi_put [cgi_url "Configure" wp.tcl?page=conf_process&newconf=1&oncancel=folders&cid=[WPCmd PEInfo key] class=navbar target=_top] + } + } + } + { + {} + { + { + cgi_put [cgi_url "Get Help" wp.tcl?page=help&oncancel=folders class=navbar target=_top] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * LOGOUT * * * * + if {[WPCmd PEInfo feature quit-without-confirm]} { + cgi_puts [cgi_url "Quit $_wp(appname)" $_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid target=_top class=navbar] + } else { + cgi_puts [cgi_url "Quit $_wp(appname)" wp.tcl?page=quit&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + } +} + +## read vars +foreach item $folder_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {[catch {WPCmd PEInfo key} key]} { + error [list _action "command ID" $key] +} + +# perform requested op +if {$delquery == 1 || [string compare $delquery Delete] == 0} { + if {[string length $fid]} { + set fid [string range $fid 2 end] + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_querydelfldr.tcl] + set nopage 1 + } else { + lappend newmail [list "Click button next to folder name then Click [cgi_italic Delete]"] + } +} elseif {$delete == 1 || [string compare $delete Delete] == 0} { + if {$cid != $key} { + lappend newmail [list "Invalid Command ID"] + } elseif {[string length $fid]} { + if {[catch [concat WPCmd PEFolder delete $fid] result] == 0} { + lappend newmail [list "'[lindex $fid end]' permanently removed"] + } + } else { + lappend newmail [list "Click button next to folder name then Click [cgi_italic Delete]"] + } +} elseif {[string compare $delete Cancel] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + lappend newmail [list "Folder Delete Cancelled"] +} elseif {[string compare $rename Cancel] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + lappend newmail [list "Folder Rename Cancelled"] +} elseif {$renquery == 1 || [string compare $renquery Rename] == 0} { + if {$cid != $key} { + lappend newmail [list "Invalid Command ID"] + } elseif {[string length $fid]} { + set fid [string range $fid 2 end] + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_queryrenfldr.tcl] + set nopage 1 + } else { + lappend newmail [list "Click button next to folder name then Click [cgi_italic Rename]"] + } +} elseif {$dwnquery == 1 || [string compare $dwnquery Export] == 0} { + if {$cid != $key} { + lappend newmail [list "Invalid Command ID"] + } elseif {[string length $fid] <= 0} { + lappend newmail [list "Click button next to folder name then Click [cgi_italic Export]"] + } elseif {[file isdirectory $_wp(detachpath)] <= 0} { + lappend newmail [list "Server Configuration Problem: $_wp(detachpath) does not exist"] + } else { + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) exporting.tcl] + set nopage 1 + } +} elseif {[string compare $rename Rename] == 0} { + if {[string length $folder]} { + if {[catch [concat WPCmd PEFolder rename $fid [list $folder]] result]} { + } else { + lappend newmail [list "'[lindex $fid end]' renamed to '$folder'"] + } + } else { + lappend newmail [list "Rename failed: no new name provided"] + } +} elseif {[string compare [string range $newfolder 0 5] Create] == 0} { + if {$cid != $key} { + lappend newmail [list "Invalid Command ID"] + } elseif {[string length $folder]} { + set fpath [lrange $fid 1 end] + lappend fpath $folder + if {[catch {WPCmd PEFolder delimiter [lindex $fid 0]} result] + || [catch {WPCmd PEFolder create [lindex $fid 0] [join $fpath $result]} result]} { + lappend newmail [list "Create failed: $result"] + } else { + lappend newmail [list "Folder $folder created"] + } + } else { + lappend newmail [list "Folder creation failed: no folder name provided"] + } +} elseif {[string compare $newfolder Cancel] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + lappend newmail [list "Folder Create Cancelled"] +} elseif {[string compare [string range $import 0 5] Import] == 0} { + if {[catch {WPImport file "Missing File Upload"} errstr] == 0} { + set local_file [lindex $file 0] + + if {[catch {WPImport iname "import name"} errstr] == 0} { + set iname [string trim $iname] + + if {[string length $iname]} { + + set colid [lindex $fid 0] + set fldr [eval "file join [lrange $fid 1 end] $iname"] + + if {[catch {WPCmd PEFolder import $local_file $colid $fldr} errstr] == 0} { + lappend newmail [list "Imported folder $iname"] + } else { + lappend newmail [list "Can't Import File: $errstr"] + } + } else { + lappend newmail [list "Must provide uploaded folder name"] + } + } else { + lappend newmail [list "Can't get uploaded folder name"] + } + + catch {file delete -force $local_file} + } else { + lappend newmail [list "Problem uploading file"] + } +} elseif {[string compare [string range $newdir 0 5] Create] == 0} { + if {$cid != $key} { + lappend newmail [list "Invalid Command ID"] + } elseif {[string length $directory]} { + set fpath [lrange $fid 1 end] + lappend fpath "${directory}/" + if {[catch {WPCmd PEFolder delimiter [lindex $fid 0]} result] + || [catch {WPCmd PEFolder create [lindex $fid 0] [join $fpath $result]} result]} { + lappend newmail [list "Create failed: $result"] + } else { + lappend newmail [list "Folder $directory created"] + } + } else { + lappend newmail [list "Directory Create failed: no name provided"] + } +} elseif {[string compare $newdir Cancel] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + lappend newmail [list "Directory Creation Cancelled"] +} elseif {[string compare $cancelled Cancel] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + lappend newmail [list "New Folder or Directory Creation Cancelled"] +} elseif {[catch {WPCmd PEInfo set wp_folder_script} script] == 0} { + catch {WPCmd PEInfo unset wp_folder_script} + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) $script] + set nopage 1 +} else { + foreach i [cgi_import_list] { + switch -regexp -- $i { + ^new_[a-zA-Z0-9%_]*$ { + set fid [string range $i 4 end] + catch {WPCmd PEInfo set fid $fid} + catch {WPCmd PEInfo set wp_folder_script fr_querynewdir.tcl} + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_querynewfoldir.tcl] + set nopage 1 + } + ^nd_[a-zA-Z0-9%_]*$ { + set fid [string range $i 3 end] + catch {WPCmd PEInfo set fid $fid} + catch {WPCmd PEInfo set wp_folder_script fr_querynewdir.tcl} + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_querynewdir.tcl] + set nopage 1 + } + ^nf_[a-zA-Z0-9%_]*$ { + set fid [string range $i 3 end] + catch {WPCmd set fid $fid} + catch {WPCmd set wp_folder_script fr_querynewfldr.tcl} + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_querynewfldr.tcl] + set nopage 1 + } + ^imp_[a-zA-Z0-9%_]*$ { + set fid [string range $i 4 end] + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_queryimport.tcl] + set nopage 1 + } + default { + } + } + + catch {WPCmd PEInfo unset fid} + catch {WPCmd PEInfo unset wp_folder_script} + } +} + +if {[info exists nopage] == 0} { + if {$reload || $frestore || ([string length $show] == 0 && [string length $expand] == 0 && [string length $contract] == 0)} { + catch {set show [WPCmd PEInfo set fr_show] + set expand [WPCmd PEInfo set fr_expand] + set contract [WPCmd PEInfo set fr_contract]} + } else { + WPCmd set fr_show $show + WPCmd set fr_expand $expand + WPCmd set fr_contract $contract + } + + # collect top level folder lists + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + set shown [split $show ,] + set scroll {} + set anchorcnt 0 + + # mihodge: process actions + if {[llength $expand]} { + lappend shown $expand + set scroll $expand + } + + if {[llength $contract]} { + if {[set index [lsearch $shown $contract]] >= 0} { + set shown [lreplace $shown $index $index] + set scroll $contract + } + } + + set baseurl wp.tcl?page=folders& + + if {[llength $shown]} { + append baseurl "show=[WPPercentQuote [join $shown ,]]&" + } + + # build top-level collection's folder list + for {set i 0} {$i < [llength $collections]} {incr i} { + set col [lindex $collections $i] + set colid [lindex $col 0] + + if {[llength $collections] == 1} { + set flist 1 + } else { + if {[set index [lsearch $shown $colid]] < 0} { + set flist {} + } else { + set flist 1 + } + } + + if {[llength $flist]} { + if {[catch {WPCmd PEFolder list $colid} flist]} { + if {[string compare BADPASSWD [string range $flist 0 8]] == 0} { + # control error messages + set statmsgs [WPCmd PEInfo statmsgs] + WPCmd PEMailbox newmailreset + if {[catch {WPCmd PESession creds [lindex $expand 0] folder} creds] == 0 && $creds != 0} { + catch {WPCmd PEInfo statmsg "Invalid Username or Password"} + WPCmd PESession nocred $expand folder + } + + if {[catch {WPCmd PEFolder clextended} coln]} { + WPCmd set reason "Can't get Collection Info: $coln" + } else { + set coln [lindex $coln $expand] + if {[regexp {^([a-zA-Z\.]+).*\/user=([^ /]*)} [lindex $coln 4] dummy srvname authuser]} { + WPCmd set reason "Listing folders in the [cgi_bold [lindex $coln 1]] collection first requires that you log in to the server [cgi_bold "$srvname"]." + WPCmd set authuser $authuser + } else { + WPCmd set reason "Folders in the [cgi_bold [lindex $coln 1]] collection are on a server that must be logged into." + } + } + + WPCmd set cid [WPCmd PEInfo key] + WPCmd set authcol [lindex $expand 0] + WPCmd set authfolder folder + WPCmd set authpage [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders&expand=$expand"] + WPCmd set authcancel [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders"] + + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_queryauth.tcl] + + catch {WPCmd unset fr_expand} + + set nopage 1 + } else { + set flist {} + } + } + } + + lappend collectionfolders $flist + } +} + +if {[info exists nopage] == 0} { + # collect new mail message and errors + if {[catch {WPNewMail $reload} newmailmsg]} { + error [list _action "new mail" $newmailmsg] + } else { + foreach m $newmailmsg { + lappend newmail $m + } + + if {[info exists newmail] == 0} { + set newmail "" + } + } + + # paint the page + cgi_http_head { + WPStdHttpHdrs text/html + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Folder List" folders + + set onload "onLoad=" + set onunload "onUnload=" + set normalreload [cgi_buffer {WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders"}] + + if {[info exists _wp(exitonclose)]} { + WPExitOnClose + append onload "wpLoad();" + append onunload "wpUnLoad();" + + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function viewReloadTimer(t){" + cgi_put " reloadtimer = window.setInterval('wpLink(); window.location.replace(\\'[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders&reload=1\\')', t * 1000);" + cgi_puts "}" + } + + append onload "viewReloadTimer($_wp(refresh));" + cgi_noscript { + cgi_puts $normalreload + } + } else { + cgi_puts $normalreload + } + + WPStyleSheets + if {$_wp(keybindings)} { + set kequiv { + {{i} {top.location = 'fr_main.tcl'}} + {{a} {top.location = 'wp.tcl?page=addrbook'}} + {{?} {top.location = 'wp.tcl?page=help&oncancel=folders'}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=folders&cid=$key'"] + + append onload [WPTFKeyEquiv $kequiv] + } + } + + cgi_body bgcolor=$_wp(bordercolor) background=[file join $_wp(imagepath) logo $_wp(logodir) back.gif] "style=\"background-repeat: repeat-x\"" $onload $onunload { + + catch {WPCmd PEInfo set help_context folders} + + # prepare context and navigation information + + set mbox [WPCmd PEMailbox mailboxname] + + lappend pagehier [list "Folder List"] + lappend pagehier [list [cgi_bold "\[Return to $mbox\]"] fr_main.tcl "View list of messages"] + if {[string compare $oncancel view] == 0} { + if {$uid} { + set num [WPCmd PEMessage $uid number] + } else { + set num View + } + + lappend pagehier [list [cgi_bold "\[Return to Message $num\]"] view.tcl "View Message"] + } + + set navops "" + + WPTFTitle "Folder List" $newmail 0 "folders" + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + + cgi_table_row { + cgi_table_data valign=top class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=0 { + cgi_table_row { + cgi_table_data class=navbar "style=\"padding: 6 0 0 4\"" { + cgi_puts [cgi_span "style=font-weight: bold" "Current Folder"] + cgi_division align=center "style=margin-top:4;margin-bottom:4" { + set mbn [WPCmd PEMailbox mailboxname] + if {[string length $mbn] > 16} { + set mbn "[string range $mbn 0 14]..." + } + + cgi_put [cgi_url $mbn fr_main.tcl target=_top class=navbar] + + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + #cgi_put [cgi_span "style=color: black; border: 1px solid red; background-color: pink; font-weight: bold" "Read Only"] + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + #cgi_put [cgi_span "style=color: black; border: 1px solid red; background-color: pink; font-weight: bold" "Closed"] + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + + cgi_br + } + + cgi_hr "width=75%" + } + } + + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar style=padding-bottom:10 { + WPTFCommandMenu folder_menu common_menu + } + } + } + } + } + + # down the right side of the table is the window's contents + cgi_table_data width="100%" bgcolor=#ffffff valign=top { + + if {[llength $collections] > 1} { + cgi_division "style=\"font-family: helvetica; padding: 18; text-align: center\"" { + cgi_puts [cgi_span "style=font-weight: bold; font-size: 14pt; vertical-align: middle" "Folder Collections"] + cgi_br + cgi_puts [cgi_span "style=font-size: smaller" "(click to expand, open, delete, etc.)"] + } + } + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "cid=$key" type=hidden notab + cgi_text "frestore=1" type=hidden notab + # then the table representing the folders + cgi_table border=0 cellspacing=0 cellpadding=2 align=center { + for {set i 0} {$i < [llength $collections]} {incr i} { + set col [lindex $collections $i] + set colid [lindex $col 0] + + if {[llength $collections] == 1} { + set menu "c" + set flist 1 + } else { + if {[set index [lsearch $shown $colid]] < 0} { + set menu "ce" + set flist {} + } else { + set menu "cc" + set flist 1 + } + } + + cgi_table_row { + cgi_table_data nowrap valign=middle { + if {[WPCmd PEFolder isincoming $colid] == 0 && [llength $flist]} { + cgi_image_button delquery=[WPimg but_folddel] border=0 alt=Delete + cgi_image_button renquery=[WPimg but_foldren] border=0 alt=Rename style=margin-left:4 + cgi_image_button dwnquery=[WPimg but_foldexp] border=0 alt=Export style=margin-left:4 + } + } + + if {[llength $collections] > 1} { + if {[set index [lsearch $shown $colid]] < 0} { + set colpref [cgi_url [cgi_imglink expand] "${baseurl}expand=$colid" name=f_$colid] + } else { + set colpref [cgi_url [cgi_imglink contract] "${baseurl}contract=$colid" name=f_$colid] + } + } else { + set colpref "" + } + + cgi_table_data align=left "style=\"padding-left:10\"" nowrap { + if {[llength [lindex $collectionfolders $i]]} { + set flist [lindex $collectionfolders $i] + } + + cgi_puts ${colpref}[cgi_span "style=font-family:Helvetica; size: large; padding-left:10" "[lindex $col 1]"] + } + + if {[llength $flist]} { + if {[WPCmd PEFolder isincoming $colid] == 0} { + cgi_table_data valign=middle nowrap { + cgi_submit_button "new_$colid=Create New..." + cgi_submit_button "imp_$colid=Import..." + } + } + } + } + + if {[llength $flist]} { + blat_folder_list $colid $flist $shown $colid $baseurl $scroll anchorcnt 1 + } + + cgi_table_row { + cgi_table_data height=12 { + cgi_put [cgi_nbspace] + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/fr_addrbrowse.tcl b/web/cgi/alpine/1.0/fr_addrbrowse.tcl new file mode 100755 index 00000000..2e1d2504 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_addrbrowse.tcl @@ -0,0 +1,66 @@ +# $Id: fr_addrbrowse.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_addrbrowse.tcl +# +# Purpose: CGI script to generate frame set for selecting addresses +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {op "" ""} + {field "" ""} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=73 + cgi_frame subbody=wp.tcl?page=addrbook${parms} + } + } diff --git a/web/cgi/alpine/1.0/fr_addredit.tcl b/web/cgi/alpine/1.0/fr_addredit.tcl new file mode 100644 index 00000000..5836c001 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_addredit.tcl @@ -0,0 +1,86 @@ +# $Id: fr_addredit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_addredit.tcl +# +# Purpose: CGI script to generate frame set for address book operations +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {book {} -1} + {nick {} ""} + {add {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {take {} 0} + {newnick {} ""} + {ai {} -1} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + if {$add} { + set title 72 + } else { + set title 71 + } + + cgi_frame hdr=header.tcl?title=${title} + cgi_frame body=addredit.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_cledit.tcl b/web/cgi/alpine/1.0/fr_cledit.tcl new file mode 100755 index 00000000..60ae3909 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_cledit.tcl @@ -0,0 +1,79 @@ +#!./tclsh +# $Id: fr_cledit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_conf_process.tcl +# +# Purpose: CGI script to generate frame set for config operations +# in webpine-lite pages. +# This page assumes that it was loaded by conf_process.tcl + +# Input: +set frame_vars { +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +cgi_http_head { + WPStdHttpHdrs +} + + set add 0 + if {[info exists cledit_add] && $cledit_add == 1} { + set add 1 + } + cgi_html { + cgi_head { + WPStdHtmlHdr [expr {$add == 1 ? "Add Collection Configuration" : "Edit Collection Configuration"}] + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + if {0} { + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + } + + set title [expr {$add == 1 ? 151 : 152}] + set parms "" + if {[info exists cledit_add]} { + set parms "${parms}&add=${cledit_add}" + } + if {[info exists cledit_cl]} { + set parms "${parms}&cl=${cledit_cl}" + } + if {[info exists cledit_onclecancel]} { + set parms "${parms}&onclecancel=${cledit_onclecancel}" + } + + cgi_frame hdr=header.tcl?title=${title} + cgi_frame body=wp.tcl?page=cledit&cid=$cid&oncancel=$oncancel$parms + } + } + diff --git a/web/cgi/alpine/1.0/fr_compose.tcl b/web/cgi/alpine/1.0/fr_compose.tcl new file mode 100755 index 00000000..bcdd3c35 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_compose.tcl @@ -0,0 +1,144 @@ +# $Id: fr_compose.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_comp.tcl +# +# Purpose: CGI script to generate frame set for composer in +# webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "" 0} + {part "" ""} + {style "" ""} + {nickto "" ""} + {book "" 0} + {ai "" -1} + {notice "" ""} + {repall "" 0} + {reptext "" 0} + {repqstr "" ""} + {restore "" 0} + {f_name "" ""} + {f_colid "" 0} + {cid "Missing Command ID"} + {spell "" ""} + {oncancel "" "main.tcl"} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Import Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +switch -- $style { + Reply { + set title "40,[WPCmd PEMessage $uid number]" + } + Forward { + set title "30,[WPCmd PEMessage $uid number]" + } + Postponed { + set title "20," + } + Spell { + # validate input + set spellresult {} + if {[catch {cgi_import_as last_line last} result] == 0 && [regexp {^[0-9]+$} $last] && $last < 10000} { + array set replace {} + + for {set n 0} {$n < $last} {incr n} { + if {[catch {cgi_import_as l_$n locs} result] == 0} { + + set words {} + + foreach l [split $locs {,}] { + if {[regexp {[0-9]+_([0-9]+)_([0-9]+)} $l match o len]} { + if {[info exists replace($l)]} { + lappend words [list $o $len $replace($l)] + } elseif {([catch {cgi_import_as r_$l newword} result] == 0 && [string length [set newword [string trim $newword { }]]]) + || ([catch {cgi_import_as s_$l newword} result] == 0 && [string length [set newword [string trim $newword { }]]])} { + lappend words [list $o $len $newword] + if {[catch {cgi_import_as a_$l allofem} result] == 0 + && [string compare $allofem on] == 0 + && [catch {cgi_import_as e_$l allofem} result] == 0} { + foreach e [split $allofem {,}] { + set replace($e) $newword + } + } + } + } + } + + if {[llength $words]} { + lappend spellresult [list $n $words] + } + } + } + + if {[llength $spellresult]} { + catch {WPCmd PEInfo set wp_spellresult $spellresult} + } + } + + set title "10," + } + default { + set title "10," + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + WPStdHtmlHdr Compose + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms & + } else { + append parms ? + } + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + cgi_frame hdr=header.tcl?title=$title title="Composer Title" + cgi_frame body=compose.tcl${parms} title="Compose Form" + } +} diff --git a/web/cgi/alpine/1.0/fr_filtedit.tcl b/web/cgi/alpine/1.0/fr_filtedit.tcl new file mode 100755 index 00000000..41abee9b --- /dev/null +++ b/web/cgi/alpine/1.0/fr_filtedit.tcl @@ -0,0 +1,136 @@ +#!./tclsh +# $Id: fr_filtedit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_conf_process.tcl +# +# Purpose: CGI script to generate frame set for config operations +# in webpine-lite pages. +# This page assumes that it was loaded by conf_process.tcl + +# Input: +set frame_vars { +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl +source filter.tcl + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Filter Configuration" + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + if {[info exists filtedit_add] && 1 == $filtedit_add} { + set title 153 + } else { + set title 154 + } + + set parms "" + if {[info exists filtedit_add]} { + set parms "${parms}&add=${filtedit_add}" + } + if {[info exists filtedit_fno]} { + set parms "${parms}&fno=${filtedit_fno}" + } + if {[info exists filtedit_onfiltcancel]} { + set parms "${parms}&onfiltcancel=${filtedit_onfiltcancel}" + } + if {[info exists filtedit_indexcolor]} { + set parms "${parms}&filtedit_indexcolor=1" + if {[info exists fg] && [string length $fg]} { + set parms "${parms}&fg=$fg" + } + if {[info exists bg] && [string length $bg]} { + set parms "${parms}&bg=$bg" + } + if {[info exists fgorbg]} { + set parms "${parms}&fgorbg=$fgorbg" + } + } elseif {[info exists filtedit_score]} { + set parms "${parms}&filtedit_score=1" + if {[info exists scoreval] && [string length $scoreval]} { + set parms "${parms}&scoreval=$scoreval" + } + if {[info exists scorehdr] && [string length $scorehdr]} { + set parms "${parms}&scoreval=$scorehdr" + } + } + + if {[info exists filterrtext]} { + # relay pattern elements + set parms "${parms}&filterrtext=${filterrtext}" + foreach {pvar pexp} $pattern_id { + if {[info exists $pvar]} { + if {[string length [set pval [subst $$pvar]]]} { + append parms "&${pvar}=${pval}" + } + } + } + + foreach {pvar pexp} $pattern_fields { + if {[info exists $pvar]} { + if {[string length [set pval [subst $$pvar]]]} { + append parms "&${pvar}=${pval}" + } + } + } + + # relay various pattern actions + if {[info exists action] || 0 == [catch {WPImport action}]} { + append parms "&action=$action" + } + + if {0 == [catch {WPImport actionfolder}]} { + append parms "&actionfolder=$actionfolder" + } + + if {0 == [catch {WPImport moind}] && [string length $moind]} { + append parms "&moind=$moind" + } + + if {0 == [catch {WPImport actionfolder}]} { + append parms "&actionfolder=$actionfolder" + } + + if {[info exists folder] == 0} { + wpGetVarAs folder folder + } + + if {[string length $folder]} { + append parms "&folder=$folder" + } + + if {[info exists ftype] == 0} { + wpGetVarAs ftype ftype + } + + if {[string length $ftype]} { + append parms "&ftype=$ftype" + } + } + + cgi_frame hdr=header.tcl?title=${title} + cgi_frame body=wp.tcl?page=filtedit&cid=$cid&oncancel=$oncancel$parms + } + } + diff --git a/web/cgi/alpine/1.0/fr_flags.tcl b/web/cgi/alpine/1.0/fr_flags.tcl new file mode 100755 index 00000000..febc2eaf --- /dev/null +++ b/web/cgi/alpine/1.0/fr_flags.tcl @@ -0,0 +1,67 @@ +#!./tclsh +# $Id: fr_flags.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_flags.tcl +# +# Purpose: CGI script to generate frame set for flag setting +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "Missing UID"} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $frame_vars { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=160 + cgi_frame subbody=flags.tcl${parms} + } + } +} diff --git a/web/cgi/alpine/1.0/fr_fldrbrowse.tcl b/web/cgi/alpine/1.0/fr_fldrbrowse.tcl new file mode 100644 index 00000000..9373e5ff --- /dev/null +++ b/web/cgi/alpine/1.0/fr_fldrbrowse.tcl @@ -0,0 +1,71 @@ +# $Id: fr_fldrbrowse.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_fldrbrowse.tcl +# +# Purpose: CGI script to generate frame set for selecting a folder from the user's +# defined collections in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {onselect "" main} + {oncancel "" main} + {target "" ""} + {controls "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + + switch $controls { + 2 { set tnum 221 } + default {set tnum 220} + } + + cgi_frame subhdr=header.tcl?title=${tnum} title="Folder Selection for Save" + cgi_frame subbody=wp.tcl?page=fldrbrowse${parms} title="Folder Selection Frame" + } +} diff --git a/web/cgi/alpine/1.0/fr_fldrsavenew.tcl b/web/cgi/alpine/1.0/fr_fldrsavenew.tcl new file mode 100644 index 00000000..f59a8914 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_fldrsavenew.tcl @@ -0,0 +1,65 @@ +# $Id: fr_fldrsavenew.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_fldrcreate.tcl +# +# Purpose: CGI script to generate frame set for creating a new folder to save to + +# Input: +set frame_vars { + {onselect "" main} + {oncancel "" main} + {target "" ""} + {controls "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + + switch $controls { + 2 { set tnum 223 } + default {set tnum 222} + } + + cgi_frame subhdr=header.tcl?title=${tnum} title="Folder Creation for Save" + cgi_frame subbody=wp.tcl?page=fldrsavenew${parms} title="Folder Creation Frame" + } +} diff --git a/web/cgi/alpine/1.0/fr_help.tcl b/web/cgi/alpine/1.0/fr_help.tcl new file mode 100755 index 00000000..a6f7e388 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_help.tcl @@ -0,0 +1,91 @@ +# $Id: fr_help.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_help.tcl +# +# Purpose: CGI script to generate frame set for display of help text +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {topic "" ""} + {index "" ""} + {oncancel "" ""} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + cgi_title "WebPine Help" + } + + cgi_frameset "rows=$_wp(titleheight),0,*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists help_vars]} { + foreach v $help_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + lappend parmlist [lindex $v 0] + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {(![info exists parmlist] || [lsearch -exact $parmlist [lindex $v 0]] < 0) && [string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + cgi_frame hdr=header.tcl?title=140 title="Help Title" + cgi_frame noop=wp.tcl?page=noop + cgi_frame body=help.tcl$parms title="Help Body" + } +} diff --git a/web/cgi/alpine/1.0/fr_index.tcl b/web/cgi/alpine/1.0/fr_index.tcl new file mode 100755 index 00000000..92b34184 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_index.tcl @@ -0,0 +1,58 @@ +#!./tclsh +# $Id: fr_index.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_index.tcl +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages + +# Input: +set index_vars { + {expunge ""} + {emptyit ""} + {f_colid {} ""} + {f_name {} ""} + {cid {} 0} + {split {} 0} +} + +# Output: +# + +# read config +source ./alpine.tcl + +WPEval $index_vars { + cgi_http_head { + WPStdHttpHdrs {} 10 + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=100%,*" border=0 frameborder=0 framespacing=0 { + set parms "" + if {[info exists index_vars]} { + foreach v $index_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame body=wp.tcl?page=index${parms} title="Message List" + } + } +}
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/fr_ldapbrowse.tcl b/web/cgi/alpine/1.0/fr_ldapbrowse.tcl new file mode 100755 index 00000000..c6ac8c59 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_ldapbrowse.tcl @@ -0,0 +1,61 @@ +# $Id: fr_ldapbrowse.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_ldapbrowse.tcl +# +# Purpose: CGI script to generate frame set for selecting addresses +# from an LDAP query in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: (NOTE: these are expected to be set when we get here) +set frame_vars { + {ldapquery "" ""} + {addresses "" ""} + {field "" ""} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=74 + cgi_frame subbody=ldapbrowse.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_ldapquery.tcl b/web/cgi/alpine/1.0/fr_ldapquery.tcl new file mode 100644 index 00000000..b2b90e24 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_ldapquery.tcl @@ -0,0 +1,75 @@ +# $Id: fr_ldapquery.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_ldapquery.tcl +# +# Purpose: CGI script to generate frame set for LDAP server query +# handling in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {dir "Missing Directory Index"} + {srchstr {} ""} + {field {} ""} + {op {} ""} + {searchtype {} ""} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + cgi_frame hdr=header.tcl?title=240 + cgi_frame body=ldapquery.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_main.tcl b/web/cgi/alpine/1.0/fr_main.tcl new file mode 100755 index 00000000..8654ab69 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_main.tcl @@ -0,0 +1,34 @@ +#!./tclsh +# $Id: fr_main.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_main.tcl - frame set for Index and View +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages + +# Input: +set frame_vars { + {expunge {} 0} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl + + +WPEval $frame_vars { + source main.tcl +} diff --git a/web/cgi/alpine/1.0/fr_promptsave.tcl b/web/cgi/alpine/1.0/fr_promptsave.tcl new file mode 100755 index 00000000..4bbf040b --- /dev/null +++ b/web/cgi/alpine/1.0/fr_promptsave.tcl @@ -0,0 +1,68 @@ +# $Id: fr_promptsave.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_promptsave.tcl +# +# Purpose: CGI script to generate frame set for resume composition form +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=3 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=190 + cgi_frame subbody=promptsave.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_queryattach.tcl b/web/cgi/alpine/1.0/fr_queryattach.tcl new file mode 100755 index 00000000..8cbdc015 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryattach.tcl @@ -0,0 +1,70 @@ +# $Id: fr_queryattach.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryattach.tcl +# +# Purpose: CGI script to generate frame set for specifying an attachment +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=110 + cgi_frame subbody=queryattach.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_queryauth.tcl b/web/cgi/alpine/1.0/fr_queryauth.tcl new file mode 100755 index 00000000..ad5d13d1 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryauth.tcl @@ -0,0 +1,71 @@ +# $Id: fr_queryauth.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryauth.tcl +# +# Purpose: CGI script to generate frame set for input of user/passwd +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {cid "Missing Command ID"} + {authcol "Missing Authenticaion Collection"} + {authfolder "Missing Authentication Folder"} + {authpage "Missing Post Authorization Instructions"} + {authcancel "Missing Auth Cancel Instructions"} + {authuser "" ""} + {reason "" ""} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame hdr=header.tcl?title=130 title="Status Frame" + cgi_frame body=$_wp(serverpath)/session/queryauth.tcl?sessid=$_wp(sessid)${parms} title="User and Password Prompt" + } +} diff --git a/web/cgi/alpine/1.0/fr_querycreate.tcl b/web/cgi/alpine/1.0/fr_querycreate.tcl new file mode 100755 index 00000000..b3ff332c --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querycreate.tcl @@ -0,0 +1,42 @@ +# $Id: fr_querycreate.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querycreate.tcl +# +# Purpose: CGI script to generate frame set for creation confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=120 title="Status Frame" + cgi_frame subbody=querycreate.tcl title="Creation Confirmation Prompt" + } +} diff --git a/web/cgi/alpine/1.0/fr_querydelfldr.tcl b/web/cgi/alpine/1.0/fr_querydelfldr.tcl new file mode 100755 index 00000000..653c52cb --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querydelfldr.tcl @@ -0,0 +1,43 @@ +# $Id: fr_querydelfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querydelfldr.tcl +# +# Purpose: CGI script to generate frame set for folder delete confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=170 + cgi_frame subbody=querydelfldr.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_queryexpunge.tcl b/web/cgi/alpine/1.0/fr_queryexpunge.tcl new file mode 100755 index 00000000..704c12c7 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryexpunge.tcl @@ -0,0 +1,71 @@ +# $Id: fr_queryexpunge.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_expunge.tcl +# +# Purpose: CGI script to generate frame set for expunge confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + WPCmd PEInfo set wp_spec_script fr_queryexpunge.tcl + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=90 + cgi_frame subbody=queryexpunge.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_queryimport.tcl b/web/cgi/alpine/1.0/fr_queryimport.tcl new file mode 100644 index 00000000..d4e7ee28 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryimport.tcl @@ -0,0 +1,44 @@ +# $Id: fr_queryimport.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryimport.tcl +# +# Purpose: CGI script to generate frame set for specifying a folder +# to upload and import to a collection. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + cgi_frame subhdr=header.tcl?title=250 title="Folder Import Dialog" + cgi_frame subbody=queryimport.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_querynewdir.tcl b/web/cgi/alpine/1.0/fr_querynewdir.tcl new file mode 100755 index 00000000..a8f54899 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querynewdir.tcl @@ -0,0 +1,43 @@ +# $Id: fr_querynewdir.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querynewdir.tcl +# +# Purpose: CGI script to generate frame set for Directory create confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=172 + cgi_frame subbody=querynewdir.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_querynewfldr.tcl b/web/cgi/alpine/1.0/fr_querynewfldr.tcl new file mode 100755 index 00000000..6bc17b42 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querynewfldr.tcl @@ -0,0 +1,43 @@ +# $Id: fr_querynewfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querynewfldr.tcl +# +# Purpose: CGI script to generate frame set for folder create confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=171 + cgi_frame subbody=querynewfldr.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_querynewfoldir.tcl b/web/cgi/alpine/1.0/fr_querynewfoldir.tcl new file mode 100755 index 00000000..fc6a61b7 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querynewfoldir.tcl @@ -0,0 +1,43 @@ +# $Id: fr_querynewfoldir.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querynewfoldir.tcl +# +# Purpose: CGI script to generate frame set for Folder/Directory create confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=174 + cgi_frame subbody=querynewfoldir.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_queryprune.tcl b/web/cgi/alpine/1.0/fr_queryprune.tcl new file mode 100644 index 00000000..20e9638c --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryprune.tcl @@ -0,0 +1,66 @@ +# $Id: fr_queryprune.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryprune.tcl +# +# Purpose: CGI script to generate frame set for pruning dialog +# in webpine. + +# Input: +set frame_vars { + {cid "Missing Command ID"} + {start "Missing Start Page"} + {nojs "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } + + append parms "[lindex $v 0]=[WPPercentQuote [subst $[lindex $v 0]]]" + } + } + } + + cgi_frame hdr=header.tcl?title=260 title="Folder Pruning Frame" + cgi_frame body=queryprune.tcl?sessid=$_wp(sessid)&${parms} title="Folder Pruning Dialog" + } +} diff --git a/web/cgi/alpine/1.0/fr_queryquit.tcl b/web/cgi/alpine/1.0/fr_queryquit.tcl new file mode 100644 index 00000000..4f12e8ba --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryquit.tcl @@ -0,0 +1,70 @@ +# $Id: fr_queryquit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryquit.tcl +# +# Purpose: CGI script to generate frame set for logging out of a session +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {cid "Missing Command ID"} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + cgi_http_equiv Refresh "$_wp(logoutpause); url=$_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}" + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=3 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=230 + cgi_frame subbody=queryquit.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_queryrenfldr.tcl b/web/cgi/alpine/1.0/fr_queryrenfldr.tcl new file mode 100755 index 00000000..a498700c --- /dev/null +++ b/web/cgi/alpine/1.0/fr_queryrenfldr.tcl @@ -0,0 +1,43 @@ +# $Id: fr_queryrenfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_queryrenfldr.tcl +# +# Purpose: CGI script to generate frame set for folder rename confirmation +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {fid "No Folder Specified"} +} + +# Output: +# + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + cgi_frame subhdr=header.tcl?title=173 + cgi_frame subbody=queryrenfldr.tcl?fid=$fid + } +} diff --git a/web/cgi/alpine/1.0/fr_querysave.tcl b/web/cgi/alpine/1.0/fr_querysave.tcl new file mode 100755 index 00000000..af8e8c88 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_querysave.tcl @@ -0,0 +1,68 @@ +# $Id: fr_querysave.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_querysave.tcl +# +# Purpose: CGI script to generate frame set for resume composition form +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=3 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=90 + cgi_frame subbody=querysave.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_resume.tcl b/web/cgi/alpine/1.0/fr_resume.tcl new file mode 100755 index 00000000..3e332cae --- /dev/null +++ b/web/cgi/alpine/1.0/fr_resume.tcl @@ -0,0 +1,104 @@ +# $Id: fr_resume.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_resume.tcl +# +# Purpose: CGI script to generate frame set for resume composition form +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {oncancel "" main} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +proc ppnd_uid {ppnd} { + foreach i $ppnd { + switch -- [lindex $i 0] { + uid { + return [lindex $i 1] + } + } + } + + error "No Valid UID for Postponed message" +} + + +if {[catch {WPLoadCGIVar cid} result]} { + catch {WPCmd PEInfo statmsg "Missing Command ID: $result"} + source [WPTFScript $oncancel] +} elseif {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} + source [WPTFScript $oncancel] +} elseif {[catch {WPCmd PEPostpone count} postponed]} { + catch {WPCmd PEInfo statmsg "Resume Error: $postponed"} + source [WPTFScript $oncancel] +} else { + switch -- $postponed { + -1 - + 0 { + catch {WPCmd PEInfo statmsg "No Postponed Messages"} + source [WPTFScript $oncancel] + } + default { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame hdr=header.tcl?title=80 title="Status Frame" + cgi_frame body=resume.tcl${parms} title="Resumable Message List" + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/fr_seldate.tcl b/web/cgi/alpine/1.0/fr_seldate.tcl new file mode 100755 index 00000000..99f0a933 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_seldate.tcl @@ -0,0 +1,70 @@ +# $Id: fr_seldate.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_seldate.tcl +# +# Purpose: CGI script to generate frame set for selecting by date +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=101 + cgi_frame subbody=seldate.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_select.tcl b/web/cgi/alpine/1.0/fr_select.tcl new file mode 100755 index 00000000..8b70d23a --- /dev/null +++ b/web/cgi/alpine/1.0/fr_select.tcl @@ -0,0 +1,71 @@ +# $Id: fr_select.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_select.tcl +# +# Purpose: CGI script to generate frame set for selecting by the various methods +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=104 title="Status Frame" + cgi_frame subbody=select.tcl${parms} title="Search Criteria" + } +} diff --git a/web/cgi/alpine/1.0/fr_selstat.tcl b/web/cgi/alpine/1.0/fr_selstat.tcl new file mode 100755 index 00000000..317684fd --- /dev/null +++ b/web/cgi/alpine/1.0/fr_selstat.tcl @@ -0,0 +1,71 @@ +# $Id: fr_selstat.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_selstat.tcl +# +# Purpose: CGI script to generate frame set for selecting by status +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=103 + cgi_frame subbody=selstat.tcl${parms} + } + } diff --git a/web/cgi/alpine/1.0/fr_seltext.tcl b/web/cgi/alpine/1.0/fr_seltext.tcl new file mode 100755 index 00000000..644ed353 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_seltext.tcl @@ -0,0 +1,71 @@ +# $Id: fr_seltext.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_seltext.tcl +# +# Purpose: CGI script to generate frame set for selecting by text +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "" 0} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=102 + cgi_frame subbody=seltext.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_spellcheck.tcl b/web/cgi/alpine/1.0/fr_spellcheck.tcl new file mode 100755 index 00000000..bdd64e07 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_spellcheck.tcl @@ -0,0 +1,71 @@ +# $Id: fr_spellcheck.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_spellcheck.tcl +# +# Purpose: CGI script to generate frame set for spell checking composition +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {repqstr "" ""} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame hdr=header.tcl?title=180 + cgi_frame body=spellcheck.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_split.tcl b/web/cgi/alpine/1.0/fr_split.tcl new file mode 100644 index 00000000..1861ad35 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_split.tcl @@ -0,0 +1,58 @@ +# $Id: fr_split.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_split.tcl +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages + +# Input: +set split_vars { +} + +# Output: +# + +## read vars +foreach item $split_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs {} 10 +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=33%,*" { + set parms "" + if {[info exists split_vars]} { + foreach v $split_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame fr_top=wp.tcl?page=index&split=1${parms} title="Message List" + cgi_frame fr_bottom=fr_view.tcl?split=1${parms} title="Message View" + } +} diff --git a/web/cgi/alpine/1.0/fr_take.tcl b/web/cgi/alpine/1.0/fr_take.tcl new file mode 100644 index 00000000..b5a37ebb --- /dev/null +++ b/web/cgi/alpine/1.0/fr_take.tcl @@ -0,0 +1,70 @@ +# $Id: fr_take.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_take.tcl +# +# Purpose: CGI script to generate frame set for taking addresses +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {uid "Missing UID"} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=210 + cgi_frame subbody=takeaddr.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_takeedit.tcl b/web/cgi/alpine/1.0/fr_takeedit.tcl new file mode 100644 index 00000000..a339bafe --- /dev/null +++ b/web/cgi/alpine/1.0/fr_takeedit.tcl @@ -0,0 +1,79 @@ +# $Id: fr_takeedit.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_takeedit.tcl +# +# Purpose: CGI script to generate frame set for taking addresses +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {book "Missing address book"} + {nick {} ""} + {add {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {take {} 0} + {newnick {} ""} + {ai {} -1} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=211 + cgi_frame subbody=addredit.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_takesame.tcl b/web/cgi/alpine/1.0/fr_takesame.tcl new file mode 100644 index 00000000..fb69a4aa --- /dev/null +++ b/web/cgi/alpine/1.0/fr_takesame.tcl @@ -0,0 +1,79 @@ +# $Id: fr_takesame.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_takeedit.tcl +# +# Purpose: CGI script to generate frame set for taking addresses +# in webpine-lite pages. the idea is that this +# page specifies a frameset that loads a "header" page +# used to keep the servlet alive via +# periodic reloads and a "body" page containing static/form +# elements that can't/needn't be periodically reloaded or +# is blocked on user input. + +# Input: +set frame_vars { + {book "Missing address book"} + {nick {} ""} + {add {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {take {} 0} + {newnick {} ""} + {ai {} -1} +} + +# Output: +# + +## read vars +foreach item $frame_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +cgi_html { + cgi_head { + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + + set parms "" + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + cgi_frame subhdr=header.tcl?title=212 + cgi_frame subbody=querynick.tcl${parms} + } +} diff --git a/web/cgi/alpine/1.0/fr_tconfig.tcl b/web/cgi/alpine/1.0/fr_tconfig.tcl new file mode 100755 index 00000000..a7d62244 --- /dev/null +++ b/web/cgi/alpine/1.0/fr_tconfig.tcl @@ -0,0 +1,69 @@ +#!./tclsh +# $Id: fr_tconfig.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_conf_process.tcl +# +# Purpose: CGI script to generate frame set for config operations +# in webpine-lite pages. +# This page assumes that it was loaded by conf_process.tcl + +# Intput: +set frame_vars { +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Configuration" + } + + cgi_frameset "rows=$_wp(titleheight),*" resize=yes border=0 frameborder=0 framespacing=0 { + if {0} { + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + if {[string length $parms]} { + append parms "&" + } else { + append parms "?" + } + + append parms "[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + } + + set title 150 + + set vlavarstr "" + if {[info exists fr_tconfig_vlavar]} { + set vlavarstr "&vlavar=$fr_tconfig_vlavar" + } + cgi_frame hdr=header.tcl?title=${title} title="Status Frame" + cgi_frame body=wp.tcl?page=tconfig&newconf=$newconf&oncancel=$oncancel&wv=$conftype$vlavarstr title="Configuration options" + } + } + diff --git a/web/cgi/alpine/1.0/fr_view.tcl b/web/cgi/alpine/1.0/fr_view.tcl new file mode 100755 index 00000000..a4258baa --- /dev/null +++ b/web/cgi/alpine/1.0/fr_view.tcl @@ -0,0 +1,30 @@ +#!./tclsh +# $Id: fr_view.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# fr_view.tcl - wrapper around do_view.tcl to start tcl interp +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages + +# Input: + +# Output: +# + +# inherit global config +source ./alpine.tcl + +WPEval {} { + source do_view.tcl +} diff --git a/web/cgi/alpine/1.0/genvars.tcl b/web/cgi/alpine/1.0/genvars.tcl new file mode 100755 index 00000000..b982aee9 --- /dev/null +++ b/web/cgi/alpine/1.0/genvars.tcl @@ -0,0 +1,114 @@ +# $Id: genvars.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +set general_vars { + {var personal-name "Name"} + {var user-domain "User Domain"} + {var inbox-path "Inbox Location"} + {var default-fcc "Default Fcc"} + {var postponed-folder "Default Postponed Folder"} + {var alt-addresses "Other Addresses"} + {var wp-indexheight "Font Size"} + {var smtp-server "SMTP Server"} + {feat enable-newmail-sound "Enable Background Sound on New Mail Arrival"} + {feat enable-flag-cmd "Enable Flag Command"} + {feat auto-move-read-msgs "Automatically Move Read Messages"} + {feat expunge-without-confirm "Expunge INBOX Without Confirming"} + {feat expunge-without-confirm-everywhere "Expunge Everywhere Without Confirming"} + {feat quit-without-confirm "Quit Without Confirming"} + {feat enable-jump-cmd "Enable Jump Command"} + {special wp-columns "Display Width"} + {special left-column-folders "Message View/List Folder List Count"} +} + +set msglist_vars { + {special index-format "Message Line Format"} + {var sort-key "Sort By"} + {var incoming-startup-rule "Start At"} + {var wp-indexlines "Message Lines Displayed"} + {feat mark-for-cc "Mark Messages For Cc"} + {feat enable-aggregate-command-set "Enable Aggregate Commands"} + {feat auto-zoom-after-select "Zoom View after Search"} + {feat auto-unselect-after-apply "Unmark Messages After Command"} +} + +set composer_vars { + {special signature "Signature"} + {var default-composer-hdrs "Default Composer Headers"} + {var customized-hdrs "Customized Headers"} + {var fcc-name-rule "Fcc name rule"} + {var empty-header-message "Empty Header Message"} + {var posting-character-set "Posting Character Set"} + {feat compose-rejects-unqualified-addrs "Compose Rejects Unqualified Addresses"} + {feat enable-sigdashes "Enable Sigdashes"} + {feat quell-user-lookup-in-passwd-file "Don't Look Up Users in passwd File"} + {var reply-indent-string "Reply Indent String"} + {feat enable-reply-indent-string-editing "Enable Reply Indent String Editing"} + {var reply-leadin "Reply Leadin"} + {feat include-attachments-in-reply "Include Attachments in Reply"} + {feat include-header-in-reply "Include Header in Reply"} + {feat include-text-in-reply "Include Text in Reply"} + {feat signature-at-bottom "Signature at Bottom"} + {feat strip-from-sigdashes-on-reply "Strip From Sigdashes on Reply"} + {feat fcc-without-attachments "Fcc Without Attachments"} + {feat enable-8bit-esmtp-negotiation "Enable 8bit ESMTP Negotiation"} + {feat enable-delivery-status-notification "Enable Delivery Status Notification"} + {feat enable-verbose-smtp-posting "Enable Verbose SMTP Posting"} + {feat use-sender-not-x-sender "Use Sender, Not X-Sender"} + {feat send-confirms-only-expanded "Confirm Send only if Addresses Expanded"} + {feat quell-content-id "Prevent Content-ID header in Attachments"} + {feat quell-format-flowed "Do Not Send Flowed Text"} + {feat forward-as-attachment "Forward message as attachment"} +} + +set folder_vars { + {special collections "Folder Collections"} + {var default-fcc "Default Fcc"} + {var default-saved-msg-folder "Default Saved Message Folder"} + {var saved-msg-name-rule "Saved Message Name Rule"} + {var postponed-folder "Postponed Folder"} + {var read-message-folder "Read Messages Folder"} + {var form-letter-folder "Form Letter Folder"} + {var folder-sort-rule "Folder Sort Rule"} + {var incoming-folders "Incoming Folders"} + {var pruned-folders "Pruned Folders"} + {var pruning-rule "Pruning Rule"} + {feat prune-uses-yyyy-mm "Prune Uses YYYY-MM"} + {feat enable-dot-folders "Enable Hidden Folders"} + {feat enable-lame-list-mode "Enable Lame List Mode"} + {feat try-alternative-authentication-driver-first "Try Alternative Authentication First"} + {feat quell-empty-directories "Do Not Display Empty Directores"} +} + +set address_vars { + {var address-book "Address Books"} + {var global-address-book "Global Address Books"} + {var addrbook-sort-rule "Address Book Sort Rule"} + {var ldap-servers "Directory Servers"} +} + +set msgview_vars { + {special view-colors "Message View Color Settings"} + {var viewer-hdrs "Viewer Headers"} + {feat enable-msg-view-urls "Enable URLs"} + {feat enable-msg-view-web-hostnames "Enable Web Hostnames"} + {feat enable-msg-view-addresses "Enable Address Links"} + {feat enable-msg-view-attachments "Enable Attachments View"} + {feat enable-full-header-cmd "Enable Full Headers"} + {feat quell-host-after-url "Hide server name display after links in HTML"} +} + +set rule_vars { + {special filters "Filters"} + {special scores "Scoring"} + {special indexcolor "Index Colors"} +} diff --git a/web/cgi/alpine/1.0/header.tcl b/web/cgi/alpine/1.0/header.tcl new file mode 100755 index 00000000..8bff53e6 --- /dev/null +++ b/web/cgi/alpine/1.0/header.tcl @@ -0,0 +1,226 @@ +#!./tclsh +# $Id: header.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# header.tcl +# +# Purpose: CGI script to generate generic header for +# webpine-lite pages. the idea is that this +# page goes in the {title,nav}-bar portion of a +# framed page so we keep the servlet alive via +# periodic reloads while more static/form stuff +# is displayed in the "body" frame. + +# Input: +set header_vars { + {title "" "0,0"} + {reload} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set nologo 0 +set about {} + +WPEval $header_vars { + + set tv [split $title ","] + switch -- [lindex $tv 0] { + 10 { + set title_text "Compose New Message" + } + 20 { + set title_text "Postponed Message" + } + 30 { + set title_text "Forward Message" + if {[regexp {^[0-9]*$} [lindex $tv 1]]} { + append title_text " [lindex $tv 1]" + } + } + 40 { + set title_text "Reply to Message" + if {[regexp {^[0-9]*$} [lindex $tv 1]]} { + append title_text " [lindex $tv 1]" + } + } + 50 { + set title_text "Message Index" + set nologo 1 + } + 60 { + set title_text "Help System" + } + 70 { + set title_text "Address Books" + } + 71 { + set title_text "Edit Address Book Entry" + } + 72 { + set title_text "New Address Book Entry" + } + 73 { + set title_text "Address Selection" + } + 74 { + set title_text "LDAP Query Result Selection" + } + 80 { + set title_text "Select Postponed Message" + } + 90 { + set title_text "Expunge Deleted Messages" + set nologo 1 + } + 101 { + set title_text "Select Messages by Date" + set nologo 1 + } + 102 { + set title_text "Select Messages by Text" + set nologo 1 + } + 103 { + set title_text "Select Messages by Status" + set nologo 1 + } + 104 { + set title_text "Search and Mark Messages" + set nologo 1 + } + 110 { + set title_text "Attach a File" + } + 120 { + set title_text "File Creation Confirmation" + set nologo 1 + } + 130 { + set title_text "Authentication Required" + } + 140 { + set title_text "Web Alpine Help" + } + 150 { + set title_text "Configuration" + } + 151 { + set title_text "Add Collection Configuration" + } + 152 { + set title_text "Edit Collection Configuration" + } + 153 { + set title_text "Add Filter Configuration" + } + 154 { + set title_text "Edit Filter Configuration" + } + 160 { + set title_text "Set Message Flags" + set nologo 1 + } + 170 { + set title_text "Confirm Folder Delete" + } + 171 { + set title_text "New Folder Creation" + } + 172 { + set title_text "New Directory Creation" + } + 173 { + set title_text "Folder Rename" + } + 174 { + set title_text "Create New Folder or Directory" + } + 180 { + set title_text "Spell Check Composition" + } + 190 { + set title_text "Save Messages" + set nologo 1 + } + 200 { + set title_text "Attachment Display" + } + 210 { + set title_text "Take Addresses" + } + 211 { + set title_text "Take Address Edit" + } + 212 { + set title_text "Take Address Same Nickname" + } + 220 { + set title_text "Folder List for Save" + set nologo 1 + } + 221 { + set title_text "Folder List for Save" + } + 222 { + set title_text "Folder To Save To" + set nologo 1 + } + 223 { + set title_text "Folder To Save To" + } + 230 { + set title_text "Quitting Web Alpine" + } + 240 { + set title_text "LDAP Query" + } + 250 { + set title_text "Folder Upload and Import" + } + 260 { + set title_text "Monthly Folder Clean Up" + } + default { + if {[catch {WPCmd PEInfo set wp_header_title} title_text]} { + set title_text Untitled + } + } + } + + WPCmd PEInfo set wp_header_title $title_text + + if {[catch {WPNewMail $reload} newmail]} { + error [list _action "new mail" $newmail] + } + + cgi_http_head { + WPStdHttpHdrs text/html + } + + cgi_html { + cgi_head { + WPStdHtmlHdr Header + WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/header.tcl?sessid=$sessid" + WPStyleSheets + } + + cgi_body bgcolor=$_wp(bordercolor) background=[file join $_wp(imagepath) logo $_wp(logodir) back.gif] "style=\"background-repeat: repeat-x\"" { + WPTFTitle $title_text $newmail $nologo $about + } + } +} diff --git a/web/cgi/alpine/1.0/help.tcl b/web/cgi/alpine/1.0/help.tcl new file mode 100755 index 00000000..6881895d --- /dev/null +++ b/web/cgi/alpine/1.0/help.tcl @@ -0,0 +1,36 @@ +#!./tclsh +# $Id: help.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# help.tcl +# +# Purpose: CGI script to generate html help text for Alpine + +# Input: +set help_vars { + {topic {} ""} + {topicclass {} ""} + {index {} ""} + {oncancel {} main} + {params {} ""} +} + +# Output: +# +# HTML/Javascript/CSS help text for alpine + +# inherit global config +source ./alpine.tcl + +WPEval $help_vars { + source do_help.tcl +} diff --git a/web/cgi/alpine/1.0/help/about.tcl b/web/cgi/alpine/1.0/help/about.tcl new file mode 100644 index 00000000..44d28a12 --- /dev/null +++ b/web/cgi/alpine/1.0/help/about.tcl @@ -0,0 +1,30 @@ +# $Id: about.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +cgi_h2 "About Web Alpine" +cgi_p "Version [WPCmd PEInfo version].[WPCmd PEInfo revision] (basic HTML interface)" +cgi_p { +Web Alpine is a mail user agent, built on the Alpine Mail System, designed to +provide email access and management facilities via the World Wide Web. +As a web-based application, Alpine provides universal, convenient, and +secure access to your email environment. +} +cgi_p {Because its foundation is shared +with the Alpine Mail System, Web Alpine can easily provide a view of your email +environment consistent with that of Alpine and PC-Alpine. However, due to +inherent speed and efficiency limitations of web email, it is not intended +to replace any other email programs. Web Alpine is designed specifically for +those away from their own desktop computers and for people with light duty +email needs. +} +cgi_p { +} +cgi_p "Send comments and suggestions to [cgi_quote_html "<$_wp(comments)>"]." diff --git a/web/cgi/alpine/1.0/help/addrbook.html b/web/cgi/alpine/1.0/help/addrbook.html new file mode 100644 index 00000000..11399f33 --- /dev/null +++ b/web/cgi/alpine/1.0/help/addrbook.html @@ -0,0 +1,61 @@ +<!-- +# $Id: addrbook.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Address Books</b></font> + +<p>The Address Books screen provides a listing of addresses and contact information. If you have +more than one address book, your "Read-Only" books will be listed directly beneath your personal +listing.</p> + +<ul type="square"> +<li><a href="#add"><b>Adding an entry</b></a></li> +<li><a href="#remove"><b>Removing an entry</b></a></li> +<li><a href="#edit"><b>Editing an entry</b></a></li> +<li><a href="#create"><b>Creating a distribution list</b></a></li> +<li><a href="#compose"><b>Going directly to Message Compose</b></a></li> +</ul> + +<a name="add"><b>Adding an entry</b></a><br> +Click <input type=submit value="Add New Entry"> to go to a screen that includes the following +fields: "Nickname:", "Full Name:", "Addresses:", "Fcc:", "Comments:". +Complete the information that you want to save in your address book and +click <input type=submit value="Save Entry"> to add an entry to your personal addressbook. + +<p>For more information about these fields, see the <a href="addrentry.html">Address Book Entry</a> +help text.</p> + +<p> +<a name="remove"><b>Removing an entry</b></a><br> +Click the nickname of an entry you would like to remove. On the next +screen, click <input type=submit value="Delete Entry">. +<p> + +<a name="edit"><b>Editing an entry</b></a><br> +Click the nickname of an entry you would like to edit. On the next +screen, make your desired changes and click <input type=submit value="Save Entry">. +<p> + +<a name="create"><b>Creating a distribution list</b></a><br> +Click <input type=submit value="Add New Entry"> to go to a screen that includes the following +fields: "Nickname:", "Full Name:", "Addresses:", "Fcc:", "Comments:". +Complete the information that you want to save in your +address book. Include the addresses for your distribution (or group +mailing) list in the "Addresses:" field, separating each address by a +comma. Use a Nickname and Full Name that will be meaningful for you for +this list. <p> + +<a name="compose"><b>Going directly to Message Compose</b></a><br> +Click a highlighted address to go directly to your Message Compose page. +The address you select will be in the "To:" field ready for your new +message. In the case of distribution lists, select any one of the +addresses in that list and they will all be included in the "To:" field. diff --git a/web/cgi/alpine/1.0/help/addrbrowse.html b/web/cgi/alpine/1.0/help/addrbrowse.html new file mode 100644 index 00000000..3e9abf2e --- /dev/null +++ b/web/cgi/alpine/1.0/help/addrbrowse.html @@ -0,0 +1,27 @@ +<!-- +# $Id: addrbrowse.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Addressing Messages</b></font> + +<p>Select addresses for your message composition in your address book after you +click <img src="../../images/book.gif" alt="Address book icon" style="vertical-align:middle"> on your Message Compose +screen.</p> + +<p>Click the checkbox next to address or addresses to which you want to send your +message.</p> + +<p>Click <input type=submit value="Address"> to return to your Message Compose screen. +Your message will now include the addresses you have selected. + +<p>Click <input type=submit value="Cancel"> to return to your Message Compose screen without +adding an address.</p> diff --git a/web/cgi/alpine/1.0/help/addredit.html b/web/cgi/alpine/1.0/help/addredit.html new file mode 100644 index 00000000..01defdcc --- /dev/null +++ b/web/cgi/alpine/1.0/help/addredit.html @@ -0,0 +1,59 @@ +<!-- +# $Id: addredit.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Address Book Entry</b></font> + +<p>You can add and edit individual and group entries to your address book by adding information to +the following fields:</p> + +<P> +<ul type="square"> + <li><a href="#nick"><b>Nickname</b></a></li> + <li><a href="#fullname"><b>Full Name</b></a></li> + <li><a href="#addresses"><b>Addresses</b></a></li> + <li><a href="#fcc"><b>Fcc</b></a></li> + <li><a href="#comments"><b>Comments</b></a></li> +</ul> + +<a name="nick"><b>Nickname</b></a><br> +Enter a nickname which will identify this address book entry. Every +address book entry needs to have a unique nickname associated with it. +While composing a message, you can use the nickname in place of the address. +By clicking <input type=submit value="Expand">, the nickname will automatically by replace by +the full address or addresses for this entry. The nickname is not seen in the outgoing message. + +<p><a name="fullname"><b>Full Name</b></a><br> +Enter the full name for this entry. For an +individual entry, you will ordinarily use that person's name. For a group +of addresses (or distribution list), use a descriptive word or phrase +that describes the group. + +<p><a name="addresses"><b>Addresses</b></a><br> +Enter the email address or addresses for this entry. You must complete this field for all your +address book entries. You can create group mailing lists for sending +email messages to several addresses at once by listing the addresses +separated by commas, just as you would enter them when composing a +message. For those addresses already in your address book, you can just +add the nicknames separated by commas. + +<p><a name="fcc"><b>Fcc</b></a><br> +When the "Fcc:" (Folder carbon copy) field is used, a copy of all messages +that you send with this addressbook entry as the first address in the +"To:" field will be saved in the folder specified in the "Fcc:" field +rather than your default Fcc folder (usually "sent-mail"). + +<p><a name="comments"><b>Comments</b></a><br> + +This optional field allows you to enter any comments about the entry. This field is not used in your +outgoing messages. + diff --git a/web/cgi/alpine/1.0/help/attach.html b/web/cgi/alpine/1.0/help/attach.html new file mode 100644 index 00000000..b632c9f4 --- /dev/null +++ b/web/cgi/alpine/1.0/help/attach.html @@ -0,0 +1,37 @@ +<!-- +# $Id: attach.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Add an Attachment</b></font> + +<p>Add a file (such as a document, image, audio clip) to your message after +you click <input type=submit value="Attach"> on your Message Compose screen.</p> + +<p>Click <input type=submit value="Browse..."> to find and select the file you want to attach. +If you know the exact path to the file, simply type in that path.</p> + +<p>You have the option of entering a short description of the attachment +in the second text box. If you choose to include a description, your +recipients will see that text alongside the file name. Descriptions +can be particularly helpful when you include several attachments to your +message.</p> + +<p>Click <input type=submit value="Add Attachment"> to return to your Message Compose screen. +Your attached file will be listed in the "Attachments:" field. To add +another attachment, from Message Compose, click <input type=submit value="Attach"> again.</p> + +<p>If you have attached a file that you do not want to send, return to the Message +Compose screen by clicking <input type=submit value="Cancel">. Then click the corresponding <img +src="../../images/but_remove.gif" alt="remove icon"> to remove it.</p> + +<p>Click <input type=submit value="Cancel"> to return to your Message Compose screen without +adding an attachment.</p> diff --git a/web/cgi/alpine/1.0/help/compose.html b/web/cgi/alpine/1.0/help/compose.html new file mode 100644 index 00000000..aad7ac40 --- /dev/null +++ b/web/cgi/alpine/1.0/help/compose.html @@ -0,0 +1,147 @@ +<!-- +# $Id: compose.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<form action="alpine/wp.tcl" target="noop" method=get> +<input name="page" value="noop" type=hidden notab> +<font size="+2"><b>Message Compose</b></font> + +<p>The Message Compose screen is where you will write and send your email +messages.</p> + +<p> +<ul type="square"> + <li><a href="#header"><b>Using your header fields</b></a></li> + <li><a href="#write"><b>Writing your messages</b></a></li> + <li><a href="#send"><b>Sending, postponing and canceling</b></a></li> + <li><a href="#note"><b>Differences from Pine and PC-Pine</b></a></li> +</ul> + +<a name="header"><b>Using your headers</b></a><p> + +The message header area is used for addressing your message and providing +other information that may be useful to you or the message recipient. + +<p>By default, your messages headers will include: To, Cc, +Attachments, Subject. Go to <b>Configure</b> from the Message View or List +page and click the Composer tab to change +the defaults or customize your settings. If you have additional headers +configured, click <img src="../../images/hdrmore.gif" alt="More Headers" +style="background-color:#ffffcc;padding:4;vertical-align:middle; xborder: 1px solid brown"> to +display them. +Below is a description of commonly used headers: + +<ul> +<li> +<b>To:</b> Use this field to specify intended email recipients. This can +be done in any of three ways: +<ul type="square"> + <li>Type the full email address of the intended message recipient. +Separate multiple addresses with a comma.</li> + + <li>Type a name or nickname specified in your address book and click +<input type=submit value="Expand">. Alpine will not automatically expand +your addresses without this step. Separate multiple names or nicknames +with a comma.</li> + + <li>Click <img src="../../images/book.gif" alt="Address book icon" +style="vertical-align:middle"> to go to your address book to select an +address.</li> +</ul></p></li> + +<li> <b>Attachments:</b> Use this field to attach files (such as +documents, +images, audio clips) to your message. Click <input type=submit +value="Attach"> to find and attach a file +from your local system. If you have attached a file that you do not want +to send, +click the corresponding <img src="../../images/but_remove.gif" alt="remove +icon" style="vertical-align:middle"> to +remove it. <p></li> + +<li><b>Subject:</b> Use this field to provide a few words that summarize +the message.<p></li> + +<li><b>Cc:</b> (Carbon copy) This field is similar to the "To:" field, but +it is used to send a copy of the message to one or more people. These +email +addresses will be seen by all message recipients.<p></li> + +<li><b>Bcc:</b> (Blind carbon copy) This field is similar to the "To:" and +"Cc:" fields, but it is +used to send a copy of the message to one or more people whose +addresses you do not want disclosed to other message recipients.<p></li> + +<li><b>Fcc:</b> (File carbon copy) Use this field to specify the folder +to which a copy of your +outgoing message will be saved. When this header is visible, you can +change or remove the Fcc by editing the folder name.<p></li> + +<li><b>Reply-To:</b> Use this field when you would like replies to your +messages to be directed to an address other than your usual "From:" +address.<p></li> + +</ul> + +<a name="write"><b>Writing your messages</b></a><p> + +Type your message in the large text box beneath the headers. Depending on +your browser, messages you send may contain a single long line rather than +the nicely wrapping text shown in the text box. In those cases, +recipients will have to scroll horizontally to read your message. To +avoid this problem, use the Return key at the end of each line. + +<p>To spell check your message, click the +<input type=submit value="Spell Check"> button. The resulting page will list each +potentially misspelled word. Each word will have a text box for you to +enter a correction. Additionally, some words will also have +a list of suggested corrections. Click the <i>Apply</i> button to have +your changes appear in the composer, or +<i>Cancel</i> to return to the composer with the original text. +</p> + +<p>Do you want to add a personalized signature line to your messages? Go +to <b>Configure</b> from the Message View or List page and click the Composer tab.</p> + + +<a name="send"><b>Sending, postponing, canceling</b></a><p> +To send your message, postpone it to resume later, or to cancel it +completely, click the appropriate radio button and then click <input +type=submit value="OK">. +<ul> + <li><b>Send</b> - Use this option to send your message to the +recipients.<p></li> + <li><b>Postpone</b> - Use this option to store an unfinished message +without sending it. To finish the message at a later time, click +<b>Resume</b> in the far left column of the Message List.<p></li> + <li><b>Cancel</b> - Use this option to throw out the current composition. +The message will not be sent and you will not be able to resume +it.<p></li> +</ul> + +<p><a name="note"><b>Differences from Pine and PC-Pine</b></a><p> + +<p>Alpine is designed primarily for easy access to email. It is not +intended to replace any other heavy duty email programs. Accordingly, it +is missing some of the more advanced features you will find in Pine and +PC-Pine. As development continues, features will be added as long as they +do not make a large impact on Alpine's speed or efficiency. + +<p> Some of the features you will not currently find in Alpine Compose: +<ul> +<li>Lcc (List carbon copy) +<li>Where is (instead, use your browser's "find" command) +<li>Read a file into the composition +</ul> + +</ul> +</form> diff --git a/web/cgi/alpine/1.0/help/create_save.tcl b/web/cgi/alpine/1.0/help/create_save.tcl new file mode 100644 index 00000000..f2a07b5c --- /dev/null +++ b/web/cgi/alpine/1.0/help/create_save.tcl @@ -0,0 +1,17 @@ +# $Id: create_save.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +cgi_h2 "Create Folder Confirmation Help" +cgi_p "Help pages for the create file to save in confirmation page will appear here." +cgi_p { + Someday. + +} diff --git a/web/cgi/alpine/1.0/help/expunge.html b/web/cgi/alpine/1.0/help/expunge.html new file mode 100644 index 00000000..f1602175 --- /dev/null +++ b/web/cgi/alpine/1.0/help/expunge.html @@ -0,0 +1,20 @@ +<!-- +# $Id: expunge.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Expunge Deleted Messages</b></font> + +<p>Click <input type=submit value="Expunge"> to permanently remove the messages you have flagged for deletion. You will +not be able to retrieve your messages once you have expunged them. </p> + +<p>Click <input type=submit value="Cancel"> to return to your list of messages. The messages you previously flagged for +deletion will remain in your folder, still flagged for deletion.</p> diff --git a/web/cgi/alpine/1.0/help/filtconf.html b/web/cgi/alpine/1.0/help/filtconf.html new file mode 100644 index 00000000..67654e35 --- /dev/null +++ b/web/cgi/alpine/1.0/help/filtconf.html @@ -0,0 +1,62 @@ +<HTML> +<!-- +# $Id: filtconf.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<BODY> +<FONT SIZE=+2><B>Message Filtering</B></FONT> + + +<p>Filtering is a way to automatically move certain messages from one +folder to another or to delete messages, according to rules that you +define. For each filtering rule you define, you will provide a +<i>Pattern</i> to establish the messages you want filtered, and an +<i>Action</i>, to control what to do with those messages.</p> + +<p>Click <img src="../../images/cf_add.gif" alt="Add" align=middle> to go to a screen where you can define a set of +new filter rules. + +<p>Click <img src="../../images/cf_edit.gif" alt="Edit" align=middle> next to a filter that you would like to change. You +will go to an edit screen. You will only see this option if you have +already created filters.</p> + + +<p>Click <img src="../../images/cf_delete.gif" alt="Delete" align=middle> next to a filter rule you would like to remove. +That filter will disappear. You will only see this option if +you have already created filter rules.</p> + +<p>When you have more than one filter defined, you will see the <img src="../../images/cf_shup.gif" xalign=middle> (shuffle up), +and <img src="../../images/cf_shdown.gif" xalign=middle> (shuffle down), options next to each filter. Use these to +move your filters up or down in the list. The order is important. Your +messages will be checked for filtering against the top filter first and, +if the filter is set up for that message, it will be filtered. If no +matching information is found, the message will be checked against the +second filter and so on down the list. Messages that do not match any +filter rules will be delivered to your Inbox.</p> + +<p>Performance considerations:</p> +<ul> + <li>The more filters you have defined the longer it will take to run + down the list. Deleting unused filters is a good + idea. + <li>Filtering in newsgroups served by an NNTP server will be slow if your + patterns include tests other than "From:" or + "Subject:". + <li>Filtering a folder served by an IMAP server based on protocol + versions prior to 4. +</ul> + + + +</BODY> +</HTML> + diff --git a/web/cgi/alpine/1.0/help/filtedit.html b/web/cgi/alpine/1.0/help/filtedit.html new file mode 100644 index 00000000..0adb42f7 --- /dev/null +++ b/web/cgi/alpine/1.0/help/filtedit.html @@ -0,0 +1,240 @@ +<html> +<head> +<!-- +# $Id: filtedit.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +</head> +<body> +<font size="+2"><b>Filter Configuration</b></font> +<p>This Filter Configuration screen is where you can add new filters +or modify existing ones.</p> + +<p>In order to determine whether or not a message matches a filter, the +message is compared with the Filter's Pattern. Once a filter match is +found for a particular message, there are some actions which may be +taken.</p> + +<p>NOTE: When you set up a Pattern to delete messages, it is recommended +that you test the Pattern first with a "Move" folder in case unintended +matches occur. Messages that are deleted will be removed from the folder +and may be unrecoverable.</p> + +<ul type="square"> +<li><a href="#patterns"><b>Filter Patterns</b></a> +</li><li><a href="#actions"><b>Filter Actions</b></a> +</li><li><a href="#examples"><b>Examples</b></a> +</li></ul> + +<a name="patterns"><b>Filter Patterns</b></a><br> + +<ul> +<li><b>Nickname:</b><br> +This is a nickname to help you. You should have a different nickname for +each filtering rule you define. The nickname will be used in the Message +Filtering screen to allow you to pick a rule to edit.<p></p> + +</li><li><b>To:</b><br> +Any text you enter as the "To pattern" will be compared to the recipients +from the To: line of messages when WebPine +opens folders. When the text you entered matches all or part of the To: +line of a message, then the Filter Action you +have specified will be carried out. (Any other non-blank parts of the +Pattern must match, too.) + +<p>You may enter a complete email address, part of an address, or a +comma-separated list of addresses or partial +addresses. For example:</p> + +<pre> To: = friend@public.com + To: = rated.net + To: = admin@public.com, admin@msn.com, fool@motleyfool.com +</pre> + +<p>Each of those are valid "To patterns".</p> + +<p>Messages match those patterns if any of the addresses in the To: line +of the message contains the pattern. If the pattern is a comma-separated +list of patterns (like the last example above) then it is a match if any +of the patterns in the list match any of the addresses in the To: line. +(It is not possible to specify two addresses which must BOTH be present +for a match. It is only possible to specify that EITHER address1 OR +address2 must be present. That is exactly what the comma-separated list +does.)</p> + +<p>Some messages may be "bounced" to you, and will have a "Resent-To:" +header line. If the message contains a Resent-To: line, WebPine will look +for matches to your "To: patterns" there, and NOT in the original To: +line.</p> + +</li><li><b>From:</b><br> +This is just like the "To pattern" except that it is compared with the +address in the From: line of the message instead of the addresses from the +To: line. See the help for the To pattern for more information on header +patterns.<p></p> + +</li><li><b>Sender:</b><br> +This is just like the "To pattern" except that it is compared with the +address from the Sender: line of the message +instead of the addresses from the To: line. See the help for the To +pattern for more information on header patterns.<p></p> + +</li><li>Cc:</li><br> +This is just like the "To pattern" except that it is compared with the +addresses from the Cc: line of the message instead of the addresses from +the To: line. See the help for the To pattern for more information on +header patterns.<p></p> + + +<li><b>Recipient:</b><br> +This is just like the "To pattern" except that it is compared with the +addresses from both the To: line and the Cc: +line of the message instead of just the addresses from the To: line. In +other words, it is considered a match if the +pattern matches EITHER an address in the To: line OR an address in the Cc: +line. (Notice that defining the Recipient +pattern does not have the same effect as defining both the To and Cc +patterns. Recipient is To OR Cc; not To AND Cc. +It is equivalent to having two different rules; one with a To pattern and +the other with the same Cc pattern.)<p></p> + + +</li><li><b>Participants:</b><br> +This is just like the "To pattern" except that it is compared with the +addresses from the From: line, the To: line, and the Cc: line of the +message instead of just the addresses from the To: line. In other words, +it is considered a match if the pattern matches EITHER an address in the +From: line, OR an address in the To: line, OR an address in the Cc: line. +(Notice that defining the Participant pattern does not have the same +effect as defining all of the From, To, and Cc patterns. Participant is +From OR To OR Cc; not From AND To AND Cc. It is equivalent to having +three different rules; one with a From pattern, another with the same To +pattern, and a third with the same Cc pattern.)<p></p> + + +</li><li><b>Newsgroups:</b><br> +If this pattern is non-blank, then for this rule to be considered a match, +at least one of the newsgroups from the +Newsgroups line of the message must match this pattern. If this pattern is +a comma-separated list of patterns, then at +least one of the newsgroups must match at least one of the patterns. (Any +other non-blank parts of the Pattern must +match, too.)<p></p> + +</li><li><b>Subject:</b><br> +This is similar to the other parts of the Pattern. It is compared with the +contents from the Subject of the message. + +<p>If you enter non-ASCII characters in this field then the search will be +done using the character set you have defined with the "character-set" +configuration variable. (The truly sophisticated may use an alternate +character set for a search by entering the MIME encoding of the header +string here.)</p> + + +</li><li><b>All Text:</b><br> +This is similar to the header patterns. Instead of comparing with text in +a particular header field it is compared with all of the text in the +message header and body. + +<p>If you enter non-ASCII characters in this field then the search will be +done using the character set you have defined +with the "character-set" configuration variable. (The truly sophisticated +may use an alternate character set for a +search by entering the MIME encoding of the header string here.)</p> + +<p>It is possible that you may notice degraded performance when using +AllText Patterns.</p> + + +</li><li><b>Message is New</b><br> +This part of the Pattern may have one of three possible values. The +default value is "Don't care", which matches any message. The other two +values are "Yes", which means the message must be "New" in order to be a +match; or "No", which means the message must not be "New" in order to be a +match. "New" is the same as Unseen and not "New" is the same as Seen.<p></p> + +</li><li><b>Message is Deleted</b><br> +This part of the Pattern may have one of three possible values. The +default value is "Don't care", which matches any message. The other two +values are "Yes", which means the message must be marked "Deleted" in +order to be a match; or "No", which means the message must not be marked +"Deleted" in order to be a match. + +<p>If you are thinking of using this part of the Pattern as a way to +prevent messages from being filtered more than once in a Filter Pattern, +take a look at the Filter Option "move-only-if-not-deleted" instead. It +should work better than using this field since it will hide the filtered +messages even if they are already Deleted. That option is at the bottom of +the Filter configuration screen.</p> + +</li><li><b>Message is Important</b><br> +This part of the Pattern may have one of three possible values. The +default value is "Don't care", which matches any message. The other two +values are "Yes", which means the message must be flagged "Important" in +order to be a match; or "No", which means the message must not be flagged +"Important" in order to be a match.<p></p> + +</li><li><b>Message is Answered</b><br> +This part of the Pattern may have one of three possible values. The +default value is "Don't care", which matches any message. The other two +values are "Yes", which means the message must be marked "Answered" in +order to be a match; or "No", which means the message must not be marked +"Answered" in order to be a match. +</li></ul> + +<a name="actions"><b>Filter Actions</b></a><br> +The Filter Action specifies the action to be taken when the Pattern is a +match. It may be either <b>Delete</b> or <b>Move</b> + +<p>If you set it to "Move", then provide the name of the folder to which +the matching message should be moved in the corresponding text box. You +may type a list of folders separated by commas, in which case the message +will be copied to all of the folders in the list before it is deleted.</p> + +<b>Move only if not deleted</b><br> If you set this option then a message +will be moved into the specified folder only if it is not marked for +deletion. This is useful if you have multiple Pine or WebPine sessions +running simultaneously and you don't want messages to be filtered into a +folder more than once. It is also useful if you want to filter only the +"undeleted" messages in a newsgroup into a folder. This method is not +foolproof. There may be cases where a message gets marked deleted and so +it is never filtered into the folder. For example, if you deleted it in +another Pine or WebPine session or another mail program that didn't use +the filtering rule.<br> + +This option has no effect if the Filter Action is not set to Move.<p></p> + +<a name="examples"><b>Examples</b></a><br> +To create a filter to move all incoming messages from +"sue@travelworld.com" to your "Vacation" folder, add the following to the +Filter Configuration screen:<br> +<b>Nickname:</b> Travelworld<br> +<b>From:</b> sue@travelworld.com<br> +<b>Move filter action:</b>Vacation<br> + +Click <b>Save</b> to add the filter.<br> + +<p>To create a filter to delete all incoming messages that contain the +text "Make Money fast!" in the subject line, add the following to your +Filter Configuration screen:<br> +<b>Nickname:</b> Make Money<br> +<b>Subject:</b> Make Money Fast!<br> +<b>Delete:</b> (Click next to this option)<br> +Reminder: It is a very good idea to test this with the "Move to Folder" +option in case unintended matches occur.<br> + +Click <b>Save</b> to add the filter. + + + +</p></body></html>
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/help/folders.html b/web/cgi/alpine/1.0/help/folders.html new file mode 100644 index 00000000..6e23973b --- /dev/null +++ b/web/cgi/alpine/1.0/help/folders.html @@ -0,0 +1,39 @@ +<!-- +# $Id: folders.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Folder List</b></font> + +<p> Your email messages are stored in folders. The Folder List screen allows you to +get to those folders by clicking on the folder name. Manage your folders by doing +the following:</p> + +<ul> +<li>Delete a folder: Click the radio button corresponding to the correct +folder and click <img src="../../images/but_folddel.gif" alt="delete icon" style="vertical-align:middle">. +You will be prompted for confirmation before the folder is actually deleted.</li> +<li>Rename a folder: Click the radio button corresponding to the correct +folder and click +<img src="../../images/but_foldren.gif" alt="folder rename icon" style="vertical-align:middle">. +You will be prompted for confirmation before the folder is actually renamed.</li> +<li>Add a folder: Click <input type=submit value="Create New..."> to go to the Folder Creation +screen.</li> +</ul> + +<p>If your folder list includes directories (used to contain folders) or +collections (used to organize folders on different email hosts), you will +see the following icons:</p> + +<ul> +<li>Click <img src="../../images/b_plus.gif" alt="expand icon"> to expand the listing to see the contents</li> +<li>Click <img src="../../images/b_minus.gif" alt="contract icon"> to collapse the listing and see the top-level only</li> +</ul> diff --git a/web/cgi/alpine/1.0/help/foldiradd.html b/web/cgi/alpine/1.0/help/foldiradd.html new file mode 100644 index 00000000..2823ea72 --- /dev/null +++ b/web/cgi/alpine/1.0/help/foldiradd.html @@ -0,0 +1,30 @@ +<!-- +# $Id: foldiradd.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Creating Folders</b></font> + +<p>Folders are used to contain messages. Directories are used to contain folders. +<p> +After you click <input type=submit value="Create New..."> on the Folder List page, you can create either +one. + +<ul> + <li>To add a folder: enter the name of the folder you want to add to + in the "New folder name:" text box. Click <input type=submit value="Create New Folder">.</li> + <li>To add a directory: enter the name of the directory you want to add to + in the "Create New Directory:" text box. Click <input type=submit value="Create New Directory">.</li> +</ul> + +<p>Click <input type=submit value="Cancel"> to return to the Folder List screen without creating a new +directory or folder.</p> + diff --git a/web/cgi/alpine/1.0/help/forward.tcl b/web/cgi/alpine/1.0/help/forward.tcl new file mode 100644 index 00000000..c016ca23 --- /dev/null +++ b/web/cgi/alpine/1.0/help/forward.tcl @@ -0,0 +1,16 @@ +# $Id: forward.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +cgi_h2 "Forward Help" +cgi_p "Help pages for the Forward compose form will appear here." +cgi_p { + Someday. +} diff --git a/web/cgi/alpine/1.0/help/index.html b/web/cgi/alpine/1.0/help/index.html new file mode 100644 index 00000000..58bcd323 --- /dev/null +++ b/web/cgi/alpine/1.0/help/index.html @@ -0,0 +1,281 @@ +<!-- +# $Id: index.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<form action="alpine/wp.tcl" target="noop" method=get> +<input name="page" value="noop" type=hidden notab> +<font size="+2"><b>Message List</b></font> + +<p>Your Message List contains summary information about each of the messages in +your current Alpine folder and provides ways for you to take actions on +those messages.</p> + +<p>To compose a new message, resume a postponed one, or go to another folder, +click the appropriate option in the far left column of your page. +You will also see options to change your Alpine configuration and to +manage your address book.</p> + +<ul type="square"> + <li><a href="#read"><b>Reading your mail</b></a></li> + <li><a href="#navigate"><b>Navigating your list</b></a></li> + <li><a href="#scroll"><b>Scrolling through messages</b></a></li> + <li><a href="#sort"><b>Sorting your mail</b></a></li> + <li><a href="#delete"><b>Deleting messages</b></a></li> + <li><a href="#expunge"><b>Removing deleted messages</b></a></li> + <li><a href="#save"><b>Saving messages to another folder</b></a></li> + <li><a href="#flags"><b>Setting status flags</b></a></li> + <li><a href="#search"><b>Searching</b></a></li> + <li><a href="#jump"><b>Jump Command (optional)</b></a></li> + <li><a href="#note"><b>Differences in Pine and PC-Pine</b></a></li> +</ul> + +<a name="read"><b>Reading your mail</b></a><p> + +After logging into Alpine, you will see your Message List INBOX. This is the default folder for new +mail. To read a message, click its subject. + +<p>Click <b>Folder List</b> if you want to read mail within a different folder.</p> + + +<a name="navigate"><b>Navigating your list</b></a><p> +In the column on the left side of your Message List page, you will +see four navigation options: <b>Previous</b>, <b>First</b>, <b>Next</b>, +<b>Last</b>. +<table border=0 cellpadding=4 style="margin-left:24"> + <tr> + <td><img src="../../images/but_rnd_prev3.gif" alt="Previous"></td> + <td>to display messages in the current folder before those currently listed</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_first3.gif" alt="First"></td> + <td>to display messages in the current folder beginning with message 1</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_next3.gif" alt="Next"></td> + <td>to display messages in the current folder after those currently listed</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_last3.gif" alt="Last"></td> + <td>to display messages in the current folder at the end of the list</td> + </tr> +</table> + +<p>With most browsers and the usual settings, you also have the option of +using keyboard controls for some of your navigation. You may, however, +need to first click in your Alpine window to make sure that your system +knows which screen is active. + +<p>The keyboard controls are: +<table border=0 cellspacing=12 cellpadding=3> +<tr><td text align="center">n</td> + <td>next message</td></tr> +<tr><td text align="center">p</td> + <td>previous message</td></tr> +<tr><td text align="center">i</td> + <td>return to message index</td></tr> +<tr><td text align="center">c</td> + <td>compose new message</td></tr> +<tr><td text align="center">l</td> + <td>list folder</td></tr> +<tr><td text align="center">d</td> + <td>flag message as deleted</td></tr> +<tr><td text align="center">u</td> + <td>unflag message as deleted</td></tr> +<tr><td text align="center">a</td> + <td>go to address book</td></tr> +<tr><td text align="center">r</td> + <td>reply to current message</td></tr> +<tr><td text align="center">f</td> + <td>forward current message</td></tr> +</table> + + +<a name="scroll"><b>Scrolling through messages</b></a><p> +You have the option of scrolling, rather than paging using <i>Next</i> and +<i>Previous</i>, through most of your messages in your Message List. Go +to <b>Configure</b> on the left side of your Message List page, click the +Message List tab and enter a higher number in the <i>Message Lines +Displayed</i> field. Bear in mind that the higher +number you choose, the longer it may take Alpine to open your folders. + + +<p><a name="sort"><b>Sorting your mail</b></a><p> +To sort your mail, the List Headers Bar must first be displayed. Display the bar by clicking +the <img src="../../images/baropen.gif" alt="small arrow"> icon +near the top of the screen. + +<p>Using the Sort options, you can arrange your mail by <b>Date</b>, +<b>From</b>, <b>To</b>, <b>Size</b>, <b>Subject</b>, <b>Ordered +Subject</b>, and <b>Thread</b>. Click: +<ul> + <li><b>Date</b> to sort by the date your messages were sent.</li> + <li><b>From</b> to sort alphabetically by the email address of the sender of the message.</li> + <li><b>To</b> to sort alphabetically according to the "To:" line.</li> + <li><b>Size</b> to sort by the number of characters in the message.</li> + <li><b>Subject</b> to sort alphabetically according to the "Subject:" line.</li> + <li><b>Ordered Subject</b> to group messages with the same "Subject:" line and put them into date order.</li> + <li><b>Thread</b> to present messages as a continuous chain grouped by "Subject:" line. This sort is particularly helpful when viewing newsgroups.</li> +</ul> + +<p>Once you have sorted your mail, the name of that sort (i.e. the column +heading) will be highlighted and an arrow will appear next to the name. To +reverse the sort order, click the arrow. +By default, your Message List is set to sort your mail by arrival time. +</p> + +<!--<p><i>{Do you want to change your default sort order? <a href="">Click +here</a> for that configuration option.[not implemented yet]}</i></p>--> + +<a name="delete"><b>Deleting messages</b></a><p> +<ul> + <li>Click the checkboxes next to the appropriate messages</li> + <li>Click <input type=submit value="Delete">. All messages with a mark in the checkbox will be flagged for deletion. (If you notice that some messages are mistakenly flagged for deletion, click their associated checkboxes and click <input type=submit value="Undelete">)</li> + <li>Click <input type=submit value="Expunge"> to permanently remove from your folder all the messages that have been flagged for deletion</li> +</ul> + +<p>If you want to delete several messages at once that share a similar +attribute, you might want to first perform a search. See the +<a href="#search">Searching</a> text for more information.</p> + +<p>Note: if marking a message for deletion fails to work it may be because +you recently used your browser's "Back" button. To avoid this, be sure to +Alpine links and navigation options. + + +<!-- <p><i>{Do you want to Expunge without being prompted for a +confirmation? <a href="">Click here</a> to change that configuration +option. [not implemented yet]}</i> +<p>{<i><a href="">Click here</a> to enable aggregate commands to have +this option available on this page. [not implemented yet]</i>}</p> --> + +<p> +<a name="expunge"><b>Removing deleted messages</b></a><p> +Flagging messages for deletion is only half the process of actually removing the messages from the folder altogether. +Click <input type=submit value="Expunge"> to permanently remove messages flagged for deletion. Because removed messages cannot +be restored, you will be prompted to confirm your desire. At the prompting click:</p> + +<p><input type=submit value="Expunge"> to permanently remove the messages you have flagged for deletion. You will +not be able to retrieve your messages once you have expunged them. </p> + +<p><input type=submit value="Cancel"> to return to your list of messages. The messages you previously flagged for +deletion will remain in your folder, still flagged for deletion.</p> + + +<p> <a name="save"><b>Saving messages to another folder</b></a> +<p> + +To save messages from your Message List, the Message Command Bar must +first be displayed. Display the bar by clicking the <img +src="../../images/baropen.gif" alt="small arrow"> icon near the top of the +screen. Then, click the checkboxes next to the messages you want to +save to another folder (or click just one checkbox if you are only +saving that one message). + +<p> +Save the chosen messages by choosing from the options in the dropdown menu next to the +<input type=submit value="Save"> button. Among the Save options, you'll find: + +<ul> + <li> The name of the default folder to save to, typically <font face="courier">saved-messages</font>. + <li> Several, typically six, names of folders you have most recently saved messages to + <li> An option to type in directly the name of the folder you wish to save to (either a new folder you wish to create, or one +already containing messages) + <li> An option to choose the folder from the list of all your folders +</ul> + +If Alpine does not act on your choice immediately, click the <input type=submit value="Save"> +button to initiate saving. Once saved, the chosen messages will be marked for deletion. + +<p> + +<!---Config option for Collection lists?--> + +<a name="flags"><b>Setting status flags</b></a><p> +By default, the area immediatly to the left of the message numbers is reserved for the following status flags: +<table border=0 cellpadding=4 style="margin-left:24"> + <tr> + <td><font face=Courier><b>+</b></font></td> + <td>message has your address in the To: line [Note: this is a fixed value]</td> + </tr> + <tr> + <td><font face=Courier><b>*</b></font></td> + <td>(Important) - You have previously set the status of this message to important</td> + <tr> + </tr> + <td><font face=Courier><b>A</b></font></td> + <td>(answered) - You have replied to this message</td> + </tr> + <tr> + <td><font face=Courier><b>N</b></font></td> + <td>(new) - You have not yet looked at the text of this message</td> + </tr> + <tr> + <td><font face=Courier><b>D</b></font></td> + <td>(deleted) - You have marked this message for deletion, but not yet expunged it</td> + </tr> +</table> + +To add or remove the status flags, the Message Command Bar must first be +displayed. Display the bar by clicking the <img src="../../images/baropen.gif" +alt="small arrow"> icon near the top of the screen. Then: <ul> + <li>Click the checkboxes next to the appropriate messages</li> + <li>Choose the appropriate value from the dropdown menu</li> + <li>Click <input type=submit value="Set"></li> +</ul> + + +<!--Config option for enabling status w/click--> + +<a name="search"><b>Searching</b></a><p> + +To search, the Message Command Bar must first be displayed. Display the bar +by clicking the <img src="../../images/baropen.gif" alt="small arrow"> icon +near the top of the screen. + +<p>Click <input type=submit value="Search"> to get to a page where you can find messages by +text, date, or status.</p> + +After you specify your search criteria, you will be returned to your +Message List. If matches were found, your Message List will display your +found messages and those messages will be marked. (Be aware: by default +Search will include messages marked before the search along with your +search results.) Click <input type=submit value="Show All Messages"> to display your entire Message +List. + +<p><a name="jump"><b>Jump Command (optional)</b></a><p> + +Depending on your configuration, you may also see a text box next to a +<input type=submit value="Jump"> button on the left side of the page. Enter a +message number into the text box and click the button to redisplay +the Message List with the chosen message at the top of the page. + +<p> +You may find message numbers on the Message List lines make this command more useful. +If not displayed in the Message List, you can add message numbers to each line by +going to <b>Configure</b> on the left of the Message List page, clicking the +Message List tab and adjusting the Message Line Format accordingly. + +<p><a name="note"><b>Differences from Alpine and PC-Alpine</b></a><p> + +<p>Alpine is designed primarily for easy access to email. It is not +intended to replace any other heavy duty email programs. Accordingly, it +is missing some of the more advanced features you will find in Pine and +PC-Pine. As development continues, features will be added as long as they +do not make a large impact on Alpine's speed or efficiency. + +<p> Some of the features you will not currently find in Alpine Message +List: <ul> +<li>Go directly to a folder you type in (may be added soon) +<li>Export message + +</ul> +<!--Go to Configure to change the view display after search default--> diff --git a/web/cgi/alpine/1.0/help/index.tcl.1 b/web/cgi/alpine/1.0/help/index.tcl.1 new file mode 100644 index 00000000..67cc941d --- /dev/null +++ b/web/cgi/alpine/1.0/help/index.tcl.1 @@ -0,0 +1,301 @@ +# $Id$ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +cgi_put [cgi_font size=+2 [cgi_bold "Message List"]] + +cgi_p +cgi_puts [cgi_font size=-1 color=red "Note: This text may be out-of-date; changes to the Message List page are in process."] + +cgi_p { + Your Message List contains summary information about each of the + messages in your current WebPine-lite folder and provides ways for you to + take actions on those messages. +} + +cgi_p { + To compose a new message, resume a postponed one, or go to another + folder, select the appropriate option in the column on the left-hand side + of your page. You will also see options to change your WebPine-lite + configuration and to manage your address book. +} + +cgi_bullet_list type=square { + cgi_li [cgi_url [cgi_bold "Reading your mail"] "#read"] + cgi_li [cgi_url [cgi_bold "Navigating your list"] "#navigate"] + cgi_li [cgi_url [cgi_bold "Sorting your mail"] "#sort"] + cgi_li [cgi_url [cgi_bold "Operating on a set of messages"] "#aggregate"] + cgi_li [cgi_url [cgi_bold "Deleting messages"] "#delete"] + cgi_li [cgi_url [cgi_bold "Saving messages to another folder"] "#save"] + cgi_li [cgi_url [cgi_bold "Setting status flags"] "#flags"] + cgi_li [cgi_url [cgi_bold "Searching"] "#search"] +} + +cgi_anchor_name "read" +cgi_puts [cgi_bold "Reading your mail"][cgi_nl]" +cgi_puts { + Once you log into WebPine-lite, you will see your Message List INBOX. To + read a message within any folder, select its subject line. +} + +cgi_p { + Go to [cgi_bold "Folder List"] if you want to read mail within another + folder. +} + +cgi_p { + Your INBOX is where your new mail is delivered unless you filter some + mail to another folder. +} + +if {0} { +<!-- <p>{<i><a href="">Click here</a> to configure mail filters.[not +implemented yet]}</i></p> --> +} + +cgi_anchor_name "navigate" +cgi_puts [cgi_bold "Navigating your list"][cgi_nl] +cgi_puts { + In the column on the left-hand side of your Message List page, you will + see four navigation options: [cgi_bold Previous], [cgi_bold First], [cgi_bold Next], + [cgi_bold Last]. +} + +cgi_puts "Select:[cgi_nl]" +cgi_bullet_list { + cgi_li { + [cgi_bold Previous] to download your Message List page that contains + your previous set of messages. For example, if you see messages 101-150 + out of 280, select [cgi_bold Previous] to go to messages 50-100.[cgi_nl] + } + cgi_li { + [cgi_bold First] to view your Message List beginning with message number 1. + } + cgi_li { + [cgi_bold Next] to download your Message List page that contains + your next set of messages. For example, if you see messages 101-150 out + of 280, select [cgi_bold Next] to go to messages 151-200. + } + cgi_li { + [cgi_bold Last to view your Message List page that ends with your last + message in that folder. + } +} + +cgi_p { + Use your browser scrollbar to see messages that are downloaded, but are + out of eyesight due to screen size. +} + +if {0} { +<!-- <p>{<i>Do you want to change the number of messages WebPine-lite +downloads to your Message List? <a href="">Click here</a> to make that +configuration change.[not implemented yet]}</i></p> --> +} + +cgi_p { + [cgi_anchor_name "sort"][cgi_bold "Sorting your mail"][cgi_nl] + Using the Sort options you can arrange your mail by [cgi_bold "Date"], + [cgi_bold "From"], [cgi_bold "To"], [cgi_bold "Size"], [cgi_bold "Subject"], [cgi_bold "Ordered Subject"], + and [cgi_bold "Thread"]. By default, your Message List is set to + sort your mail by arrival time. Most of the time, arrival time and date + (effectively departure time) are nearly the same. They may differ, + however, because of messages may take a long time in delivery or because + of time zone differences. +} + + +cgi_puts "Select:[cgi_nl]" +cgi_button_list { + cgi_li "[cgi_bold "Date"] to sort by the date your messages were sent.<br> + cgi_li "[cgi_bold "From"] to sort by the name of the sender of the +message.<br> + cgi_li "[cgi_bold "To"] to sort your messages alphabetically according to the "To:" +line.<br> + cgi_li "[cgi_bold "Size"] to sort by the number of characters in the message.<br> + cgi_li "[cgi_bold "Subject"] to sort your messages alphabetically according to the +subject line.<br> + cgi_li "[cgi_bold "Ordered Subject"] to group messages with the same subject name and +put them into date order.<br> + cgi_li "[cgi_bold "Thread"] to present messages as a continuous chain grouped by +Subject. This sort is particularly helpful when viewing newsgroups.</ul> + +cgi_p +Once you have sorted your mail, the name of that sort (i.e. the column +heading) will be highlighted and an arrow will appear next to the name. To +reverse the sort order, click the arrow.</p> + +<!-- <p><i>{Do you want to change your default sort order? <a href="">Click +here</a> for that configuration option.[not implemented yet]}</i></p> --> + +cgi_p +cgi_anchor_name "aggregate">[cgi_bold "Operating on a set of messages"]</a><br> + +cgi_p +Operating on a set of messages is referred to as [cgi_italic "aggregate operations"]. +The way you perform aggregate operations is by placing a mark in the checkbox on +the line associated with the desired message, +and then choosing the operation to perform such as deleting or setting +other message flags, or saving them to a folder. + +cgi_p +The set of aggregate operations are either hidden or exposed. When +hidden you will see a <img src=../../images/slideout.gif style="vertical-align:middle"> tab on the left edge of the line +containing the sort names. Click the tab to expose the aggregate +commands and the checkboxes next to each message. Similarly, when aggregate operations are visible, you will see a +<img src=../../images/slidein.gif style="vertical-align:middle"> tab on the line containg the sort names. You can click this +tab to hide aggregate operations. + +cgi_p +When aggregate commands are exposed, the set of commands available is either +simple or complete. The simple set consists of only the ability to [cgi_bold "Delete"] +messages. When the simple mode is in effect, you will see a [cgi_bold "Delete"] button +and next to it the <img src=../../images/tabmore.gif style="vertical-align:middle"> tab +above the column of checkboxes. Click the <img src=../../images/tabmore.gif style="vertical-align:middle"> tab +to expose the complete set of commands. + +cgi_p +When the complete set of commands is visible, a <img src=../../images/tabless.gif style="vertical-align:middle"> +tab will be on the sort name row. Click it to return to the simple aggregate command set. + +cgi_p +The complete set of aggregate operations adds an additional display line above the sort names row. +It contains the [cgi_bold "Flag"] and [cgi_bold "Save"] commands. The choices above the checkbox column will change +as well into a dropdown list of alternative methods for setting or unsetting checkboxes. + +cgi_p +There are three ways to mark a message when the complete mode is in effect:</p> +<ul> + cgi_li "Select the checkbox next to the message or messages + cgi_li "Perform a Search using the [cgi_bold "Search/Mark..."] menu + cgi_li "Select [cgi_italic "Mark All"] from the [cgi_bold "Search/Mark..."] menu. +</ul> + +cgi_p +Lastly, the dropdown will offer a [cgi_bold "Zoom"] option. Choosing it will change the Message List by +hiding all of the unchecked messages from view. This is useful, for example, to examine a Search result +that may have marked only a few messages in a large folder. + +<!-- <p><i>{<a href="">Click here</a> to enable or disable aggregate +commands from this page. [not implemented yet]}</i></p> --> + +cgi_p +cgi_anchor_name "delete">[cgi_bold "Deleting Messages"]</a><br> +When you see the [cgi_bold "Delete"] option in the upper-right corner of +your Message List page, to delete messages: +<blockquote> +<ul> + cgi_li "Select the checkboxes next to the appropriate messages + cgi_li "Select [cgi_bold "Delete"] + cgi_li "Select [cgi_bold "Expunge"] to remove the messages from your folder +</ul> +</blockquote> + +When you are showing all of your aggregate operations (i.e. you +will see the [cgi_bold "Search/Mark..."] menu and the "Set Message Status" and +"Save Messages" operations), to delete: +cgi_division style= +<ul> + cgi_li "Select the checkboxes next to the appropriate messages by either +selecting them individually or use the [cgi_bold "Search/Mark..."] +menu options + cgi_li "Select [cgi_bold "Flag"] messages as Deleted + cgi_li "Select [cgi_bold "Expunge"] to remove the messages from your folder. +</ul> +</blockquote> + +cgi_p +If you do not see checkboxes to the left of your messages, all of your +aggregate operations are hidden. Click the tab to the left of your column +sort names to show [cgi_bold "Delete"], then click the tab next to [cgi_bold "Delete"] +if you want to see all the aggregate operations.</p> + +<!-- <p><i>{Do you want to Expunge without being prompted for a +confirmation? <a href="">Click here</a> to change that configuration +option. [not implemented yet]}</i> +cgi_p +{<i><a href="">Click here</a> to enable aggregate commands to have +this option available on this page. [not implemented yet]</i>}</p> --> + + +cgi_anchor_name "save">[cgi_bold "Saving messages to another folder"]</a><br> +"Save Messages" is only available from your Message List page when all of +your aggregate operations are showing. If you do not see "Save Messages" +on the top right-hand side of your page, some of your aggregate operations +are hidden. Click the tab to the left of your sort column headings to show +all of them. + +Select the checkboxes next to the messages you want to save to +another folder. Alongside the [cgi_bold "Save"] button, type in the name of the +folder to which you want the messages saved. The folder name can be one +that already exists, or you can create a new folder by typing in a new +name. If you have folder collections, select the correct one using the +dropdown menu. Select [cgi_bold "Save"] to save the message(s) into the folder +you have typed. + +cgi_p +The messages in your current folder that you have saved to another +will be flagged for deletion.</p> + + +cgi_anchor_name "flags">[cgi_bold "Setting status flags"]</a><br> +Immediately to the left of your message numbers is an underscore +reserved for your status flags: +cgi_button_list { + cgi_li "[cgi_bold "+"] message sent directly to your address (your address was in the To: line)" + cgi_li "[cgi_bold "*"] important message" + cgi_li "[cgi_bold "A"] answered message" + cgi_li "[cgi_bold "N"] new (unread) message" + cgi_li "[cgi_bold "D"] flagged for deletion (additionally the subject line will have a strike through it)" +</ul> + +cgi_p { + Select the underscore to go to a page where you can set or unset any of + your message status flags. +} + +cgi_anchor_name "search" +cgi_puts { + [cgi_bold "Searching"][cgi_nl] + You can search through your messages in your Message List using the + [cgi_bold "Search/Mark..."] dropdown menu. If you do not see the menu + (to the left of your sort column headings), some of your aggregate + commands are hidden. Click the tab in that area to show more commands. +} + +cgi_p { + Select one of the menu items under [cgi_bold "Search/Mark..."] to + find messages: +} +cgi_bullet_list { + cgi_li [cgi_italic "...by text"] + cgi_li [cgi_italic "...by date"] + cgi_li [cgi_italic "...by status"] +} + +cgi_puts { + Specify your search criteria on the next page. After you make your + selection, you will return to your Message List and the checkbox will be + selected for those messages found in your search. +} + +cgi_p { + If you want to display just those messages that were found in your + search, next select [cgi_bold "Zoom"] from the [cgi_bold "Search/Mark..."] menu list. + (Be aware that if you had other messages checked for selection before your + search, they will also be included in your zoomed view). +} + +if {0} { +<!-- <p><i>Note: If your browser is not javascript-enabled, after you make +your selection from the dropdown menu you will need to select the +<b>Do</b> button.</i></p> --> +} + diff --git a/web/cgi/alpine/1.0/help/release.html b/web/cgi/alpine/1.0/help/release.html new file mode 100644 index 00000000..3396a3b3 --- /dev/null +++ b/web/cgi/alpine/1.0/help/release.html @@ -0,0 +1,83 @@ +<HTML> +<HEAD> + +<!-- +# $Id: release.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> + +<TITLE>Alpine Release Information</TITLE> + +<STYLE TYPE='TEXT/CSS'> +BODY { background-color: #FEFAC9 ; font-family: Arial, sans-serif } +DL { padding: 0 18 } +DT { font-weight: bold } +DD { padding-bottom: 12 } +</STYLE> + +</HEAD> + +<BODY> + +<DIV STYLE="font-weight: bold; font-size: 16pt ; padding: 12" ALIGN="CENTER"> +<IMG SRC="../../images/logo/alpine/small.gif" STYLE="float: left; padding-left: 20"> +Alpine Release Highlights +</DIV> + +<DIV STYLE="background-color: white; padding: 24; margin: 20; border: 1px solid black"> +This page is used to publish the highlights of periodic updates. Bug fixes, explanations +for new features and so forth can typically be found here. +<P> +<H2>December 2007:</H2> + +<DL> +<DT>Web Alpine General Release</DT> +<DD> +<P> +This is the first release to the general public of the Web Alpine IMAP +client. It's built on the Alpine Mail System which itself is derived +from the Pine Mail System. Externally, besides numerous new features, +the most significant change is likely the new licensing. The Alpine Mail System +has been release under the Apache 2.0 license. + +<P> +Internally, there are significant changes. The code has been +restructured to partition mail data access routines from those +functions that provide the user interface. This allows development on +the mail engine proper to be easily reflected across the supported +interfaces. Similarly, each interface, Unix, Windows, and Web, can be +developed reasponably independently. +<P> +Similarly, significant work has been done to make Alpine more +international. Internally, message text and so forth is represented in +Unicode, and the groundwork has been laid to support status and +command translations. + +<P> +As for the Web Alpine IMAP client, it is an updated, evolutionary +improvement upon the Pine-based version that has been serving tens of +thousands of users daily on the University of Washington campus for +several years. It is not quite as fully featured as the other Alpine +mail tools, but is a reasonably solid and complete IMAP client. We +also tend to agree with many of its critics that it is a somewhat homely +interface, and we are taking significant steps toward addressing that +criticism. Stay tuned! + +</DD> +</DL> + +<P> + +</DIV> + +</BODY> +</HTML> diff --git a/web/cgi/alpine/1.0/help/reply.tcl b/web/cgi/alpine/1.0/help/reply.tcl new file mode 100644 index 00000000..32fb66ae --- /dev/null +++ b/web/cgi/alpine/1.0/help/reply.tcl @@ -0,0 +1,17 @@ +# $Id: reply.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +cgi_p +cgi_h2 "Reply Help" +cgi_p "Help pages for the Reply compose form will appear here." +cgi_p { + Someday. +} diff --git a/web/cgi/alpine/1.0/help/resume.html b/web/cgi/alpine/1.0/help/resume.html new file mode 100644 index 00000000..7a59e908 --- /dev/null +++ b/web/cgi/alpine/1.0/help/resume.html @@ -0,0 +1,28 @@ +<!-- +# $Id: resume.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<font size="+2"><b>Message Resume</b></font> + +<p>At the Message Resume screen, you can return to composing an unfinished +message that you have previously postponed. </p> + +<p>Click the radio button next to the message that you want to continue composing. Click +<input type=submit value="Resume Chosen Message"> to go to a Message Compose screen that +contains your postponed message.</p> + +<p>If you decide not to resume a message, Click <input type=submit value="Cancel">. Note, cancelling +on this screen will not remove any of your messages. To +remove a postponed message you must first click <input type=submit value="Resume Chosen Message"> +and then, on the Message Compose screen, click +<input type=submit value="Cancel">. + diff --git a/web/cgi/alpine/1.0/help/secure.html b/web/cgi/alpine/1.0/help/secure.html new file mode 100644 index 00000000..f44df381 --- /dev/null +++ b/web/cgi/alpine/1.0/help/secure.html @@ -0,0 +1,119 @@ +<HTML> +<HEAD> +<!-- +# $Id: secure.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<TITLE>Alpine with Session Encryption</TITLE> +<STYLE TYPE='TEXT/CSS'> +BODY { background-color: #F3F3F3 ; font-family: Arial, sans-serif } +</STYLE> +</HEAD> + +<BODY> + +<DIV STYLE="font-weight: bold; font-size: 16pt ; padding: 12" ALIGN="CENTER"> +<IMG SRC="../../images/logo/alpine-w-logo-small.gif" STYLE="float: left; padding-left: 20"> +Alpine with Session Encryption +</DIV> + +<DIV STYLE="background-color: white; padding: 24; margin: 20"> + +Web browser access to email is inherently slower than a desktop email +application. And while Alpine is designed to be as efficient as +possible, there remain certain performance obstacles that cannot be +easily overcome. + +<p> + +One obstacle is session encryption (also known as +<a href="http://www.washington.edu/computing/web/publishing/ssl.html">Secure +Socket Layer</a> or SSL). When session encryption is enabled, all +communication between the browser and the Alpine server is scrambled +such that an eavesdropper would find it extremely difficult to observe +the contents. When disabled, all communication, except for your +username and password, between the browser and Alpine server takes +place in clear text and is easily observable. + +<p> + +While encryption and decryption require some extra computing +resources, the heaviest performance cost has to do with default +browser behavior. Usually browsers retain a copy of pages and +their various elements, such as images, for a time with the intent of +avoiding costly network communication next time that page or a page +containing the same elements is requested. However, to be extra +careful of potentially exposing sensitive information, many browsers +default behavior is not to retain copies of elements retrieved over +encrypted connections. Thus, Alpine's performance cost has to +do with the browser re-requesting common elements on the various +Alpine pages. + +<p> + +Typically, from a computer connected directly to the campus network +(or other high-speed network such as DSL or cable-modem) this +performance cost is not noticeable. However, a user on a slower, +modem-connected computer can be severely effected. + +<p> + +There are two ways to work around this situation. One is to alter the +browser's configuration to retain elements on pages served securely. +The downside is that this setting often will then apply to all secure +pages, not just Alpine. The other work around is to disable session +encryption for Alpine. The downside is that communication between +the Alpine server and your computer, except for passwords, is +visible. + +<p> + +The likelihood that the communication will be observed depends on the +path the communication takes over the network. For example, while +using a computer in a campus lab or laptop connected to a wireless +hub, it is not unthinkable that someone on the local network may be +watching traffic. In such situations the communication speed is high +enough to offset the performance cost, so session encryption is a pretty +good idea. Similarly, communication between the Alpine server and a +computer connected to a campus modem, is not likely to travel +over a publicly accessible network, so malicious eavesdropping is much +less likely. Given the slower communication speed and reduced risk of +observation, disabling session encryption while connected via modem +is reasonable. + +<p> + +Alpine knows about the campus modem pools, and will adjust the +"Session Encryption" default setting based on whether or not +the browser you are using appears to be running on a computer +connected to a campus modem pool. Modem pool connections will +default to <b>not</b> using session encryption. All other connections +will default to using session encryption. That is, a computer on the +campus network or connected to a network or dial-in service outside +the UW will have its Alpine session encrypted unless you uncheck the +box labelled "SSL Session Encryption." If you are on a slow +connection and confident that your connection is not likely to travel +any hostile path, or otherwise decide the performance benefit +outweighs the risk of observation, then unchecking the box may be a +reasonable option for you. + +<p> + +Please note: Session encryption <i>only</i> ensures that communication +between your browser and the Alpine server is secure. It does not +mean email messages you send from Alpine are in any way safe from +observation or otherwise confidential. + + +</DIV> +</BODY> +</HTML> diff --git a/web/cgi/alpine/1.0/help/takeaddr.html b/web/cgi/alpine/1.0/help/takeaddr.html new file mode 100644 index 00000000..053b9063 --- /dev/null +++ b/web/cgi/alpine/1.0/help/takeaddr.html @@ -0,0 +1,34 @@ +<!-- +# $Id: takeaddr.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<FONT SIZE=+2><B>Take</B></FONT> + +<P> + +Use <b>Take</b> to capture addresses from your current email message and +put them into your address book. All the email addresses contained within +your message will be listed as choices for entry into your address book. + +<p> + +<p> Click the check-box next to the address or addresses you would like to +take to your address book. Click one check-box if you want to add just +that single address. Click more than one check-box to create a group +mailing list, which will link those addresses to one nickname in +your address book. After you make your selection, click <b>Take +Address</b> to then complete your address book entry, or click +<b>Cancel</b> to return to your email message without altering anything. + +<p> If you have more than one address book, you will see a pull-down menu. +Use that menu to select among your defined address books. +</p> diff --git a/web/cgi/alpine/1.0/help/takeedit.html b/web/cgi/alpine/1.0/help/takeedit.html new file mode 100644 index 00000000..18d18392 --- /dev/null +++ b/web/cgi/alpine/1.0/help/takeedit.html @@ -0,0 +1,63 @@ +<!-- +# $Id: takeedit.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<FONT SIZE=+2><B>Address Book Entry - Take</B></FONT> +<P> + +To complete your entry, supply the following information for +your address book: + +<P> +<UL TYPE=square> +<LI><a href="#nick"><b>Nickname</b></a> +<LI><a href="#fullname"><b>Full Name</b></a> +<LI><a href="#addresses"><b>Addresses</b></a> +<LI><a href="#fcc"><b>Fcc</b></a> +<LI><a href="#comments"><b>Comments</b></a> +</UL> + +<a name="nick"><b>Nickname</b></a><br> +The nickname you choose will identify this address book entry. Every +address book entry is required to have a nickname associated with it. +Use the nickname in place of an address on the Message Compose page and +<b>Expand</b> will fill in the address or addresses for this entry. The +nickname is not seen in the outgoing message. + +<p> +<a name="fullname"><b>Full Name</b></a><br> +This optional field is for the full name for this entry. For an individual +entry, you will ordinarily use that person's name. For a group of +addresses (or distribution list), use a descriptive word or phrase that +describes the group. Edit existing names by typing in the field. + +<p> +<a name="addresses"><b>Addresses</b></a><br> +This required field will be filled in with the addresses you selected from +your email message. Group mailing lists will have addresses separated by +commas. + +<p> +<a name="fcc"><b>Fcc</b></a><br> +The "Folder carbon copy" field gives you the ability to save a copy of the +messages you send to the folder name you put here. The Fcc name will be +used instead of your default Fcc folder (usually "sent-mail") when you +use this address book entry as the first address in To: line of messages +you compose. + +<p> +<a name="comments"><b>Comments</b></a><br> +This is a comment you can add for your convenience. This field is not +used in your outgoing messages. + +<p>When finished, click <b>Save</b> to update your address book, or +<b>Cancel</b> to return to the message view without making any changes. diff --git a/web/cgi/alpine/1.0/help/tech-notes.html b/web/cgi/alpine/1.0/help/tech-notes.html new file mode 100644 index 00000000..7f275620 --- /dev/null +++ b/web/cgi/alpine/1.0/help/tech-notes.html @@ -0,0 +1,471 @@ +<html> +<head> +<!-- +# $Id: tech-notes.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +</head> +<body> +<font size=+3><b>Web Alpine Technical Notes</b></font> + +<!-- history: originally prepared for AIT, 22 October 2002 --> +<!-- history: updated for initial campus release, 19 Apr 2004 --> + +<h2>Why Web Alpine</h2> + +Web Alpine was originally conceived as a means of providing reliable, +ubiquitous, and consistent access to UW email facilites via the Interactive +Message Access Protocol (IMAP). As with Pine, it is intended to present a +simple, approachable interface that can be easily navigated with +minimal familiarity. It is also intended to be as efficient as +possible, in both page-service and user navigation while meshing +as neatly as possible with the central campus IMAP infrastructure. + +<p> + +<h2>How Web Alpine</h2> + +<p> + +Web Alpine's foundation rests firmly on Unix Alpine's many years of +development and deployment. It's core element is a per-session server +(or serverette) that provides data to the scripts generating the web +pages the users sees and manages the connection to the IMAP mail +server where the user's mail resides. This serverette is literally +built from the same Alpine sources used to build the Unix Alpine and +PC-Alpine mail user agents. Thus, it inherits most of the efficiency, +such as data caching and request ordering and grouping, that has been +built into Alpine, as well as many of the features and functions. + +<p> + +<h3>Components</h3> +<p> + +<table width=80% align=center border=0 cellpadding=8> +<tr> + <td valign=top align=left><b>Browser</b></td> + <td>Performs usual browser role: sends requests, renders responses and displays or hands off for display non-HTML data</td> +</tr> +<tr> + <td valign=top align=left nowrap><b>Web Server</b></td> + <td>Performs extraordinary web server role: produces HTML responses to requests, maintains relationship between user's browser and IMAP server for the life of the user's session.</td> +</tr> +<tr> + <td valign=top align=left nowrap><b>IMAP Server</b></td> + <td>Performs usual mail server role: provides access to the various bits and pieces of mail data via Interactive Message Access Protocol</td> +</tr> +</table> +<p> +<div align=center> +<img src=wpsys.jpeg> +</div> +<p> + +<h3>Protocols, Services, Technologies</h3> +<p> + +<table width=80% align=center> +<tr><td> + <dl> + <dt><b>HTTP(s)</b></dt> + <dd>Protocol between browser and web server. Common language allowing users to get at their mail from the widest variety of platforms and locations.</dd> + <dt><b>IMAP(s)</b></dt> + <dd>Broadly implemented distributed mail protocol which permits users to access mail from a variety of + clients: web alpine, pine, pc-pine, outlook express, eudora.</dd> + <dt><b>Pubcookie</b></dt> + <dd>Secure, distributed web-based authentication service optionally used as the mechanism to authenticate users in the Web Alpine login process.</dd> + <dt><b>GSSAPI</b></dt> + <dd>SASL authentication mechanism used to establish session between Web Alpine serverette and IMAP server on behalf of Pubcookie authenticated user.</dd> + <dt><b>Tcl</b></dt> + <dd>Tool Command Language. Chosen CGI scripting language for the Web Alpine page templates. Reasonable + language, reasonably implemented, reasonably supported, particularly well suited for exporting functionality + in pre-existing C-based tools.</dd> + <dt><b>Unix Domain Sockets</b></dt> + <dd>Communication channel used to pass requests/responses between Tcl interpreters processing scripts and web alpine serverette.</dd> +</dl> +</td></tr> +</table> +<p> + +<h3>Web Alpine Distribution Layout</h3> +<p> +The Web Alpine application consists of three main components; the CGI scripts that generate pages containing the user's email data, +a serverette running on the http server spanning the life of the user's session, and a couple of libraries +to aid page generation and serverette communciation. + +<p> +Web Alpine is packaged as part of the Alpine Distribution and it's source resides +within the <tt>web/</tt> subdirectory. Subdirectories are organized by the service +the provide, and breakdown as follows: +<p> +<table border=0 xbgcolor="#dddddd" align=center width="90%" cellpadding=2> +<tr> + <td valign=top><tt>bin/</tt></td> + <td></td> + <td></td> + <td valign=top>Contains scripts and generated binaries that initiate and maintain Web Alpine sessions. + </td> +</tr> +<tr> + <td valign=top><tt>cgi/</tt></td> + <td></td> + <td></td> + <td valign=top>Contains scripts referenced by the browser to generate the Web Alpine interface. + Subdirectories within organize scripts by function, and allow for suitable scoping + of session key. + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>alpine/</tt></td> + <td></td> + <td valign=top>Browser's view of Web Alpine application. Contains scripts to generate pages + the user interacts with. + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>session/</tt></td> + <td></td> + <td valign=top>Scripts referenced by the browser to manage session initiation. + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>images/</tt><br><tt>sounds/</tt><br><tt>pub/</tt></td> + <td></td> + <td valign=top>Scripts and data that don't require restricted access control. + </td> +</tr> +<tr> + <td valign=top><tt>config/</tt></td> + <td></td> + <td></td> + <td valign=top>Server configuration scripts, default settings. + </td> +</tr> +<tr> + <td valign=top><tt>lib/</tt></td> + <td></td> + <td></td> + <td valign=top>Contains components to support IPC, CGI processing and HTML generation. + </td> +</tr> +<tr> + <td valign=top><tt>src/</tt></td> + <td></td> + <td></td> + <td valign=top>Contains source files for Web Alpine's binary components which will be linked + against the <tt>pith/</tt> libarary components. + </td> + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>alpined.d/</tt></td> + <td></td> + <td valign=top>Source files for <tt>alpined</tt> serverette. This is a per-user, per-session + server that services requests for email data from the CGI scripts via UNIX domain + socket. + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>pubcookie/</tt></td> + <td></td> + <td valign=top>Source files providing UW Pubcookie web authentication support. + </td> +</tr> +<tr> + <td></td> + <td valign=top><tt>cgi.tcl-1.10/</tt></td> + <td></td> + <td valign=top>Source for TCL library providing CGI/HTML support + </td> +</tr> +<tr> + <td valign=top><tt>detach@</tt></td> + <td></td> + <td></td> + <td valign=top>Typically a symbolic link to a subdirectory within <tt>/tmp</tt>. It is used to hold temporary + copies of message attachments as they're downloaded to the browser. +<table width="100%" align=center bgcolor="#dddddd"><tr><td> +In the pubcookie case, it must have world read/write/execute mode set due to +<tt>alpined</tt> pseudo-uid partitioning. +</td></tr></table> + +</tr> +</table> + +<p> + +<h2>Web Alpine Configuration</h2> +<h3>CGI Script Configuration</h3> +<p> +Most Web Alpine configuration is contained in the <tt>config/alpine.tcl</tt> configuration file. +Most of the interesting settings are toward the top of the file and pretty much suggest +what they set. The most important settings, though, are probably: + +<table width="80%" align=center> +<tr><td> +<dl width=80%> +<dt> + <tt>_wp(fileroot)</tt> +</dt> +<dd> +that defines where the Web Alpine application was unpacked on your system, and +</dd> +<dt> +<tt>_wp(urlprefix)</tt> +</dt> +<dd> +which defines where browsers can find Web Alpine's CGI scripts. This is set to +the null string if the server's DocumentRoot is synonymous with the root of +Web Alpine's CGI directory. Othewise, it's typically set to the Alias accessed +subdirectory in the web server's configuration. + +</dd> +</dl> +</td></tr> +</table> + + +<h3>Web Server Configuration</h3> +<p> +Typically, a Web Alpine server is used solely to serve Web Alpine pages. That is, no other hosting is +done by the server. Thus, it is usually convenient to configure the web server to treat +the <tt>web/cgi/</tt> directory within the distribution as the root directory of the pages +it serves (or to move those files and directories into the web server's document root). +Similarly, it may be necessary to configure the web server to process CGI scripts from +it's root (since this <em>should</em> be a dedicated server this shouldn't matter). + +<h3>IMAP Server Configuration</h3> +<p> +Genarally, no configuration is required of the IMAP server. +<table width="75%" align=center bgcolor="#dddddd"><tr><td> +However, in the Pubcookie case the Web and IMAP servers need to coordinate the +existence of a meta-user, such as <tt>webalpine</tt>, used for SASL proxy authentication. For UW imapd this +means creating an account on the IMAP server that is a member of the <tt>"mailadm"</tt> +group. A SASL GSSAPI authentication handshake is used between the +Web and IMAP server when the web server initiates a session on behalf of +a particular user. +</td></tr></table> + +<h3>User Configuration</h3> +<p> +Since no user-initiated local file or mailbox access is permitted by (much less compiled into) the <tt>alpined</tt>, +user configuration and data files are stored using Pine's remote pinerc and address book capabilites. The configuration +settings in <tt>web/config/</tt> are used to set per-user defaults and direct Web Alpine toward the user's configuration +settings on the IMAP server. Similarly, the default addressbook is stored as an IMAP folder on the server as well. +Concurrent Web Alpine, Unix Pine and PC-Pine users that would like a consistent mail environment can easily configure their +other Pine's to use the <tt>remote_pinerc</tt> and <tt>remote_addrbook</tt> on their IMAP server. + +<h3>Browser Configuration</h3> +<p> +A Web Alpine goal is to run reasonably on as many browsers as possible. Toward that end, little beyond basic table and form support +is required of the browser. And while Javascript is not a requirement to access Web Alpine functions, when enabled in the browser +some enhanced capability is available such as keyboard accessible commands and implicit selection of various listbox choices. + +<h2>Session Lifecycle</h2> +<p> + +<ol> + <li>User requests <tt>greeting.tcl</tt> which consists of a form to be filled out with any necessary authentication tokens and mail server choice. + <table width="75%" align=center bgcolor="#dddddd"><tr><td> +In Pubcookie case user is not presented the username/password option unless they have chosen to +connect to a mail server outside the locally managed, predefined set. + </td></tr></table> + <li>User submits form with authentication tokens and initial mail server + <table width="75%" align=center bgcolor="#dddddd"><tr><td> +By default, the submitted authentication tokens consist of a username/password pair. When Pubcookie is +in use, the browser sends the pubcookie-specific authentication token with the form submission. + </td></tr></table> + + <li>Web Alpine CGI logon script processes form and instantiates serverette. The logon script: + <ol> + <li>validates form data + <li>generates session key + <li>launches the Web Alpine serverette, <tt>alpined</tt>, passing session key via stdin + <table width="75%" align=center bgcolor="#dddddd"><tr><td> +<tt>serverette</tt> reads session key, creates Unix domain socket, and enters command loop +waiting for input on the fresh socket + </td></tr></table> + <li>sends serverette the command to establish a session with the requested IMAP server on behalf of the given user + <table width="75%" align=center bgcolor="#dddddd"><tr><td> +By default, the login script simply passes the username/password pair to the serverette where +it's the serverette's job to present them to the IMAP server for validation. If the IMAP server +declines, a "bad user or password" error page is generated and sent to the browser and the serverette + exits. +<p> +The Pubcookie case is a bit more involved. The CGI scripts rely on the netid specified in the REMOTE_USER +environment variable which is set as a side effect of pubcookie module processing. The trusted netid +is not passed directly to the serverette, rather all CGI processing is done via a setuid Tcl interpreter. +The uid is unique to each netid on the system, but not related to any netid/uid binding on general access +systems. Running the CGI scripts and serverette under a netid-bound uid provides a convenient way to implement +the authentication mechanism between the serverette and the IMAP server as well as a useful way to partition +serverettes such that one compromised serverette can't affect others. + </td></tr></table> + + <li>With a valid IMAP session established, the logon script redirects the user's browser to the initial + Message List page. + </ol> + <li>The user navigates/manipulates their email environment based on web pages generated by Tcl script +templates which were fleshed out via requests to the <tt>alpined</tt> serverette. The serverette in turn +may draw on its cache of IMAP data, make new requests of the IMAP server, post messages via SMTP or +the local mail queue, formulate LDAP queries, or perform other tasks as required. + <table width="75%" align=center bgcolor="#dddddd"><tr><td> +Note: Web Alpine sessions run as long as the user's browser requests pages. In the absense of user interaction +Web Alpine will self-refresh every few minutes to mainain the session. Sessions only end when the user logs out +or closes the browser. + </td></tr></table> + <li>User ends session and confirms + <table width="75%" align=center bgcolor="#dddddd"><tr><td> + Note: If the user simply closes their browser, the serverette will self-exit after 30 minutes. + </td></tr></table> +</ol> + +<h3>Web Server Considerations</h3> +<p> +Web Alpine has been developed under Apache (versions 1.x thru 2.x). However, because the intent was to be as flexible +and manageable as possible, little aside from SSL and basic CGI services are required of the web server. It's +conceivable Web Alpine could be made to run under another server, or even Windows and IIS modulo the UNIX-Sockets communication +issues between the CGI scripts and <tt>alpined</tt>. + +<p> +The downside, of course, is that this requires somewhat redundant +parses of the configuration and CGI-helper library with each page request. It's a trade-off. A slightly more efficient approach might be to create +an apache module that understands requests and passes them directly to the corresponding <tt>alpined</tt> which would execute the script and return +HTML directly. However, the additional cost in installation and management complexity stands to offset those gains. + +<p> +Similarly, it is <bold>assumed</bold> that the Web Alpine service is provided on a black box server. That is, a host +that has no general user accounts. Unmodified, Web Alpine creates the UNIX-domain sockets corresponding +pretty directly to the user's session key in the <tt>/tmp</tt> directory. In addition, depending on the nature +of the connection, the session key may also be exposed via oridinary httpd logging. <em>Important safety tip:</em> make +sure ordinary users do not have access to the Web Alpine system or httpd log files. In the future those sockets may be moved into +a access-restricted subdirectory, but the httpd log file record may be harder, and less reliably concealed. + +<h3>CGI Considerations</h3> +<p> + +Most Web Alpine pages are generated via CGI scripts written in Tcl. A +library of Tcl functions called <tt>cgi.tcl</tt> is used heavily to +help with the HTML generation. Of course, this means that a web +developer that might wish to change or enhance Web Alpine pages, will have +to acquire some Tcl knowledge. Additionally, the library has one or two +interface inconsistencies (not unlike Tcl, but that's another +discussion), which will mean a bit steeper learning curve, but we +think this is only slightly more difficult than the amount of Tcl +one would have to learn in a more template-oriented approach. We think +the scipt's logic flow and such is much easier to understand +and maintain than the substitution and recursion necessary in an +html-template approach. + +<p> + + +<h3><span style="font-family: monospace; font-size: big">alpined</span> Considerations</h3> +<p> +Tcl, incidentally, is also the language used to move data in and out +of the Web Alpine serverette, <tt>alpined</tt>. Tcl lends itself nicely +to string oriented data, and provides a convenient, simple interface +to export functionality contained in C-based utilities. + +<h3>HTML Considerations</h3> +<p> +Much of the HTML generated by Web Alpine does layout based on tables. This somewhat sub-optimal state +mostly has to do with when the Web Alpine development effort was initiated and the concurrent browser +chaos. The goal is to move scripts toward generating more CSS-oriented layout over time. + +<p> +Similarly, earlier versions of Web Alpine relied heavily on Javascript in a misguided attempt to make the +browser-based experience feel as familiar as possible to a dedicated desktop application. Beyond the fact that +Javascript support varied widely across browsers at the time, it should have also been obvious that +by presenting a familiar desktop-like interface, we also set desktop-like performance +expectations which we had no hope of meeting. + +<h3>Clustering Considerations</h3> +<p> +Since <tt>alpined</tt> persists for the life of the user's session, the session is bound to the particular +server that initiated it. In order to provide service to a sizeable constituency, it may be necessary to spread usage across +a group or cluster of servers. There exist numerous strategies to distribute connecting users across a cluster, such +as an initial server that redirects randomly to one of the servers in a cluster, DNS-based randomizing, or load-balancing +strategies. The former can lead to web server names users find distracting (though this doesn't appear to be to +much of an issue) and the latter, of course, could lead to misdirected requests over time (or as loads change) so +it is necessary for servers to either redirect or proxy requests to the appropriate server. +<p> +As a basic allowance for such installations, Web Alpine's session key +contains the hostname of the server that created it. Similarly, the +access routines that parse the key for access to the appropriate +<tt>alpined</tt> are aware of the hostname and will redirect +misguided requests to the appropriate server. This isn't particularly +satisfying in terms of network RTTs. +<p> +One alternative that saves network performance +at the expense of slightly increased server load is to introduce a +directory above the <tt>web alpine/</tt> script directory and then add one +along side that new directory for each server in the cluster. It's then possible to use the Apache +directive to proxy requests within the scope of those directories to +the corresponding server. + +<h3>Security Considerations</h3> +<p> +<ul> +<li>Session keys only valid for life of session. Can't acquire increased or prolonged rights based on key. +<li>Link layer (ssl) encryption available (and likely the default in most situations) +<li><tt>alpined</tt> pseudo-uid partitioning is employed in the pubcookie context +</ul> +<p> + +<h2>Future Plans</h2> +<p> +Through the semi-formal usability testing process, early testing +phases and regular campus use, overall response has been very favorable. +Usability testing concurrent with ongoing feature development and interface adjustments +continues to hone rough edges, particularly where the drive for performance has led to +less intuitive interface choices. We plan to continue emphasis on the refine/feedback +loop as we roll in many of the features Pine users have come to appreciate. + +<p> +Performance in terms of both user perceived response time and users per web server are +always a concern, but must, of course, be balanced against additional maintenance and complexity costs. +Less obvious complicating factors must be considered, such as <tt>alpined</tt> process partitioning +and session-key containing cookie exposure in the face of malicous HTML attachments. +We plan, of course, to continue exploring various methods to improve performance. + +<h2>Appendix: Installation Tests</h2> +<p> +For the most part, if you can get the login greeting page and +then log into a session, things should be working for the +most part. Some things you might try to verify +a complete installation include: + +<ul> +<li>Open a secondary folder</li> +<li>Go back to Inbox</li> +<li>View or Save an attachment</li> +<li>Send a message</li> +<li>Send a message with an attachment</li> +<li>Spell check a message (if is ispell installed on the web server)</li> +<li>Create an address book entry</li> +<li>Delete an address book entry</li> +<li>Save a message to a new folder</li> +<li>Verify the new folder appears in the cached folder drop down</li> +<li>Logout, Verify the folder appears in drop down list of subsequent session</li> +<li>Try configuration settings such as Enable Full Headers</li> +<li>Logout, Verify the setting change in subsequent session</li> +</ul> + + +</body> +</html> diff --git a/web/cgi/alpine/1.0/help/view.html b/web/cgi/alpine/1.0/help/view.html new file mode 100644 index 00000000..0560ad2b --- /dev/null +++ b/web/cgi/alpine/1.0/help/view.html @@ -0,0 +1,195 @@ +<!-- +# $Id: view.html 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +--> +<form action="alpine/wp.tcl" target="noop" method=get> +<input name="page" value="noop" type=hidden notab> +<font size="+2"><b>Message View</b></font> + +<p>The Message View is where you will read, forward, and reply to your mail.</p> + +<UL TYPE=square> + <li><a href="#navigate"><b>Navigating your messages</b></a></li> + <li><a href="#attach"><b>Viewing attachments</b></a></li> + <li><a href="#reply"><b>Replying to the message</b></a></li> + <li><a href="#forward"><b>Forwarding the message</b></a></li> + <li><a href="#save"><b>Saving the message to another folder</b></a></li> + <li><a href="#take"><b>Adding addresses directly to address book</b></a></li> + <li><a href="#header"><b>Displaying full headers</b></a></li> + <li><a href="#print"><b>Printing</b></a></li> + <li><a href="#jump"><b>Jump Command (optional)</b></a></li> + <li><a href="#note"><b>Differences from Pine and PC-Pine</b></a></li> +</ul> + +<a name="navigate"><b>Navigating your messages</b></a><p> +In the far left column of the Message View screen, there are four navigation options: <b>Previous</b>, <b>First</b>, <b>Next</b>, +<b>Last</b>. Click: +<table border=0 cellpadding=4 style="margin-left:24"> + <tr> + <td><img src="../../images/but_rnd_prev3.gif" alt="Previous"></td> + <td>to go to the previous message in this folder</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_first3.gif" alt="First"></td> + <td>to go to the first message in this folder</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_next3.gif" alt="Next"></td> + <td>to go the next message in this folder</td> + </tr> + <tr> + <td><img src="../../images/but_rnd_last3.gif" alt="Last"></td> + <td> to go to the last message in this folder</td> + </tr> +</table> +<p> + +With most broswsers and the usual settings, you also have the option of +using keyboard controls for some of your navigation. You may, however, +need to first click in your Alpine window to make sure that your system +knows which screen is active. + +<p>The keyboard controls are: +<table border=0 cellspacing=12 cellpadding=3> +<tr><td text align="center">n</td> + <td>next message</td></tr> +<tr><td text align="center">p</td> + <td>previous message</td></tr> +<tr><td text align="center">i</td> + <td>return to message index</td></tr> +<tr><td text align="center">c</td> + <td>compose new message</td></tr> +<tr><td text align="center">l</td> + <td>list folder</td></tr> +<tr><td text align="center">d</td> + <td>flag message as deleted</td></tr> +<tr><td text align="center">u</td> + <td>unflag message as deleted</td></tr> +<tr><td text align="center">a</td> + <td>go to address book</td></tr> +<tr><td text align="center">r</td> + <td>reply to current message</td></tr> +<tr><td text align="center">f</td> + <td>forward current message</td></tr> +</table> + +<p> +<a name="attach"><b>Viewing attachments</b></a><p> +When a message includes an attachment, you will see highlighted links +under the heading "Parts/Attachments." Click either "View" or the link +description to see the attachment. Click "Save" to +download the attachment. + +<p>The attachment links also allow you to read messages delivered as HTML. +Simply view the second attachment to display the message as intended. + +<p>If you cannot view your attachments, go to +<b>Configuration</b> + and click the Message View tab. Make sure "Enable Attachments View" is marked.</p> +<p> + +<a name="reply"><b>Replying to the message</b></a><p> +Use <input type=submit value="Reply"> to respond to the author of the message and/or to the +other recipients who were sent the original message. + +<p>To respond to all original recipients, check "<input type=checkbox checked> To All" and then click +<input type=submit value="Reply">.</p> + +<p>By default, "Include text" will be checked. If you do not want to +include the previous text in your reply, remove that checkmark before you +click <input type=submit value="Reply">.</p> + + +<a name="forward"><b>Forwarding the message</b></a><p> +Use <input type=submit value="Forward"> to send the message you are +viewing to someone else. +You will need to supply the email address of the new recipient on the +subsequent Message Compose screen.</p> + + + +<a name="save"><b>Saving the message to another folder</b></a><p> + +Save the message you are viewing to another folder by choosing from +the options in the dropdown menu next to the +<input type=submit value="Save"> button. Among the Save options, +you'll find + +<ul> + <li> The name of the default folder to save to, typically <font face="courier">saved-messages</font>. + <li> Several, typically six, names of folders you have most recently saved messages to + <li> An option to type in directly the name of the folder you wish to save to (either a new folder you wish to create, or one +already containing messages) + <li> An option to choose the folder from the list of all your folders +</ul> + +If Alpine does not act on your choice immediately, click the <input type=submit value="Save"> +button to initiate saving. Once saved, the chosen messages will be marked for deletion. + + +<p> +<a name="take"><b>Adding addresses directly to address book</b></a></p> +Click <input type=submit value="Take"> on the top panel of +your screen to go to a listing of all the email addresses contained within +this message. Click next to any or all of those addresses to add them +to your addressbook.<p> + +<a name="header"><b>Displaying full headers</b></a><p> +Click the <img src="../../images/hdr.gif" alt="display full headers"> icon +near the top right of your screen to view your full headers. The full +headers contain information about the path taken by this email message. To +return to digested headers, click <img src="../../images/hdrnon.gif" alt="display digested headers">.<p> + + +<a name="print"><b>Printing</b></a><p> +Click the <img src="../../images/printer2.gif" alt="print"> icon near the top +right +of your screen to print your message. + +<p>If you lose the right edge of your message, you may want to decrease +your font size: + +<ol> +<li>Click <b>Configure</b> +<li>Click the "General" tab on the subsequent screen +<li>Choose "small font" or "smallest font" from the drop down box next to +<b>Font Size?</b> +</ol> + + +<p><a name="jump"><b>Jump Command (optional)</b></a><p> + +Depending on your configuration, you may also see a text box next to a +<input type=submit value="Jump"> button on the left side of the page. Enter a +message number into the text box and click the button to have that message +number's text displayed. + + +<p><a name="note"><b>Differences from Pine and PC-Pine</b></a><p> + +<p>Alpine is designed primarily for easy access to email. It is not +intended to replace any other heavy duty email programs. Accordingly, it +is missing some of the more advanced features you will find in Pine and +PC-Pine. As development continues, features will be added as long as they +do not make a large impact on Alpine's speed or efficiency. + +<p> Some of the features you will not currently find in Alpine Message +View: +<ul> +<li>Change message status (available on Message List page) +<li>Bounce +<li>Go directly to a specific folder (may be added soon) +<li>Where is (instead, use your browser's "find" command) +<li>Export message +</ul> +</form> + diff --git a/web/cgi/alpine/1.0/help/wpsys.jpeg b/web/cgi/alpine/1.0/help/wpsys.jpeg Binary files differnew file mode 100644 index 00000000..ba601d85 --- /dev/null +++ b/web/cgi/alpine/1.0/help/wpsys.jpeg diff --git a/web/cgi/alpine/1.0/helpbody.tcl b/web/cgi/alpine/1.0/helpbody.tcl new file mode 100755 index 00000000..1adbf1e3 --- /dev/null +++ b/web/cgi/alpine/1.0/helpbody.tcl @@ -0,0 +1,200 @@ +#!./tclsh +# $Id: helpbody.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# helpbody.tcl +# +# Purpose: CGI script to generate html help text for Web Alpine + +# Input: +set help_vars { + {topic "" about} + {topicclass "" ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +set sections { + {about 0 "About Web Alpine" about} + {index 0 "Message List" index} + {view 0 "Message View" view} + {take 1 "Take Address" takeaddr} + {takeedit 1 "Take Address Edit" takeedit} + {folders 0 "Folder List" folders} + {foldiradd 1 "New Folder or Directory" foldiradd} + {compose 0 Compose compose} + {addrbrowse 1 "Address Browse" addrbrowse} + {attach 1 "Attach" attach} + {resume 0 "Resume" resume} + {addrbook 0 "Address Books" addrbook} + {addredit 1 "Edit Entry" addredit} +} + +set hidden_sections { + {filtconf 0 "Filter Configuration" filtconf} + {filtedit 0 "Filter Editor" filtedit} +} + +proc WPHelpTopic {topic} { + source genvars.tcl + foreach g [list general_vars msglist_vars composer_vars folder_vars address_vars msgview_vars rule_vars] { + foreach m [set $g] { + if {[string compare $topic [lindex $m 1]] == 0} { + return [lindex $m 2] + } + } + } + + return $topic +} + +WPEval $help_vars { + foreach s $sections { + if {[string compare $topic [lindex $s 0]] == 0} { + set helpfile [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) help [lindex $s 3]] + } + } + + if {![info exists helpfile]} { + foreach s $hidden_sections { + if {[string compare $topic [lindex $s 0]] == 0} { + set helpfile [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) help [lindex $s 3]] + } + } + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Web Alpine Help" + WPStyleSheets + } + + cgi_body_args + cgi_body BGCOLOR=white "style=margin:16;margin-right:40;margin-bottom:64" { + if {[info exists helpfile]} { + if {[file exists ${helpfile}.tcl]} { + source ${helpfile}.tcl + } elseif {[file exists ${helpfile}.html]} { + + cgi_puts "<form action=\"[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl\" target=\"noop\" method=get>" + cgi_puts {<input name="page" value="noop" type=hidden notab>} + + if {[catch {open ${helpfile}.html r} fid]} { + unset helpfile + } else { + cgi_put [read $fid] + close $fid + } + } else { + unset helpfile + } + + cgi_puts "</form>" + } + + if {[info exists helpfile] == 0} { + if {[string length $topicclass] && [catch {WPCmd PEInfo help $topic $topicclass} helptext] == 0 && [llength $helptext]} { + set shownvarname [WPHelpTopic $topic] + + # rough once-over to digest it for suitable display in the alpine context + set show 1 + foreach line $helptext { + switch -regexp -- $line { + {^<[/]?[hH][tT][mM][lL]>.*} - + {^<[/]?[tT][iI][tT][lL][eE]>.*} - + {^<[/]?[bB][oO][dD][yY]>.*} { + continue + } + {^<!--chtml if pinemode=.*} { + if {[regexp {^<!--chtml if pinemode=["]([^"]*).*} $line dummy mode] + && [string compare $mode web] == 0} { + set show 1 + } else { + set show 0 + } + } + {^<!--chtml else[ ]*-->} { + set show [expr {$show == 0}] + } + {^<!--chtml endif-->} { + set show 1 + } + default { + if {$show} { + set urls {} + while {[regexp {<[aA] ([^>]*)>} $line urlargs]} { + lappend urls $urlargs + if {[regsub {(.*)<[aA] ([^>]*)>(.*)} $line "\\1___URL___\\3" line] == 0} { + break + } + } + + # special locally expanded markup + set exp {<!--[#]echo var=([^ ]*)-->} + while {[regexp $exp $line dummy locexp]} { + set locexp [string trim $locexp {"}] + switch -regex $locexp { + ^FEAT_* { + set locexp [WPHelpTopic [string range $locexp 5 end]] + } + ^VAR_* { + set locexp [WPHelpTopic [string range $locexp 4 end]] + } + } + + if {[regsub $exp $line $locexp line] == 0} { + break + } + } + + if {[info exists shownvarname]} { + regsub -all -nocase $topic $line $shownvarname line + } + + foreach url $urls { + if {[regsub {.*[Hh][Rr][Ee][Ff]=[\"]?([^ \">]*)[\"]?.*} $url {\1} href]} { + set newurl "<a href=helpbody.tcl?topic=$href\\&topicclass=plain>" + } else { + set newurl "" + } + if {[regsub {(.*)___URL___(.*)} $line "\\1$newurl\\2" line] == 0} { + break + } + } + + cgi_puts $line + } + } + } + } + } else { + cgi_center { + cgi_put [cgi_img [WPimg dot2] height=50] + cgi_put [cgi_font class=notice "Help text for [cgi_italic $topic] doesn't exist yet, but when it does it'll appear here."] + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/helpindex.tcl b/web/cgi/alpine/1.0/helpindex.tcl new file mode 100755 index 00000000..235e619d --- /dev/null +++ b/web/cgi/alpine/1.0/helpindex.tcl @@ -0,0 +1,102 @@ +#!./tclsh +# $Id: helpindex.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +# +# helpindx.tcl +# +# Purpose: CGI script to generate html help text for Alpine +# +# Input: + +set help_vars { + {topic "" about} + {index "" ""} + {oncancel "" main} + {params "" ""} +} + +# +# +# Output: +# +# HTML/Javascript/CSS help text for Alpine +# + + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +set help_menu { +} + +set sections { + {about 0 "About Alpine" about} + {index 0 "Message List" index} + {view 0 "Message View" view} + {take 1 "Take Address" takeaddr} + {takeedit 1 "Take Address Edit" takeedit} + {folders 0 "Folder List" folders} + {foldiradd 1 "New Folder or Directory" foldiradd} + {compose 0 Compose compose} + {addrbrowse 1 "Address Browse" addrbrowse} + {attach 1 "Attach" attach} + {resume 0 "Resume" resume} + {addrbook 0 "Address Books" addrbook} + {addredit 1 "Edit Entry" addredit} +} + + +WPEval $help_vars { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Web Alpine Help" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + lappend help_menu [list {} [list {cgi_put [cgi_nl][cgi_url [cgi_bold "Exit Help"] wp.tcl?page=${oncancel}&cid=[WPCmd PEInfo key]&x=[clock seconds] target=_top class=navbar]}]] + lappend help_menu {} + + if {[string compare [string tolower $index] full] == 0} { + foreach s $sections { + set prefix "" + if {[lindex $s 1]} { + for {set j 0} {$j < [lindex $s 1]} {incr j} { + append prefix [cgi_nbspace][cgi_nbspace] + } + + append prefix {- } + } + + if {[string compare $topic [lindex $s 0]] == 0} { + lappend help_menu [list {} [list "cgi_puts \"<table width=\\\"100%\\\" cellspacing=0 cellpadding=0><tr><td class=navbar bgcolor=#000000>${prefix}[lindex $s 2]</td></tr></table>\""]] + } else { + lappend help_menu [list {} [list "cgi_puts \"${prefix}\[cgi_url \"[lindex $s 2]\" \"help.tcl?topic=[lindex $s 0]&oncancel=[WPPercentQuote $oncancel]&index=${index}\" class=navbar target=body\]\""]] + } + } + } else { + lappend help_menu [list {} [list "cgi_puts \"\[cgi_url \"About Web Alpine\" \"helpbody.tcl?topic=about&oncancel=[WPPercentQuote $oncancel]\" class=navbar target=bodtext\]\""]] + if {[string compare [string tolower $index] none]} { + lappend help_menu [list {} [list "cgi_puts \"\[cgi_url \"Other Topics\" \"helpindex.tcl?topic=${topic}&index=full&oncancel=[WPPercentQuote $oncancel]\" class=navbar target=bodindx\]\""]] + } + } + + WPTFCommandMenu help_menu {} + } + } +} diff --git a/web/cgi/alpine/1.0/index.tcl b/web/cgi/alpine/1.0/index.tcl new file mode 100755 index 00000000..6a0fa543 --- /dev/null +++ b/web/cgi/alpine/1.0/index.tcl @@ -0,0 +1,1972 @@ +# $Id: index.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# index.tcl +# +# Purpose: CGI script snippet to generate html output associated +# with the WebPine message list (index) body frame +# +# Input: +set index_vars { + {sort {} date} + {rev {} 0} + {top {} 0} + {uid {} 0} + {width {} $_wp(width)} + {op {} none} + {bod_next {} 0} + {bod_last {} 0} + {bod_first {} 0} + {bod_prev {} 0} + {growpage {} 0} + {shrinkpage {} 0} + {grownum {} 0} + {goto {} ""} + {gonum {} ""} + {select {} ""} + {selectop {} ""} + {doselect {} 0} + {auths {} 0} + {user {} ""} + {pass {} ""} + {create {} 0} + {save {} ""} + {browse {} ""} + {f_name {} ""} + {f_colid {} ""} + {savecancel {} ""} + {promptsave {} ""} + {setflag {} ""} + {flags {} ""} + {repall {} 0} + {reptext {} 0} + {sortrev {} 0} + {sortto {} 0} + {sortfrom {} 0} + {sortdate {} 0} + {sortsize {} 0} + {sortsubject {} 0} + {sortorderedsubj {} 0} + {sortthread {} 0} + {queryexpunge {} 0} + {expunge {} 0} + {cid {} 0} + {folders {} 0} + {compose {} 0} + {submitted {} 0} + {zoom {} ""} + {mark {} ""} + {unmark {} ""} + {search {} ""} + {aggon {} ""} + {aggoff {} ""} + {hdron {} ""} + {hdroff {} ""} + {split {} 0} + {spamit {} ""} + {reload} +} + +# Output: +# + +# FOR TESTING VARIOUS LAYOUTS AND SUCH +set do_status_icons 1 + +set selectverb Search + +set growmax 50 +set growverb Increase +set shrinkverb Decrease + +# various color defs +set color(sortfg) "#FFFFFF" +set color(sortbg) "#BFBFBF" +set color(line1) "#EEEEEE" +set color(line2) "#FFFFFF" +set color(greyout) "#888888" +set sb_width 13 +set sb_dir bar + +set aggbar 1 +set sortbar 2 + +set gonum "" + +if {[catch {WPCmd PEInfo indexlines} ppg] || $ppg <= 0} { + set ppg $_wp(indexlines) +} + +# make sure any caching doesn't screw this setting +catch {WPCmd PEInfo set wp_spec_script fr_index.tcl} + +proc statmsg {s} { + global newmail + + lappend newmail [list $s] +} + +proc selectresponse {type num prevnum zoomref topref uidref} { + upvar $zoomref zoomed + upvar $topref top + upvar $uidref uid + + if {$num == 0} { + if {$prevnum} { + set statmsg "$type search found no additional messages. Set of marked messages unchanged" + } else { + set statmsg "$type search found no matching messages" + } + } elseif {$num > 0} { + if {$prevnum} { + set statmsg "$type search found $num messages. [expr {$num + $prevnum}] total messages now marked." + } else { + set statmsg "$type search found and marked $num messages" + } + + if {!$zoomed} { + # force reframing + set top "0+0" + set uid 0 + } + } else { + set statmsg "[set num [expr abs($num)]] messages Unmarked." + if {$prevnum > $num} { + append statmsg " [expr {$prevnum - $num}] remain Marked." + } + } + + # update zoomed count or zoom if necessary + if {$zoomed} { + set zoomed [WPCmd PEMailbox selected] + } elseif {[WPCmd PEInfo feature auto-zoom-after-select] && [WPCmd PEMailbox selected]} { + set zoomed [WPCmd PEMailbox zoom 1] + #append statmsg ". Those not matching excluded from view." + } + + statmsg $statmsg + catch {WPCmd PEInfo unset wp_def_search_text} +} + + +proc sortname {name {current 0}} { + global rev me + + switch -- $name { + Number { set newname "#" } + OrderedSubj { set newname "Ordered Subject" } + Arrival { set newname Arv } + Status { set newname " " } + default { set newname $name } + } + + if {$current} { + if {$rev > 0} { + set text [cgi_imglink increas] + set args rev=0 + } else { + set text [cgi_imglink decreas] + set args rev=1 + } + + append newname [cgi_url $text "wp.tcl?page=index&sortrev=1" "title=Reverse $newname ordering" target=body] + } + + return $newname +} + +proc lineclass {linenum} { + if {$linenum % 2} { + return i0 + } else { + return i1 + } +} + +proc uid_framed {u mv} { + foreach m $mv { + if {$u == [lindex $m 1]} { + return 1 + } + } + return 0 +} + +proc index_quote {text} { + set text [cgi_quote_html $text] + regsub -all { } $text {\ } text + + return $text +} + +proc index_part_color {text color} { + if {[llength $color] == 2} { + set fg [lindex $color 0] + set bg [lindex $color 1] + return [cgi_span "style=color: $fg; background-color: $bg" $text] + } else { + return $text + } +} + +## read vars +foreach item $index_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +# check for new mail first since counts +# and sort order might change... +if {[catch {WPNewMail $reload ""} newmail]} { + error [list _action "new mail" $newmail] +} + +set cid [WPCmd PEInfo key] + +set messagecount [WPCmd PEMailbox messagecount] +set delcount [WPCmd PEMailbox flagcount deleted] +set flagcmd [WPCmd PEInfo feature enable-flag-cmd] +set aggops [WPCmd PEInfo feature enable-aggregate-command-set] +set aggtabstate [WPCmd PEInfo aggtabstate] +set zoomed [WPCmd PEMailbox zoom] + +set indexheight [WPIndexLineHeight] + +if {$split != "0"} { + set vtarget fr_bottom +} else { + set vtarget spec +} + +# perform any requested actions +if {$queryexpunge == 1 || [string compare [string tolower $queryexpunge] expunge] == 0} { + if {$delcount > 0} { + set fn [WPCmd PEMailbox mailboxname] + set oncancel index + # delcount, messagecount set above + source [WPTFScript expunge] + set nopage 1 + } else { + statmsg "No deleted messages to Expunge" + } +} elseif {$expunge == 1 + || [string compare [string tolower $expunge] expunge] == 0 + || [string compare [string range [string tolower $expunge] 0 10] "yes, remove"] == 0} { + if {$delcount > 0} { + if {$delcount < $messagecount + || ($delcount == $messagecount + && 0 == [catch {cgi_import emptyit}] + && 1 == $emptyit)} { + set setflags [WPCmd PEMessage $top status] + if {[lsearch $setflags "Deleted"] != -1} { + set curmsg [WPCmd PEMessage $top number] + set nextmsg [WPCmd PEMailbox next $curmsg] + set done 0 + while {$nextmsg > $curmsg && $done == 0} { + set nextuid [WPCmd PEMailbox uid $nextmsg] + set setflags [WPCmd PEMessage $nextuid status] + if {[lsearch $setflags "Deleted"] == -1} { + set uid $nextuid + set top $uid + set done 1 + } else { + set curmsg $nextmsg + set nextmsg [WPCmd PEMailbox next $curmsg] + } + } + + if {$done == 0} { + set curmsg [WPCmd PEMessage $top number] + set prevmsg [WPCmd PEMailbox next $curmsg -1] + while {$prevmsg < $curmsg && $done == 0} { + set prevuid [WPCmd PEMailbox uid $prevmsg] + set setflags [WPCmd PEMessage $prevuid status] + if {[lsearch $setflags "Deleted"] == -1} { + set uid $prevuid + set top $uid + set done 1 + } else { + set curmsg $prevmsg + set prevmsg [WPCmd PEMailbox next $curmsg -1] + } + } + } + } + + if {[catch {WPCmd PEMailbox expunge} blasted] || [string length $blasted]} { + statmsg "Expunge problem: $blasted" + } else { + set delcount 0 + set messagecount [WPCmd PEMailbox messagecount] + if {$messagecount < 1} { + set uid 0 + set top 0 + set first 1 + if {$zoomed} { + WPCmd PEMailbox zoom 0 + } + } else { + if {$top > 0 && ([catch {WPCmd PEMessage $top number} n] || $n <= 0)} { + # previous top message is gone, figure new one below + set top 0 + } + + if {$uid > 0 && ([catch {WPCmd PEMessage $uid number} n] || $n <= 0)} { + # recently viewed message is gone + set uid 0 + } + } + } + } else { + statmsg "<div style=\"width: 75%; background-color: pink; border: 1px solid red; padding: 0 8\"><span style=\"font-size: 12pt; color: white; background-color: red; padding: 0 5\">No Messages Expunged!</span><div style=\"font-weight: normal; padding: 4 8\">To prevent unintended deletions, you must check the box on the Expunge Confirmation page to indicate that you acknowledge expunge will leave the folder <b>[WPCmd PEMailbox mailboxname]</b> empty.</div></div>" + } + } else { + statmsg "No deleted messages to Expunge" + } +} elseif {$growpage == 1 || [string compare $growverb $growpage] == 0} { + if {$grownum <= 0 || $grownum > $growmax} { + set grownum 5 + } + + incr ppg $grownum + catch {WPCmd PEInfo set grownum $grownum} + WPCmd PEInfo indexlines $ppg +} elseif {$shrinkpage == 1 || [string compare $shrinkverb $shrinkpage] == 0} { + if {$grownum <= 0 || $grownum > $growmax} { + set grownum 5 + } + + incr ppg -$grownum + catch {WPCmd PEInfo set grownum $grownum} + + if {$ppg < 1} { + set ppg 1 + } + + WPCmd PEInfo indexlines $ppg +} elseif {$bod_prev} { + set top "$top-$ppg" + set uid 0 +} elseif {$bod_first} { + set first 1 + if {$messagecount > 0} { + set top [WPCmd PEMailbox uid $first] + } + + set uid 0 +} elseif {$bod_next} { + set top "$top $ppg" + set uid 0 +} elseif {$bod_last} { + if {$messagecount > 0} { + if {$zoomed} { + if {$zoomed > $ppg} { + if {[catch {WPCmd PEMailbox uid [WPCmd PEMailbox next [expr {[WPCmd PEMailbox last] - [expr {${ppg} - 1}]}]]} top]} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } else { + set first [WPCmd PEMessage $top number] + } + } + } else { + if {[set first [expr {$messagecount - $ppg + 1}]] < 0} { + set first 1 + } + + set top [WPCmd PEMailbox uid $first] + } + } + + set uid 0 +} elseif {[string length $goto]} { + if {[regexp {^([0-9]+)$} $gonum n]} { + if {$n > 0 && $n <= [WPCmd PEMailbox last]} { + set first $n + set uid [WPCmd PEMailbox uid $first] + set top $uid + set gonum "" + } else { + statmsg "Jump value $gonum out of range" + set goto "" + } + } else { + if {[string length $gonum]} { + statmsg "Unrecognized Jump value: $gonum" + } else { + statmsg "Enter a message number, then click 'Jump'" + } + } +} elseif {$promptsave == 1 || [string compare [string tolower $promptsave] save] == 0} { + if {[WPCmd PEMailbox selected] == 0} { + statmsg "Place checkmarks in the box next to desired messages, then click 'Save'" + } else { + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_promptsave.tcl] + set nopage 1 + } +} elseif {$savecancel == 1 || [string compare cancel [string tolower $savecancel]] == 0} { + catch {WPCmd PEInfo unset wp_index_script} + lappend newmail [list "Save cancelled. Folder not created."] +} elseif {[string length $browse] && [string compare $browse Browse] == 0} { + set uid 0 + _cgi_set_uservar onselect main + _cgi_set_uservar oncancel main + _cgi_set_uservar controls 0 + source [WPTFScript savebrowse] + set nopage 1 +} elseif {([string length $save] && ([string compare [string trim $save] OK] == 0 || [string compare [string trim $save] Save] == 0)) || [string compare save [string tolower $op]] == 0} { + if {[WPCmd PEMailbox selected] == 0} { + statmsg "Place checkmarks in the box next to desired messages, then click 'Save'" + } elseif {[catch {cgi_import cancel}] == 0} { + statmsg "Save cancelled" + } else { + set f_name [string trim $f_name] + if {[string length $f_name]} { + if {[regexp {^([0-9]+)$} $f_colid]} { + switch -exact -- $f_name { + __folder__prompt__ { + set uid 0 + _cgi_set_uservar onselect {index save=OK} + _cgi_set_uservar oncancel index + _cgi_set_uservar target body + _cgi_set_uservar controls 0 + source [WPTFScript savecreate] + set nopage 1 + } + __folder__list__ { + set uid 0 + _cgi_set_uservar onselect {index save=OK} + _cgi_set_uservar oncancel index + _cgi_set_uservar target body + _cgi_set_uservar controls 0 + source [WPTFScript savebrowse] + set nopage 1 + } + default { + if {$auths} { + catch {WPCmd PESession nocred $f_colid $f_name} + if {[catch {WPCmd PESession creds $f_colid $f_name $user $pass} result]} { + lappend newmail ["Cannot set credentials ($f_colid) $f_name: result"] + } + } + + if {[catch {WPCmd PEFolder exists $f_colid $f_name} reason]} { + if {[string compare BADPASSWD [string range $reason 0 8]] == 0} { + set oncancel "index.tcl&savecancel=1" + set conftext "Create Folder '$f_name'?" + lappend params [list page index] + lappend params [list save Save] + lappend params [list f_name $f_name] + lappend params [list f_colid $f_colid] + source [WPTFScript auth] + set nopage 1 + } else { + lappend newmail [list "Existance test failed: $reason"] + } + } elseif {$reason == 0} { + if {$create == 1 || [string compare create [string tolower $create]] == 0} { + if {[catch {WPCmd PEFolder create $f_colid $f_name} reason]} { + lappend newmail [list "Create failed: $reason"] + } else { + set dosave 1 + } + } else { + set qstate [list $f_name] + set params [list [list page index]] + lappend params [list save OK] + lappend params [list f_name $f_name] + lappend params [list f_colid $f_colid] + lappend qstate $params + + if {[catch {WPCmd PEInfo set querycreate_state $qstate}] == 0} { + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_querycreate.tcl] + set nopage 1 + } else { + statmsg "Error saving creation state" + } + } + } else { + set dosave 1 + } + + if {[info exists dosave]} { + if {[catch {WPCmd PEMailbox apply save $f_colid $f_name} reason]} { + error [list _action "Cannot save to $f_name in $f_colid" $reason] + } else { + set statmsg "Saved $reason message[WPplural $reason] to $f_name" + + set savedef [WPTFSaveDefault $uid] + if {[lindex $savedef 0] == $f_colid} { + WPTFAddSaveCache $f_name + } + + if {[WPCmd PEInfo feature auto-unselect-after-apply]} { + if {[catch {WPCmd PEMailbox select none} result]} { + set statmsg "Cannot clear all message marks: $result" + } else { + if {$result == 0} { + set statmsg "No Marked messages to Unmark" + } else { + append statmsg " and unmarked" + } + } + } + + statmsg $statmsg + } + } + } + } + } else { + statmsg "Unrecognized collection id" + } + } else { + statmsg "Must provide a folder name to Save to" + } + } +} elseif {[string compare Set $setflag] == 0 || [string compare Delete $setflag] == 0 || [string compare Undelete $setflag] == 0} { + switch -- $setflag { + Delete { + set flagverb Delete + set flags delete + } + Undelete { + set flagverb Undelete + set flags undeleted + } + default { + set flagverb Set + } + } + + if {[WPCmd PEMailbox selected] == 0} { + statmsg "Place checkmarks in the box next to desired messages, then click '$flagverb'" + } else { + switch -- $flags { + delete { + set flagverb "for deletion" + if {[catch {WPCmd PEMailbox apply delete} reason]} { + set statmsg "Problem deleting: $reason" + } + } + undeleted { + set flagverb Undeleted + if {[catch {WPCmd PEMailbox apply undelete} reason]} { + set statmsg "Problem undeleting: $reason" + } + } + new { + set flagverb New + if {[catch {WPCmd PEMailbox apply flag ton new} reason]} { + set statmsg "Problem setting New flag: $reason" + } + } + read { + set flagverb Read + if {[catch {WPCmd PEMailbox apply flag not new} reason]} { + set statmsg "Problem Unsetting New flag: $reason" + } + } + answered { + set flagverb Answered + if {[catch {WPCmd PEMailbox apply flag ton ans} reason]} { + set statmsg "Problem setting Answered flag: $reason" + } + } + unanswered { + set flagverb "Not Answered" + if {[catch {WPCmd PEMailbox apply flag not ans} reason]} { + set statmsg "Problem Unsetting Answered flag: $reason" + } + } + important { + set flagverb "Important" + if {[catch {WPCmd PEMailbox apply flag ton imp} reason]} { + set statmsg "Problem setting Important flag: $reason" + } + } + unimportant { + set flagverb "Not Important" + if {[catch {WPCmd PEMailbox apply flag not imp} reason]} { + set statmsg "Problem Unsetting Important flag: $reason" + } + } + default { + statmsg "Unknown flag set request: $flags" + } + } + + if {![info exists statmsg]} { + set statmsg "$reason message[WPplural $reason] flagged $flagverb" + if {[WPCmd PEInfo feature auto-unselect-after-apply]} { + if {[catch {WPCmd PEMailbox select none} result]} { + set statmsg "Cannot clear all message marks: $result" + } else { + if {$result == 0} { + set statmsg "No Selected messages to Unmark" + } else { + append statmsg " and unmarked" + } + } + } + } + + statmsg $statmsg + } +} elseif {[string length $mark]} { + if {[string compare mark [string tolower [lindex $mark 0]]] == 0} { + if {[catch {WPCmd PEMailbox select all} result]} { + statmsg "Cannot mark all messages: $result" + } else { + set zm "" + if {$zoomed} { + set zoomed [WPCmd PEMailbox zoom 0] + set zm ". Message List now displaying all messages." + } + statmsg "All messages in folder '[WPCmd PEMailbox mailboxname]' marked$zm" + } + } elseif {[string compare $mark 1] == 0} { + if {$zoomed} { + statmsg "Messages on page already marked" + } elseif {$messagecount > 0} { + set p [split $uidpage ","] + set s [WPCmd PEMessage [lindex $p 0] number] + set e [WPCmd PEMessage [lindex $p end] number] + + if {[catch {WPCmd PEMailbox select broad num $s $e} result]} { + statmsg "Cannot mark messages: $result" + } else { + statmsg "Marked all messages [cgi_underline "on this page"]" + } + } + } +} elseif {[string length $unmark]} { + if {[string compare unmark [lindex [string tolower $unmark] 0]] == 0} { + if {[catch {WPCmd PEMailbox select none} result]} { + statmsg "Cannot clear all message marks: $result" + } else { + if {$result == 0} { + statmsg "No marked messages to Unmark" + } else { + if {[regexp {[0-9]+} $result] && $result == $messagecount} { + set result All + } + + statmsg "Unmarked $result Messages" + } + } + } elseif {[string compare $unmark 1] == 0} { + if {[catch {WPCmd PEMailbox select clear [split $uidpage ","]} result]} { + statmsg "Cannot clear message marks: $result" + } else { + if {$result == 0} { + statmsg "No marked messages to Unmark" + } else { + statmsg "Unmarked all messages [cgi_underline "on this page"]" + } + } + } +} elseif {[string length $select] && [string compare $select $selectverb] == 0} { + switch -- $selectop { + mark { + if {[catch {WPCmd PEMailbox select all} result]} { + statmsg "Cannot mark all messages: $result" + } elseif {0} { + statmsg "All messages marked" + } + } + clear { + if {[catch {WPCmd PEMailbox select none} result]} { + statmsg "Cannot clear all message marks: $result" + } elseif {0} { + if {$result == 0} { + statmsg "No marked messages to Unmark" + } else { + statmsg "Unmarked $result messages" + } + } + } + text { + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_seltext.tcl] + set nopage 1 + } + date { + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_seldate.tcl] + set nopage 1 + } + stat { + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_selstat.tcl] + set nopage 1 + } + zoom { + if {[WPCmd PEMailbox selected] == 0} { + statmsg "No marked messages to Zoom on" + } elseif {$zoomed == 0} { + set zoomed [WPCmd PEMailbox zoom 1] + } + } + unzoom { + set zoomed [WPCmd PEMailbox zoom 0] + } + null { + } + default { + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) fr_select.tcl] + set nopage 1 + } + } +} elseif {$zoom != ""} { + set z 0 + if {[WPCmd PEMailbox selected] == 0} { + if {[string compare [string tolower [string range $zoom 0 7]] "show all"]} { + statmsg "No marked messages to Zoom in on!" + } + } elseif {$zoomed == 0} { + set z 1 + } + + set zoomed [WPCmd PEMailbox zoom $z] +} elseif {$doselect == 1} { + WPLoadCGIVar result + + if {[string compare new [string tolower $result]] == 0} { + catch {WPCmd PEMailbox select none} + catch {WPCmd PEMailbox zoom 0} + set zoomed 0 + set result broad + } + + set selected [WPCmd PEMailbox selected] + + if {[catch {WPLoadCGIVar cancel}] || [string compare cancel [string tolower $cancel]] != 0} { + if {[catch {WPLoadCGIVar by}]} { + if {[string length $selectop]} { + set by [string tolower [lindex $selectop 1]] + } else { + statmsg "Unknown Search Option -- Click button associated with desired search" + set by unset + } + } + + switch -- $by { + date { + WPLoadCGIVar datecase ;# on, since or before + WPLoadCGIVar datemon ;# month abbrev: jan, feb etc + WPLoadCGIVar dateday ;# day num + WPLoadCGIVar dateyear ;# year num + + if {[catch {WPCmd PEMailbox select $result date $datecase $dateyear $datemon $dateday} reason]} { + statmsg "Date Search Failed: $reason" + } else { + selectresponse Date $reason $selected zoomed top uid + } + } + text { + WPLoadCGIVar textcase ;# ton, not + WPLoadCGIVar field ;# to from cc recip partic subj any + WPLoadCGIVar text ;# search string + + if {[catch {WPCmd PEMailbox select $result text $textcase $field $text} reason]} { + statmsg "Text Search Failed: $reason" + } else { + switch -- $field { + subj {set fieldtext "\"Subject:\""} + from {set fieldtext "\"From:\""} + to {set fieldtext "\"To:\""} + cc {set fieldtext "\"Cc:\""} + recip {set fieldtext "Recipient"} + partic {set fieldtext "Participant"} + default {set fieldtext "Full text"} + } + + selectresponse $fieldtext $reason $selected zoomed top uid + } + } + status { + if {[catch {WPLoadCGIVar flag}]} { + statmsg "Choose a Status value and then click [cgi_bold "Search Status"]" + } else { + WPLoadCGIVar statcase + if {[catch {WPCmd PEMailbox select $result status $statcase $flag} reason]} { + statmsg "Flag Search Failed: $reason" + } else { + switch -- $statcase { + not { set casetext "NOT " } + default { set casetext "" } + } + switch -- $flag { + imp {set flagtext Important} + new {set flagtext "New status"} + ans {set flagtext Answered} + del {set flagtext Deleted} + } + selectresponse "${casetext}${flagtext} status" $reason $selected zoomed top uid + } + } + } + unset { + if {[catch {WPLoadCGIVar text}] == 0} { + catch {WPCmd PEInfo set wp_def_search_text $text} + } + } + default { + WPCmd PEInfo statmsg "Unknown Search Option" + } + } + } else { + catch {WPCmd PEInfo unset wp_def_search_text} + } + + catch {WPCmd PEInfo unset wp_index_script} +} elseif {$sortrev} { + if {$rev} { + set rev 0 + } else { + set rev 1 + } +} elseif {$sortto} { + set sort To +} elseif {$sortfrom} { + set sort From +} elseif {$sortdate} { + set sort Date +} elseif {$sortsize} { + set sort siZe +} elseif {$sortsubject} { + set sort Subject +} elseif {$sortorderedsubj} { + set sort OrderedSubj +} elseif {$sortthread} { + set sort tHread +} elseif {$folders} { + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) folders.tcl] + set nopage 1 +} elseif {[string compare reply [string tolower $op]] == 0} { + if {0} { + set oncancel index + set cid [WPCmd PEInfo key] + #_cgi_set_uservar style Reply + source [WPTFScript compose] + set nopage 1 + } + statmsg "Aggregate Reply not implemented yet" +} elseif {[string compare forward [string tolower $op]] == 0} { + statmsg "Aggregate Forward not implemented yet" +} elseif {[string length $aggon]} { + set aggtabstate [expr {$aggtabstate | $aggbar}] + WPCmd PEInfo aggtabstate $aggtabstate +} elseif {[string length $aggoff]} { + if {$zoomed} { + set zoomed [WPCmd PEMailbox zoom 0] + statmsg "Message List now displaying all (marked and unmarked) messages" + } + + set aggtabstate [expr {$aggtabstate & ~$aggbar}] + WPCmd PEInfo aggtabstate $aggtabstate +} elseif {[string length $hdron]} { + set aggtabstate [expr {$aggtabstate | $sortbar}] + WPCmd PEInfo aggtabstate $aggtabstate +} elseif {[string length $hdroff]} { + set aggtabstate [expr {$aggtabstate & ~$sortbar}] + WPCmd PEInfo aggtabstate $aggtabstate +} elseif {[catch {WPCmd PEInfo set wp_index_script} script] == 0} { + catch {WPCmd PEInfo unset wp_index_script} + set uid 0 + source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) $script] + set nopage 1 +} elseif {[string length $spamit]} { + if {[WPCmd PEMailbox selected] == 0} { + statmsg "Place checkmarks in the box next to desired messages, then click '$spamit'" + } else { + # create + + # aggregate save + if {[info exists _wp(spamsubj)] && [string length $_wp(spamsubj)]} { + set spamsubj $_wp(spamsubj) + } else { + set spamsubj "Spam Report" + } + + # aggregate delete + if {[info exists _wp(spamfolder)] && [string length $_wp(spamfolder)] + && [catch { + set savedef [WPCmd PEMailbox savedefault] + if {[WPCmd PEFolder exists [lindex $savedef 0] $_wp(spamfolder)] == 0} { + WPCmd PEFolder create [lindex $savedef 0] $_wp(spamfolder) + } + + WPCmd PEMailbox apply save [lindex $savedef 0] $_wp(spamfolder) + } result]} { + statmsg "Error Reporting Spam: $result" + } elseif {[info exists _wp(spamaddr)] && [string length $_wp(spamaddr)] + && [catch {WPCmd PEMailbox apply spam $_wp(spamaddr) $spamsubj} reason]} { + statmsg "Error Sending Spam Notice: $reason" + } elseif {[catch {WPCmd PEMailbox apply delete} reason]} { + statmsg "Error marking Spam Deleted: $reason" + } else { + set seld [WPCmd PEMailbox selected] + statmsg "$seld spam message[WPplural $seld] reported and flagged for deletion" + catch {WPCmd PEMailbox select none} + } + } +} elseif {[string compare "set flags" [string tolower $op]] == 0} { + if {[catch {WPCmd PEInfo flaglist} flags]} { + statmsg "Can't get flags: $flags" + } else { + # then go thru flag list setting and clearing as needed + foreach flag $flags { + if {[catch {cgi_import_as $flag val}]} { + if {[catch {WPCmd PEMessage $uid flag $flag 0} result]} { + statmsg "Can't set $flag: $result" + break + } + } else { + set newval [expr {[string compare $val on] == 0}] + if {[catch {WPCmd PEMessage $uid flag $flag $newval} result]} { + statmsg "Can't set $flag: $result" + break + } + } + } + } +} + +if {![info exists nopage]} { + # set the specified sort order + if {[catch {WPCmd PEMailbox sort $sort $rev} currentsort]} { + error [list _action Sort $currentsort] + } + + if {$aggops} { + set selected [WPCmd PEMailbox selected] + if {$selected < 1 && $zoomed} { + set zoomed 0 + WPCmd PEMailbox zoom 0 + statmsg "Message List now displaying all (marked and unmarked) messages" + } + } + + # "top" is uid of first message in index. n after '+' is relative offset + if {$messagecount <= 0} { + set first 1 + set top 0 + set miv "" + } else { + if {[regexp {^([0-9]+)([\+\ -])([0-9]+)$} $top dummy u sign offset]} { + if {$u == 0 || [catch {WPCmd PEMessage $u number} first]} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } else { + set top $u + } + + if {$offset != 0} { + if {[catch {WPCmd PEMailbox next [WPCmd PEMessage $top number] ${sign}${offset}} newfirst] == 0} { + set first $newfirst + set top [WPCmd PEMailbox uid $newfirst] + } + } + } elseif {[regexp {^[0-9]*$} $top]} { + if {$top == 0 || [catch {WPCmd PEMessage $top number} first]} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } + } else { + statmsg "Invalid UID for first message" + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } + + # validate first is in range + if {$messagecount && $first < [set f [WPCmd PEMailbox first]]} { + set first $f + set top [WPCmd PEMailbox uid $f] + } + + # check framing + if {$zoomed} { + if {$zoomed < $ppg || [WPCmd PEMessage $top select] == 0} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } else { + set first [WPCmd PEMessage $top number] + } + + set uid $top + } else { + if {$messagecount < $ppg} { + if {![string length $goto]} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } + } elseif {$first > $messagecount} { + if {[set mdiff [expr {$messagecount - $ppg + 1}]] < 0} { + set first [WPCmd PEMailbox first] + set top [WPCmd PEMailbox uid $first] + } else { + set first $mdiff + set top [WPCmd PEMailbox uid $mdiff] + } + } + } + + # validate uid + # use "size" instead of "number" to work around temporary bug in pinetcld + if {$uid != 0 && ([catch {WPCmd PEMessage $uid size} n] || $n <= 0)} { + set uid 0 + } + + set nv [WPCmd PEMailbox nextvector $first $ppg [list indexparts indexcolor status statusbits]] + set miv [lindex $nv 0] + set charset [lindex $nv 1] + + # hook to keep last viewed message in current message list + if {$uid > 0} { + if {[catch {WPCmd PEMessage $uid number} n] == 0 && [uid_framed $uid $miv] == 0} { + set first $n + set top $uid + set nv [WPCmd PEMailbox nextvector $first $ppg [list indexparts indexcolor status statusbits ]] + set miv [lindex $nv 0] + set charset [lindex $nv 1] + } + + #set uid 0 ;# no longer "last viewed" + #catch {WPCmd PEInfo unset uid} + } + + # remember for next time + catch { + WPCmd PEInfo set top $top + WPCmd PEInfo set sort $sort + WPCmd PEInfo set rev $rev + } + } + + if {[llength $miv] == 0 + || (!([info exists charset] && [string length $charset]) + && ([catch {WPCmd PEConfig varget character-set} charset] + || [string length [set charset [lindex $charset 0]]] == 0 + || [string compare [string tolower $charset] "us-ascii"] == 0))} { + set charset "UTF-8" + } + + catch {fconfigure stdout -encoding binary} + + # start writing page + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + cgi_html { + cgi_head { + cgi_http_equiv Content-Type "text/html; charset=$charset" + + set onload "onLoad=" + set onunload "onUnload=" + if {[info exists _wp(exitonclose)]} { + WPExitOnClose + append onload "wpLoad();" + append onunload "wpUnLoad();" + } + + if {[info exists _wp(timing)]} { + set onsubmit "onSubmit=return submitTimestamp()" + cgi_script type="text/javascript" language="JavaScript" { + cgi_puts "var loadtime = new Date();" + cgi_put "function submitTimestamp(){" + cgi_put " var now = new Date();" + cgi_put " document.index.submitted.value = now.getTime();" + cgi_put " return true;" + cgi_puts "}" + cgi_put "function fini() {" + cgi_put " var now = new Date();" + cgi_put " var t_load = (now.getTime() - loadtime.getTime())/1000;" + if {$submitted} { + cgi_put " var t_submit = (now.getTime() - $submitted)/1000;" + set rtt ", rtt = '+t_submit+', cumulative = '+(t_submit + t_load)" + } else { + set rtt "'" + } + cgi_put " window.status = 'Page loaded in '+t_load+' seconds${rtt};" + cgi_puts "}" + } + append onload "fini();" + } else { + set onsubmit "" + } + + set normalreload [cgi_buffer {WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=index"}] + if {[info exists _wp(exitonclose)]} { + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function indexReloadTimer(t){" + cgi_put " reloadtimer = window.setInterval('wpLink(); window.location.replace(\\'[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=index&reload=1\\')', t * 1000);" + cgi_puts "}" + } + + append onload "indexReloadTimer($_wp(refresh));" + cgi_noscript { + cgi_puts $normalreload + } + } else { + cgi_puts $normalreload + } + + WPStyleSheets + cgi_puts "<style type='text/css'>" + cgi_puts ".marked { font-weight: bold ; color: black }" + cgi_puts ".marked0 { font-size: 7pt; font-family: arial, sans-serif ; font-weight: bold ; color: black ; background-color: gold ; padding: 1 ; border: 1px solid black }" + cgi_puts ".aggop { font-family: arial, sans-serif ; font-size: 7pt }" + cgi_puts "A.aggop { color: white ; font-size: 7pt }" + cgi_puts ".navbutton { font-family: arial, sans-serif ; font-size: 7pt; overflow: visible; width: auto; padding: 0 2px; margin-right: 2px }" + cgi_puts ".itable { font-family: geneva, arial, sans-serif }" + cgi_puts ".gradient { background-image: url('[WPimg indexhdr]') ; background-repeat: repeat-x }" + cgi_puts ".icell { white-space: nowrap; padding-right: 8px }" + cgi_puts ".icell0 { white-space: nowrap }" + cgi_puts "</style>" + + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function flip(d){" + cgi_put " var f = document.index;" + cgi_put " if(f && document.implementation){" + cgi_put " var e = document.createElement('input');" + cgi_puts " var ver = navigator.appVersion;" + cgi_put " if(!((ver.indexOf('MSIE')+1) && (ver.indexOf('Macintosh')+1))) e.type = 'hidden';" + cgi_put " e.name = 'bod_'+d;" + cgi_put " e.value = 1;" + cgi_put " f.appendChild(e);" + cgi_put " f.submit();" + cgi_put " return false;" + cgi_put " }" + cgi_put " return true;" + cgi_puts "}" + + cgi_put "function view(u) {" + cgi_put " var f = document.index;" + cgi_put " f.target = '$vtarget';" + cgi_put " f.page.value = 'fr_view';" + cgi_put " f.uid.value = u;" + cgi_puts " f.submit();" + cgi_puts " return false;" + cgi_puts "}" + + cgi_put "function toggleMarks(elobj){" + cgi_put " var i, ckd = 1;" + cgi_put " for(i = 0; i < document.index.uidList.length; i++)" + cgi_put " if(!document.index.uidList\[i\].checked){" + cgi_put " ckd = 0;" + cgi_put " break;" + cgi_put " }" + cgi_put " for(i = 0; i < document.index.uidList.length; i++) document.index.uidList\[i\].checked = !ckd;" + cgi_put " elobj.src = (ckd) ? '[WPimg markall3]' : '[WPimg marknone3]';" + cgi_put " return false;" + cgi_puts "}" + } + + if {$_wp(keybindings)} { + set kequiv { + {{?} {top.location = 'wp.tcl?page=help'}} + {{l} {top.location = 'wp.tcl?page=folders'}} + {{a} {top.location = 'wp.tcl?page=addrbook'}} + {{n} {if(flip('next')) location = 'wp.tcl?page=body&bod_next=1'}} + {{p} {if(flip('prev')) location = 'wp.tcl?page=body&bod_prev=1'}} + {{ } {if(flip('next')) location = 'wp.tcl?page=body&bod_next=1'}} + {{-} {if(flip('prev')) location = 'wp.tcl?page=body&bod_prev=1'}} + {{;} {if(document.index.select) document.index.select.click(); else document.index.aggon.click()}} + {{z} {if(document.index.zoom) document.index.zoom.click()}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key]'"] + + if {$aggops && ($aggtabstate & $aggbar)} { + set exclusions document.index.f_name + } else { + set exclusions "" + } + + append onload [WPTFKeyEquiv $kequiv $exclusions] + } + } + + cgi_body bgcolor=$_wp(bordercolor) background=[file join $_wp(imagepath) logo $_wp(logodir) back.gif] "style=\"background-repeat: repeat-x\"" $onload $onunload { + + catch {WPCmd set help_context index} + + # check for status msg updates + foreach s [WPStatusMsgs] { + lappend newmail [list $s] + } + + if {[llength $newmail]} { + WPTFStatusTable $newmail 1 "style=\"padding: 6px 0; color: white\"" + + if {!$reload} { + WPCmd PEMailbox newmailreset + } + } + + if {$ppg > 50} { + set postmethod post + set enctype "multipart/form-data" + } else { + set postmethod get + set enctype "application/x-www-form-urlencoded" + } + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=$postmethod enctype=$enctype name=index $onsubmit target=body { + + # context line + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" class="context" { + if {[llength $newmail]} { + cgi_table_row { + cgi_table_data height=1 bgcolor="#000000" width="100%" colspan=8 { + cgi_put [cgi_img [WPimg dot2] border=0 height=1] + } + } + } + + cgi_table_row bgcolor="#999999" { + if {$zoomed} { + if {[catch {WPCmd PEMailbox messagecount after [lindex [lindex $miv end] 0]} messagesremaining]} { + unset messagesremaining + } + + set z "[cgi_span class="marked" marked] " + set t $zoomed + } else { + set messagesremaining [expr {$messagecount - ($first + $ppg - 1)}] + set t $messagecount + set z "" + } + + if {[catch {WPCmd PEMailbox messagecount before [lindex [lindex $miv 0] 0]} messagesbefore] == 0 && $messagesbefore > 0} { + if {$messagesbefore > $ppg} { + set b $ppg + } else { + set b $messagesbefore + } + + switch $b { + 1 { + set c One + set p "" + } + default { + set c $b + set p s + } + } + + set prevtext " [cgi_unbreakable_string "($c on [cgi_url previous wp.tcl?page=body&bod_prev=1 "onClick=return flip('prev')"] page)"]" + } else { + set messagesbefore 0 + set prevtext "" + } + + if {$messagesbefore <= 0 && $messagesremaining <= 0} { + switch $t { + 0 { + set counttext "[cgi_bold No] ${z}messages in folder" + } + 1 { + set counttext "[cgi_bold Only] ${z}message in folder" + } + 2 { + set counttext "[cgi_bold Both] ${z}messages in folder" + } + default { + set counttext "[cgi_bold All] $t ${z}messages in folder" + } + } + } elseif {$zoomed} { + if {$messagesbefore > 0} { + if {$messagesremaining > 0} { + set counttext "[expr {$messagesbefore + 1}] thru [expr {$zoomed - $messagesremaining}] of $zoomed [cgi_span class="marked" marked] messages" + } else { + if {[set p [llength $miv]] == 1} { + set lasttext "" + } else { + set lasttext " $p" + } + + set counttext "[cgi_bold Last]${lasttext} of $zoomed [cgi_span class="marked" marked] messages" + } + } else { + set counttext "[cgi_bold First] $ppg of $zoomed [cgi_span class="marked" marked] messages" + } + } else { + set n [WPcomma $messagecount] + + if {[lindex [lindex $miv 0] 0] == 1} { + set counttext "[cgi_bold First] $ppg of $n messages" + } else { + set l [lindex [lindex $miv end] 0] + if {$l == $messagecount} { + if {[set p [llength $miv]] == 1} { + set lasttext "" + } else { + set lasttext " $p" + } + + set counttext "[cgi_bold Last]${lasttext} of $n messages" + } else { + set counttext "Message [WPcomma $first] - [WPcomma $l] of $n" + } + } + } + + cgi_table_data align=left class="context" "style=\"padding-left: 4\"" { + cgi_unbreakable { + cgi_put "${counttext}[cgi_breakable]${prevtext}" + } + } + + cgi_table_data align=right { + cgi_unbreakable { + if {[WPCmd PEInfo feature expunge-without-confirm-everywhere] + || ([WPCmd PEInfo feature expunge-without-confirm] + && [string compare [string tolower [WPCmd PEMailbox mailboxname]] inbox] == 0)} { + set butname expunge + cgi_text "emptyit=1" type=hidden notab + } else { + set butname queryexpunge + } + + if {$aggops} { + cgi_submit_button "mark=Mark All in Folder" class="navbutton" + cgi_submit_button "unmark=Unmark All" class="navbutton" + + cgi_put [cgi_breakable] + cgi_submit_button "setflag=Delete" class="navbutton" + cgi_submit_button "setflag=Undelete" class="navbutton" + if {([info exists _wp(spamaddr)] && [string length $_wp(spamaddr)]) + || ([info exists _wp(spamfolder)] && [string length $_wp(spamfolder)])} { + cgi_submit_button "spamit=Report Spam" class="navbutton" "style=\" color: white; background-color: black\"" + } + } + + cgi_submit_button "${butname}=Expunge" class="navbutton" + } + } + } + } + + cgi_text "page=index" type=hidden notab + cgi_text "cid=$cid" type=hidden notab + cgi_text "first=$first" type=hidden notab + cgi_text "uid=0" type=hidden notab + cgi_text "top=$top" type=hidden notab + cgi_text "frestore=1" type=hidden notab + cgi_text "submitted=0" type=hidden notab + + if {$aggops} { + if {[llength $miv]} { + foreach v $miv { + lappend uv [lindex $v 1] + } + + set uidpage [join $uv ","] + } else { + set uidpage "" + } + + cgi_text "uidpage=${uidpage}" type=hidden notab + + if {$aggtabstate & $aggbar} { + # commands + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" class=ops { + cgi_table_row { + cgi_table_data height=1 "bgcolor=#000000" colspan=12 align=left { + cgi_put [cgi_img [WPimg dot2] height=1] + } + } + cgi_table_row { + cgi_put "<td height=100% width=11px align=left valign=bottom background=[WPimg barclose_mid]><input type=image name=\"aggoff\" src=[WPimg barclose] border=0 alt=\"Hide Message Commands\"></td>" + + cgi_table_data align=center valign=middle nowrap class=aggop width=30% { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"color: white\">Search and Mark</legend>" + cgi_submit_button "select=${selectverb}" class=aggop "style=\"vertical-align: middle; margin-right: 4\"" + + if {$zoomed} { + cgi_submit_button "zoom=Show All Messages" class=aggop "style=\"vertical-align: middle\"" + } else { + cgi_submit_button "zoom=Show Only Marked" class=aggop "style=\"vertical-align: middle\"" + } + cgi_puts "</fieldset>" + } + + cgi_table_data align=center valign=middle nowrap class=aggop width=30% { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"color: white\">Message Status</legend>" + cgi_submit_button setflag=Set class=aggop "style=\"vertical-align:middle\"" + cgi_put "[cgi_nbspace]status to " + cgi_select flags class=aggop "style=\"vertical-align:middle\"" { + #cgi_option Deleted value=delete + #cgi_option Undeleted value=undeleted + cgi_option New value=new selected + cgi_option Read value=read + cgi_option Important value=important + cgi_option Unimportant value=unimportant + cgi_option Answered value=answered + cgi_option Unanswered value=unanswered + } + + cgi_puts "</fieldset>" + } + + cgi_table_data align=center valign=middle class=aggop width=40% { + cgi_puts "<fieldset>" + cgi_puts "<legend style=\"color: white\">Save Messages</legend>" + # * * * * Save * * * * + + cgi_submit_button "save=Save" class=aggop "style=\"vertical-align:middle\"" + cgi_put "[cgi_nbspace]to " + + set savedef [WPTFSaveDefault $uid] + + cgi_text f_colid=[lindex $savedef 0] type=hidden notab + + cgi_select f_name class=aggop "style=\"vertical-align:middle\"" "onchange=document.index.save.click(); return false;" { + foreach {oname oval} [WPTFGetSaveCache [lindex $savedef 1]] { + cgi_option $oname value=$oval + } + } + + #cgi_put "[cgi_nbspace]" + #cgi_submit_button "save=OK" class=aggop "style=\"vertical-align:middle;margin-right:2\"" + cgi_puts "</fieldset>" + } + } + cgi_table_row { + cgi_table_data height=1 "bgcolor=#000000" colspan=12 { + cgi_put [cgi_img [WPimg dot2] height=1] + } + } + } + } elseif {$aggtabstate & $sortbar} { + # aggop bar + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" class=ops { + cgi_table_row { + cgi_table_data height=1 "bgcolor=#000000" colspan=12 align=left { + cgi_put [cgi_img [WPimg dot2] height=1] + } + } + cgi_table_row { + cgi_table_data { + cgi_image_button aggon=[WPimg baropen] border=0 alt=\"Show Search/Save Commands\" + } + } + + cgi_table_row { + cgi_table_data height=1 "bgcolor=#000000" colspan=12 { + cgi_put [cgi_img [WPimg dot2] height=1] + } + } + } + } + } + + cgi_table cellspacing=0 cellpadding=0 width="100%" class="itable" { + if {$messagecount < 1} { + # special case for mailbox with no messges + cgi_table_row { + cgi_table_data class=body valign=middle height=[expr {($ppg + 1) * $indexheight}] { + cgi_center { + cgi_puts [cgi_font size=+2 "\[Folder \"[WPCmd PEMailbox mailboxname]\" contains no messages\]"] + } + } + } + } else { + + # get the desired index item order and spacing + set iformat [WPCmd PEMailbox indexformat] + + set colspan [expr {[llength $iformat] + 1}] + + # setup per-column layout parameters + foreach fmt $iformat { + + if {[info exists oncethru]} { + if {![info exists firstcell]} { + set class icell0 + set firstcell 1 + } else { + set class icell + } + + append layout " $class " + } + + set oncethru 1 + + switch -regexp -- [lindex $fmt 0] { + [Ss]tatus { + # fixed with "envelope" icon + if {[string length [lindex $fmt 2]]} { + set width "1%" + } else { + set width "42px" + } + } + default { + # proportion computed by pith (may be user specified) + if {[regexp {[0123456789]+[%]} [lindex $fmt 1]]} { + set width [lindex $fmt 1] + } else { + set width "1%" + } + } + } + + append layout "$width" + } + + append layout " icell0" + + #set doscrollbar [expr {($zoomed && $zoomed > $ppg) || (!$zoomed && $messagecount > $ppg)}] + set linenum 1 + + # paint the index line column headers + cgi_table_row class=\"gradient\" { + if {($aggtabstate & $sortbar) == 0} { + if {!([info exists headertab] && [string length $headertab])} { + cgi_table_data class=indexhdr align=left width=48px background=[WPimg baropen_mid] { + if {$aggops && ($aggtabstate & $aggbar) == 0} { + cgi_image_button aggon=[WPimg baropen] border=0 alt=\"Show Search/Save Commands\" + } + + cgi_image_button hdron=[WPimg baropen] border=0 alt=\"Show List Headers\" + } + + foreach fmt $iformat {width class} $layout { + cgi_table_data class=indexhdr align=left width=$width background=[WPimg baropen_mid] { + cgi_put [cgi_img [WPimg dot2] height=1] + } + } + } + } else { + if {$aggops} { + cgi_table_data height=100% align=left valign=bottom class=indexhdr width=\"40px\" { + cgi_table width=\"100%\" cellpadding=0 cellspacing=0 border=0 { + cgi_table_row { + cgi_table_data align=left valign=bottom { + cgi_image_button hdroff=[WPimg barclose] border=0 "alt=\"Hide List Headers\"" + } + cgi_table_data align=center valign=middle "style=\"padding-right: 14px\"" { + set marked 1 + foreach v $miv { + set u [lindex $v 1] + if {$u == 0 || ![WPCmd PEMessage $u select]} { + set marked 0 + break + } + } + + if {$marked} { + cgi_image_button unmark=[WPimg marknone3] border=0 alt=\"Unmark Messages on Page\" "onClick=return toggleMarks(this);" + } else { + cgi_image_button mark=[WPimg markall3] border=0 alt=\"Mark Messages on Page\" "onClick=return toggleMarks(this);" + } + } + } + } + } + } else { + cgi_td class=indexhdr [cgi_nbspace] + } + + set sorts [string tolower [WPCmd PEMailbox sortstyles]] + + foreach fmt $iformat {width class} $layout { + set title [lindex $fmt 0] + catch {unset sortlist} + + if {[lsearch -exact $sorts [string tolower $title]] >= 0} { + if {[string compare [string tolower [lindex $currentsort 0]] [string tolower $title]] == 0} { + lappend sortlist [list indexsort [sortname $title 1]] + } else { + lappend sortlist [list indexhdr [cgi_url [sortname $title] wp.tcl?page=index&sort[string tolower $title]=1 class=indexhdr title='Sort by $title' target=body]] + } + + # special subject sort handling + switch -regexp -- $title { + [Ss]ubject { lappend extrasort OrderedSubj ; lappend extrasort Thread } + [Ff]rom { lappend extrasort To } + x[Dd]ate { lappend extrasort Arrival } + } + + if {[info exists extrasort]} { + foreach s $extrasort { + lappend sortlist [list indexhdr [cgi_bold "|"]] + # append text [cgi_nbspace][cgi_bold "|"][cgi_nbspace] + if {[string compare [string tolower [lindex $currentsort 0]] [string tolower $s]] == 0} { + if {[string compare [string tolower $s] thread] == 0} { + set threadsort 1 + } + lappend sortlist [list indexsort [sortname $s 1]] + } else { + lappend sortlist [list indexhdr [cgi_url [sortname $s] wp.tcl?page=index&sort[string tolower $s]=1 class=indexhdr title='Sort by $s' target=body]] + } + } + + # clear for next time + unset extrasort + } + } else { + lappend sortlist [list indexhdr [sortname $title]] + } + + cgi_table_data class=indexhdr valign=middle class=$class width="$width" { + cgi_table border=0 cellspacing=0 cellpadding=2 { + cgi_table_row { + foreach s $sortlist { + cgi_table_data class=[lindex $s 0] nowrap { + cgi_puts [lindex $s 1] + } + } + } + } + } + } + + if {[info exists use_plus_minus_to_grow_shrink]} { + # grow/shrink controls + cgi_table_data class=indexhdr { + cgi_image_button growpage=[WPimg plus2] height=12 border=0 alt="Grow" + cgi_image_button shrinkpage=[WPimg minus2] height=12 border=0 alt="Shrink" + } + } + } + } + + if {$zoomed} { + cgi_table_row { + cgi_table_data class=marked0 colspan=$colspan align=center { + cgi_puts "Unmarked Messages are NOT Shown - Click [cgi_url "Show All Messages" wp.tcl?page=body&zoom=0] to View All" + #cgi_puts "Unmarked Messages Are Excluded From View" + } + } + } + + # get ready to map thread images + if {[string compare [string tolower [lindex $currentsort 0]] thread] == 0} { + set barblank [WPThreadImageLink barblank $indexheight] + set barvert [WPThreadImageLink barvert $indexheight] + if {[lindex $currentsort 1]} { + set barmsg [WPThreadImageLink ibarmsg $indexheight] + } else { + set barmsg [WPThreadImageLink barmsg $indexheight] + } + + if {[lindex $currentsort 1]} { + set barvertmsg [WPThreadImageLink ibarvertmsg $indexheight] + } else { + set barvertmsg [WPThreadImageLink barvertmsg $indexheight] + } + } + + foreach v $miv { + set n [lindex $v 0] + set u [lindex $v 1] + set msg [lindex [lindex $v 2] 0] + set linecolor [lindex [lindex $v 2] 1] + set stat [lindex [lindex $v 2] 2] + set statbits [lindex [lindex $v 2] 3] + + set class [lineclass [incr linenum]] + + if {$n > $messagecount} { + break + } + + if {[llength $linecolor] == 2 && [string compare [lindex $linecolor 0] [lindex $linecolor 1]]} { + set style "color: #[lindex $linecolor 0] ; background-color: #[lindex $linecolor 1]" + } else { + set style "" + } + + cgi_table_row class=$class "style=\"$style\"" { + if {$u == 0} { + cgi_table_data colspan=$colspan height=$indexheight { + cgi_put "Data for message $n no longer available" + } + } else { + if {$aggops} { + cgi_table_data valign=middle align=center height=$indexheight { + if {[WPCmd PEMessage $u select]} { + set checked checked + } else { + set checked "" + } + + cgi_checkbox "uidList=$u" $checked class=$class id=cb$u "style=\"$style; margin-left: 16\"" + } + } else { + cgi_td height=$indexheight width=2% [cgi_nbspace] + } + + set deleted [string index $stat 0] + set recent [expr {[string range $stat 0 2] == "010"}] + + foreach part $msg fmt $iformat {width class} $layout { + + set align "" + set onclick "" + + switch -exact -- [lindex $fmt 0] { + Subject { + set parttext "" + set leading "" + foreach p $part { + switch -- [lindex $p 2] { + threadinfo { + append leading [lindex $p 0] + regsub -all {[ ][ ]} $leading $barblank leading + regsub -all {[|][-]} $leading $barvertmsg leading + regsub -all {[\\][-]} $leading $barmsg leading + regsub -all {[|]} $leading $barvert leading + } + xthreadinfo { + set t [lindex $p 0] + append leading "$t" + for {set i 0} {$i < [string length $t]} {incr i} { + switch -- [string index $t $i] { + " " { + append leading [WPThreadImageLink barblank $indexheight] + } + ">" { + } + "-" { + if {[lindex $currentsort 1]} { + append leading [WPThreadImageLink ibarmsg $indexheight] + } else { + append leading [WPThreadImageLink barmsg $indexheight] + } + } + "|" { + append leading [WPThreadImageLink barvert $indexheight] + } + } + } + } + default { + append parttext [index_part_color [index_quote [lindex $p 0]] [lindex $p 1]] + } + } + } + + if {[string length [set label $parttext]] == 0} { + set label {[Empty Subject]} + } + + set text [cgi_url $label "fr_view.tcl?&uid=$u&c=[string range $cid 0 5]" target=$vtarget "onClick=return view($u)"] + + if {![info exists do_status_icons] && $deleted} { + set text [cgi_span "style=text-decoration: line-through" $text] + } + + set text [cgi_buffer { + cgi_division "style=\"height: $indexheight; overflow: hidden;\"" { + cgi_put "${leading}${text}" + } + }] + } + Status { + if {[string length [lindex $fmt 2]]} { + set text "" + foreach i $part { + regsub -all { } [lindex $i 0] {\ } statstr + if {[llength [lindex $i 1]]} { + append text [cgi_span "style=background-color: #[lindex [lindex $i 1] 1]; color: #[lindex [lindex $i 1] 0]" $statstr] + } else { + append text $statstr + } + } + + set text [cgi_buffer { + cgi_division "style=\"font-family: monospace\"" { + cgi_put $text + } + }] + } elseif {[info exists do_status_icons]} { + set text [WPStatusImg $u] + } else { + set text [lindex [WPStatusIcon $u gif $statbits] 2] + set align align=center + } + + if {$flagcmd} { + set text [cgi_url $text fr_flags.tcl?uid=$u target=body] + } + } + Size { + set text [index_part_color [index_quote [lindex [lindex $part 0] 0]] [lindex $part 1]] + set class isize + set onclick "onclick=\"flipCheck('cb$u')\"" + } + Number { + set text [index_part_color [index_quote [WPcomma [string trim [lindex [lindex $part 0] 0]]]] [lindex $part 1]] + set onclick "onclick=\"flipCheck('cb$u')\"" + } + From - + To { + set t [index_quote [lindex [lindex $part 0] 0]] + if {$recent} { + set t [cgi_bold $t] + } + + set text [cgi_buffer { + cgi_division "style=\"height: $indexheight; overflow: hidden;\"" { + cgi_put [index_part_color $t [lindex $part 1]] + } + }] + + set onclick "onclick=\"flipCheck('cb$u')\"" + } + default { + set text [index_part_color [index_quote [lindex [lindex $part 0] 0]] [lindex $part 1]] + set onclick "onclick=\"flipCheck('cb$u')\"" + } + } + + if {![info exists text]} { + set text doh + } + + cgi_td $align class="$class" $onclick "$text" + } + + if {[info exists use_plus_minus_to_grow_shrink]} { + cgi_td [cgi_nbspace] + } + } + } + } + + for {} {$linenum <= $ppg} {incr linenum} { + cgi_table_row class="[lineclass [expr $linenum + 1]]" { + cgi_table_data colspan=$colspan height=$indexheight { + cgi_puts [cgi_nbspace] + } + } + } + } + + if {[info exists use_bottom_text_to_grow_shrink]} { + cgi_table_row height=1 { + cgi_table_data bgcolor=#000000 colspan=$colspan { + cgi_put [cgi_img [WPimg blackdot] height=1] + } + } + + cgi_table_row { + cgi_table_data align=center valign=middle colspan=$colspan class=indexhdr { + cgi_put "[WPcomma $ppg] messages are in the list above. Press either " + cgi_submit_button growpage=$growverb class=indexhdr "style=\"vertical-align:middle\"" + cgi_put " or " + cgi_submit_button shrinkpage=$shrinkverb class=indexhdr "style=\"vertical-align:middle\"" + cgi_put " to change this by " + cgi_select grownum class=indexhdr "style=\"vertical-align:middle\"" { + set growsizes {1 5 10 25 50} + + if {[catch {WPCmd PEInfo set grownum} lastsize]} { + set lastsize 0 + } + + foreach size $growsizes { + if {$size == $lastsize} { + set sel selected + } else { + set sel "" + } + + cgi_option $size value=$size $sel + } + } + cgi_put "." + } + } + } + } + } + + cgi_table width=100% cellpadding=0 cellspacing=0 border=0 { + cgi_table_row { + cgi_table_data align=left class=context { + if {[info exists messagesremaining] && $messagesremaining > 0} { + if {$messagesremaining > $ppg} { + set moretext ", $ppg" + } else { + set moretext "" + } + + if {$zoomed} { + set marked " [cgi_bold marked]" + } else { + set marked "" + } + + set nexttext " ([WPcomma $messagesremaining] more${marked} message[WPplural $messagesremaining]${moretext} on [cgi_url next wp.tcl?page=body&bod_next=1 "onClick=return flip('next')"] page)" + } else { + set nexttext "" + } + + cgi_puts "[cgi_nbspace]${counttext}${nexttext}" + } + cgi_table_data align=right class=context { + cgi_put "Powered by [cgi_url Alpine "http://www.washington.edu/alpine/" target="_blank"] - [cgi_copyright] 2007 University of Washington" + if {[info exists _wp(ui2dir)]} { + cgi_puts " - [cgi_url "Standard Version " "$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/browse" target=_top]" + } + } + } + } + + if {[info exists _wp(cumulative)]} { + set l [string length $_wp(cumulative)] + if {$l < 6} { + set sl "." + while {$l < 6} { + append sl "0" + incr l + } + append sl $_wp(cumulative) + } else { + set sl "[string range $_wp(cumulative) 0 [expr $l - 7]].[string range $_wp(cumulative) [expr $l - 6] end]" + } + + set servlettime "servlet = $sl" + + if {[info exists wp_global_loadtime]} { + set clickdiff [expr {[clock clicks] - $wp_global_loadtime}] + # 500165 clicks/second + set st [expr ([string range $clickdiff 0 [expr [string length $clickdiff] - 4]] * 1000) / 500] + set l [string length $st] + set scripttime "tcl = [string range $st 0 [expr $l - 4]].[string range $st [expr $l - 3] end], " + } else { + set scripttime "" + } + + cgi_puts [cgi_font size=-2 "style=font-family:arial;font-weight:bold" "\[time: ${scripttime}${servlettime}\]"] + } + } + } +} diff --git a/web/cgi/alpine/1.0/ldapbrowse.tcl b/web/cgi/alpine/1.0/ldapbrowse.tcl new file mode 100755 index 00000000..e8436fd3 --- /dev/null +++ b/web/cgi/alpine/1.0/ldapbrowse.tcl @@ -0,0 +1,220 @@ +#!./tclsh +# $Id: ldapbrowse.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ldapbrowse.tcl +# +# Purpose: CGI script to browse ldap results + +# Input: [expected to be set when we get here] +set browse_vars { + {field "Missing Field Name"} + {ldapquery "Missing LDAP Query Number"} + {addresses "" ""} + {oncancel "" ""} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set ldapres_cmds { + { + {} + { + { + # * * * * USE ADDRESSES * * * * + cgi_submit_button "address=Address" class="navtext" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_submit_button "cancel=Cancel" class="navtext" + } + } + } +} + +WPEval $browse_vars { + + if {[catch {WPCmd PEInfo noop} result]} { + error [list _action "No Op" $result] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + if {$ldapquery != 0} { + if {[catch {WPCmd PELdap results $ldapquery} results]} { + WPCmd PEInfo statmsg "Some sort of ldap problem" + } + } + + cgi_head { + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post name=ldapaddr target=_top { + cgi_text "page=ldappick" type=hidden notab + cgi_text "ldapquery=$ldapquery" type=hidden notab + cgi_text "field=$field" type=hidden notab + cgi_text "addresses=[cgi_unquote_input $addresses]" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + cgi_table_row { + # next comes the menu down the left side + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu ldapres_cmds {} + } + } + + cgi_table_data valign=top width=100% class=dialog { + if {$ldapquery == 0} { + cgi_puts [cgi_italic "No matches found"] + } else { + cgi_table align=center width="75%" { + cgi_table_row { + cgi_table_data align=center valign=middle { + cgi_br + cgi_put "Below are directory entries matching text expanded from your message's $field field. Choose the addressees you want, then Click [cgi_bold Address]." + cgi_br + cgi_br + } + } + } + + set numboxes 0 + set srchindex 0 + cgi_table border=0 cellpadding=0 cellspacing=0 align=center width=96% { + foreach searchres $results { + set srchstr [lindex $searchres 0] + set retdata [lindex $searchres 1] + set expstr "" + cgi_table_row { + cgi_table_data { + + if {$srchstr != ""} { + set expstr " for \"[cgi_bold $srchstr]\"" + } + + cgi_text "str${srchindex}=${srchstr}" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=1 width=100% { + cgi_table_row { + cgi_table_data colspan=32 valign=middle height=20 class=ops { + cgi_puts "[cgi_nbspace]Directory Search Results${expstr}" + } + } + + set whitebg 1 + set nameindex 0 + set onetruebox 0 + set numsrchboxes 0 + foreach litem $retdata { + if {[llength [lindex $litem 4]] > 0} { + incr numsrchboxes + if {$numsrchboxes > 1} { + break + } + } + } + if {$numsrchboxes == 1} { + set onetruebox 1 + } + foreach litem $retdata { + set name [lindex $litem 0] + set email [lindex $litem 4] + set nomail 0 + if {$whitebg == 1} { + set bgcolor #FFFFFF + set whitebg 0 + } else { + set bgcolor #EEEEEE + set whitebg 1 + } + if {[llength $email] < 1} { + incr nameindex + continue + set nomail 1 + } + cgi_table_row bgcolor=$bgcolor { + + cgi_table_data valign=top nowrap { + if {$nomail == 1} { + cgi_puts " " + } else { + if {$onetruebox == 1} { + set checked checked + } else { + set checked "" + } + cgi_checkbox "ldapList=${srchindex}.${nameindex}" style="background-color:$bgcolor" $checked + incr numboxes + } + } + + cgi_table_data valign=top nowrap { + regsub -all "<" $name "\\<" name + regsub -all ">" $name "\\>" name + cgi_puts "$name" + } + cgi_table_data valign=top nowrap { + if {[llength $email] > 1} { + cgi_table width=100% { + foreach eaddr $email { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_font size=-1 "style=font-family:courier_new,monospace" "[cgi_lt]${eaddr}[cgi_gt]"] + } + } + } + } + } else { + if {$nomail == 1} { + cgi_puts "\[No email information\]" + } else { + cgi_puts [cgi_font size=-1 "style=font-family:courier_new,monospace" "[cgi_lt][lindex $email 0][cgi_gt]"] + } + } + } + } + incr nameindex + } + } + + cgi_br + cgi_br + } + } + incr srchindex + } + } + cgi_text "numboxes=${numboxes}" type=hidden notab + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/ldapentry.tcl b/web/cgi/alpine/1.0/ldapentry.tcl new file mode 100755 index 00000000..a483f165 --- /dev/null +++ b/web/cgi/alpine/1.0/ldapentry.tcl @@ -0,0 +1,315 @@ +#!./tclsh +# $Id: ldapentry.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ldapentry.tcl +# +# Purpose: CGI script to submit ldap search + +# Input: +set ldap_vars { + {dir "Missing Directory Index"} + {qn "Missing Query Number"} + {si "Missing Search Index"} + {ni "Missing Name Index"} + {email "" 0} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +# Command Menu definition for Message View Screen +set ldap_menu { +} + +set common_menu { + { + {} + { + { + # * * * * Ubiquitous INBOX link * * * * + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_main.tcl target=_top class=navbar] + } + } + } + } + { + {} + { + { + # * * * * FOLDER LIST * * * * + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=addrbook&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=addrbook&cid=[WPCmd PEInfo key] class=navbar] + } + } + } + { + {} + { + { + # * * * * Addr books * * * * + cgi_puts [cgi_url "Address Book" wp.tcl?page=addrbook&oncancel=main.tcl target=_top class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * ldap Query * * * * + cgi_puts [cgi_url "Back to Search Results" ldapresult.tcl?dir=${dir}&qn=${qn} class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {expr {$email > 0}} + { + { + # * * * * Compose To * * * * + cgi_puts [cgi_url "Send Mail To This Person" compose.tcl?ldap=1&dir=${dir}&qn=${qn}&si=${si}&ni=${ni}&cid=[WPCmd PEInfo key]&oncancel=addrbook class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * QUIT * * * * + cgi_puts [cgi_url "Quit Web Alpine" "$_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid class=navbar" target=_top class=navbar] + } + } + } +} + + +WPEval $ldap_vars { + + if {[catch {WPCmd PEInfo noop} result]} { + error [list _action "No Op" $result] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + if {$qn != 0} { + if {[catch {WPCmd PELdap results $qn} results]} { + WPCmd PEInfo statmsg "Some sort of ldap problem" + } + } + + cgi_head { + WPStdHtmlHdr "LDAP Entry" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + # + # next comes the menu down the left side + # + cgi_table_data valign=top rowspan=4 class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=2 { + cgi_table_row { + cgi_table_data class=navbar style=padding-top:6 { + cgi_puts "Current Folder :" + cgi_division align=center "style=\"margin-top:4;margin-bottom:4\"" { + cgi_put [cgi_url [WPCmd PEMailbox mailboxname] fr_main.tcl target=_top class=navbar] + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + + cgi_br + } + + cgi_hr "width=75%" + } + } + + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar style=padding-bottom:10 { + WPTFCommandMenu ldap_menu common_menu + } + } + } + } + } + + + cgi_table_data valign=top align=center class=dialog width=100% { + if {$qn == 0} { + cgi_puts [cgi_italic "No matches found"] + } else { + if {[catch {WPCmd PELdap ldapext $qn "${si}.${ni}"} leinfo]} { + cgi_br + cgi_puts [cgi_italic "Error getting entry: $leinfo"] + } else { + + set lehead [lindex $leinfo 0] + set ledata [lindex $leinfo 1] + + foreach item $ledata { + if {[string compare [string tolower [lindex $item 0]] name] == 0} { + set entry_name [lindex [lindex $item 1] 0] + break + } + } + + cgi_division "style=\"padding:10\"" { + cgi_puts [cgi_font size=+1 "Directory Entry for \"$entry_name\""] + } + + cgi_table border=0 cellspacing=0 cellpadding=0 width=80% "style=\"border: 1px solid goldenrod; padding: 2\"" { + + set bgwhite 1 + foreach item $ledata { + switch -exact -- [string tolower [lindex $item 0]] { + name { + continue; + } + voicemailtelephonenumber { + set fieldname "Voice Mail" + } + "email address" { + set do_email 1 + set fieldname [lindex $item 0] + } + "fax telephone" { + set do_fax 1 + set fieldname [lindex $item 0] + } + default { + set fieldname [lindex $item 0] + } + } + + set itematt "" + if {[llength $item] > 2} { + set itematt [lindex $item 2] + } + if {$itematt == "objectclass"} { + set vals [lindex $item 1] + continue + } + + if {$bgwhite == 1} { + set bgcolor #ffffff + set bgwhite 0 + } else { + set bgcolor #eeeeee + set bgwhite 1 + } + + set vals [lindex $item 1] + + cgi_table_row bgcolor=$bgcolor { + cgi_table_data width=25% nowrap valign=top rowspan=[llength $vals] { + cgi_division "style=\"padding-top:2\"" { + cgi_puts [cgi_bold $fieldname] + } + } + + cgi_table_data rowspan=[llength $vals] { + cgi_puts [cgi_img [WPimg dot2] width=8] + } + + cgi_table_data height=20px { + if {[info exists do_fax]} { + set n {[0-9]} + set n3 $n$n$n + set n4 $n$n$n$n + if {[regexp "^\\\+1 ($n3) ($n3)-($n4)\$" [lindex $vals 0] dummy areacode prefix number] && [lsearch -exact {206 425} $areacode] >= 0} { + cgi_puts [cgi_url [lindex $vals 0] compose.tcl?ldap=1&fax=yes&dir=${dir}&qn=${qn}&si=${si}&ni=${ni}&cid=[WPCmd PEInfo key]&oncancel=addrbook] + } else { + cgi_puts [lindex $vals 0] + } + + unset do_fax + } elseif {[info exists do_email]} { + cgi_puts [cgi_url [cgi_font size=-1 face=courier [lindex $vals 0]] compose.tcl?ldap=1&dir=${dir}&qn=${qn}&si=${si}&ni=${ni}&ei=0&cid=[WPCmd PEInfo key]&oncancel=addrbook] + } else { + cgi_puts [lindex $vals 0] + } + + set extrarows [lrange $vals 1 end] + } + } + + if {[info exists extrarows]} { + cgi_table_row bgcolor=$bgcolor { + set ei 0 + foreach extra $extrarows { + cgi_table_data height=20px { + if {[info exists do_email]} { + cgi_puts [cgi_url [cgi_font size=-1 face=courier $extra] compose.tcl?ldap=1&dir=${dir}&qn=${qn}&si=${si}&ni=${ni}&ei=[incr ei]&cid=[WPCmd PEInfo key]&oncancel=addrbook] + } else { + cgi_puts $extra + } + } + } + } + + unset extrarows + } + + catch {unset do_email} + } + } + } + } + } + } + } + } + } +} + diff --git a/web/cgi/alpine/1.0/ldappick.tcl b/web/cgi/alpine/1.0/ldappick.tcl new file mode 100755 index 00000000..4a485266 --- /dev/null +++ b/web/cgi/alpine/1.0/ldappick.tcl @@ -0,0 +1,76 @@ +# $Id: ldappick.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ldappick.tcl +# +# Purpose: CGI script to handle LDAP result choices from the +# via the LDAP result browser generated form + +# Input: +set pick_vars { + {cid "Missing Command ID"} + {field "Missing Field Name"} + {ldapquery "Missing LDAP Query"} + {ldapList "" ""} + {addresses "" ""} + {addrop {} ""} + {cancel {} 0} +} + +# Output: +# + +# read vars +foreach item $pick_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + error [list _action "Impart Variable" $result] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + catch {WPCmd PEInfo statmsg "Invalid Command ID"} +} + +if {$cancel != 1 && !([string compare cancel [string tolower $cancel]] == 0 || [string compare cancel [string tolower $addrop]] == 0) && [string length $ldapList] > 0} { + set ldapListStr [join $ldapList ","] + if {[catch {WPCmd PELdap setaddrs $ldapquery $ldapListStr $addresses 0} newaddrlist]} { + WPCmd PEInfo statmsg "LDAP Error: $newaddrlist" + } else { + regsub -all "'" $newaddrlist "\\'" newaddrs + + if {[catch {WPCmd PEInfo set suspended_composition} msgdata]} { + WPCmd PEInfo statmsg "Cannot read message data: $msgdata" + } else { + if {[info exists newaddrs]} { + for {set i 0} {$i < [llength $msgdata]} {incr i} { + set orig_field [lindex [lindex $msgdata $i] 0] + regsub -all -- - [string tolower $orig_field] _ fn + + if {[string compare $fn $field] == 0} { + set msgdata [lreplace $msgdata $i $i [list $orig_field $newaddrs]] + break + } + } + + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} result]} { + WPCmd PEInfo statmsg "Cannot Update $field field: $result" + } + } + } + } +} + +source [WPTFScript compose] diff --git a/web/cgi/alpine/1.0/ldapquery.tcl b/web/cgi/alpine/1.0/ldapquery.tcl new file mode 100755 index 00000000..c9ca6936 --- /dev/null +++ b/web/cgi/alpine/1.0/ldapquery.tcl @@ -0,0 +1,144 @@ +#!./tclsh +# $Id: ldapquery.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ldapquery.tcl +# +# Purpose: CGI script to handle ldap query + +# Input: +set ldap_vars { + {dir "Missing Directory Index"} + {srchstr {} ""} + {field {} ""} + {op {} ""} + {searchtype {} ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +set ldap_menu { +} + +set common_menu { + { + {} + { + { + # * * * * Ubiquitous INBOX link * * * * + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_main.tcl target=_top class=navbar] + } + } + } + } + { + {} + { + { + # * * * * FOLDER LIST * * * * + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=addrbook&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=addrbook&cid=[WPCmd PEInfo key] class=navbar] + } + } + } + { + {} + { + { + # * * * * Addr books * * * * + cgi_puts [cgi_url "Address Book" wp.tcl?page=addrbook&oncancel=main.tcl target=_top class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * HELP * * * * + cgi_puts [cgi_url "Get Help" "wp.tcl?page=help&oncancel=addrbook" target=_top class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * QUIT * * * * + cgi_puts [cgi_url "Quit Web Alpine" "$_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid class=navbar" target=_top class=navbar] + } + } + } +} + + +WPEval $ldap_vars { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + cgi_http_equiv Refresh "0; url=$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/ldapresult.tcl?dir=${dir}&srchstr=[WPPercentQuote ${srchstr}]&field=${field}&op=${op}&searchtype=${searchtype}&sessid=${sessid}" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data valign=top rclass=navbar { + WPTFCommandMenu {} {} + } + + cgi_table_data valign=top bgcolor=#ffffff width=100% { + cgi_table border=0 width=500 cellpadding=3 { + cgi_table_row { + cgi_table_data align=center "style=\"padding-top:120px\"" { + cgi_put "[cgi_font "style=\"font-family: arial, sans-serif; font-size:18pt; font-weight: bold\"" "Searching Directory "][cgi_img [WPimg dotblink]]" + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/ldapresult.tcl b/web/cgi/alpine/1.0/ldapresult.tcl new file mode 100755 index 00000000..efdce665 --- /dev/null +++ b/web/cgi/alpine/1.0/ldapresult.tcl @@ -0,0 +1,375 @@ +#!./tclsh +# $Id: ldapresult.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ldapquery.tcl +# +# Purpose: CGI script to submit ldap search + +# Input: +set ldap_vars { + {dir "Missing Directory Index"} + {srchstr {} ""} + {field {} ""} + {op {} ""} + {searchtype {} ""} + {qn {} -1} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +# Command Menu definition for Message View Screen +set ldap_menu { +} + +set common_menu { + { + {} + { + { + # * * * * Ubiquitous INBOX link * * * * + if {[string compare inbox [string tolower [WPCmd PEMailbox mailboxname]]]} { + cgi_put [cgi_url INBOX open.tcl?folder=INBOX&colid=0&cid=[WPCmd PEInfo key] target=_top class=navbar] + } else { + cgi_put [cgi_url INBOX fr_main.tcl target=_top class=navbar] + } + } + } + } + { + {} + { + { + # * * * * FOLDER LIST * * * * + cgi_puts [cgi_url "Folder List" "wp.tcl?page=folders&cid=[WPCmd PEInfo key]" target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * COMPOSE * * * * + cgi_puts [cgi_url Compose wp.tcl?page=compose&oncancel=addrbook&cid=[WPCmd PEInfo key] target=_top class=navbar] + } + } + } + { + {} + { + { + # * * * * RESUME * * * * + cgi_puts [cgi_url Resume wp.tcl?page=resume&oncancel=addrbook&cid=[WPCmd PEInfo key] class=navbar] + } + } + } + { + {} + { + { + # * * * * Addr books * * * * + cgi_puts [cgi_url "Address Book" wp.tcl?page=addrbook&oncancel=main.tcl target=_top class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * HELP * * * * + cgi_puts [cgi_url "Get Help" "wp.tcl?page=help&oncancel=addrbook" target=_top class=navbar] + } + } + } + {{cgi_puts [cgi_nbspace]}} + { + {} + { + { + # * * * * QUIT * * * * + cgi_puts [cgi_url "Quit Web Alpine" "$_wp(serverpath)/session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=$sessid class=navbar" target=_top class=navbar] + } + } + } +} + + +WPEval $ldap_vars { + + if {[catch {WPCmd PEInfo noop} result]} { + error [list _action "No Op" $result] + } + + if {$qn == -1} { + set ldapfilt "" + set numfields 0 + if {$searchtype == 1} { + set srchstr "" + source ldapadvsrch.tcl + foreach item $ldap_advanced_search { + WPLoadCGIVarAs [lindex $item 1] tmpval + regsub {^ *([^ ]|[^ ].*[^ ]) *$} $tmpval "\\1" tmpval + if {$tmpval != ""} { + set ldapfilt "${ldapfilt}([lindex $item 2]=${tmpval})" + incr numfields + } + } + if {$numfields > 1} { + set ldapfilt "(&${ldapfilt})" + } + } + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "LDAP Query Result" + WPStyleSheets + cgi_puts "<style type='text/css'>" + cgi_puts ".gradient { background-image: url('[WPimg indexhdr]') ; background-repeat: repeat-x }" + cgi_puts "</style>" + + if {$_wp(keybindings)} { + set kequiv { + {{i} {top.location = 'fr_main.tcl'}} + {{l} {top.location = 'wp.tcl?page=folders'}} + {{?} {top.location = 'wp.tcl?page=help&oncancel=addrbook'}} + } + + lappend kequiv + + set onload "onLoad=[WPTFKeyEquiv $kequiv]" + } else { + set onload "" + } + } + + cgi_body BGCOLOR="$_wp(bordercolor)" $onload { + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + # + # next comes the menu down the left side + # + cgi_table_data valign=top rowspan=4 class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=2 { + cgi_table_row { + cgi_table_data class=navbar style=padding-top:6 { + cgi_puts "Current Folder :" + cgi_division align=center "style=\"margin-top:4;margin-bottom:4\"" { + cgi_put [cgi_url [WPCmd PEMailbox mailboxname] fr_main.tcl target=_top class=navbar] + switch -exact -- [WPCmd PEMailbox state] { + readonly { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Read Only)"] + } + closed { + cgi_br + cgi_put [cgi_span "style=color: pink; font-weight: bold" "(Closed)"] + } + ok - + default {} + } + + cgi_br + } + + cgi_hr "width=75%" + } + } + + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar style=padding-bottom:10 { + WPTFCommandMenu ldap_menu common_menu + } + } + } + } + } + + cgi_table_data valign=top align=center class=dialog width=100% { + + if {$qn == -1 && [catch {WPCmd PELdap query $dir $srchstr $ldapfilt} qn]} { + cgi_division align=center "style=\"background-color:white; border: 1px solid goldenrod; margin: 10; padding: 4\"" { + cgi_puts "A problem has occured while trying to search the directory server." + cgi_br + cgi_br + cgi_puts [cgi_italic [cgi_bold "$qn"]] + cgi_br + cgi_br + cgi_puts "Try searching again by clicking [cgi_url "Address Book" wp.tcl?page=addrbook target=_top] at the left." + } + } elseif {$qn == 0} { + cgi_division align=center "style=\"background-color:white; border: 1px solid goldenrod; margin: 10; padding: 4\"" { + cgi_puts [cgi_bold "No matches for \"$srchstr\" found."] + cgi_br + cgi_br + cgi_puts "You can try another search below, or click a link at the left to continue your WebPine session." + cgi_br + cgi_br + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data name=ldapsearch target=_top { + cgi_text "sessid=$_wp(sessid)" type=hidden notab + cgi_text "page=ldapquery" type=hidden notab + cgi_text "searchtype=0" type=hidden notab + cgi_text "dir=$dir" type=hidden notab + + cgi_puts "Search Directory :" + cgi_text "srchstr=${srchstr}" size=35 + cgi_submit_button "search=Search" + } + + cgi_br + cgi_br + } + } elseif {[catch {WPCmd PELdap results $qn} results]} { + cgi_division align=center "style=\"background-color:white; border: 1px solid goldenrod; margin: 10; padding: 4\"" { + cgi_puts "A problem has occured while trying to retrieve the results of your directory search." + cgi_br + cgi_br + cgi_puts [cgi_italic [cgi_bold "$results"]] + cgi_br + cgi_br + cgi_puts "Try searching again by clicking [cgi_url "Address Book" wp.tcl?page=addrbook target=_top] at the left." + } + } else { + set numboxes 0 + set srchindex 0 + cgi_table border=0 cellpadding=0 cellspacing=10 width=100% { + + foreach searchres $results { + set srchstr [lindex $searchres 0] + set retdata [lindex $searchres 1] + set expstr "" + cgi_table_row { + cgi_table_data valign=middle align=center { + + if {$srchstr != ""} { + set expstr " for \"[cgi_bold $srchstr]\"" + } + + cgi_puts [cgi_font size=+1 "Directory Search Results${expstr}"] + } + } + + cgi_table_row { + cgi_table_data { + cgi_table border=0 bgcolor=white cellspacing=0 cellpadding=0 width=90% "style=\"border: 1px solid goldenrod; padding: 1\"" { + set whitebg 1 + set nameindex 0 + set onetruebox 0 + set numsrchboxes 0 + foreach litem $retdata { + if {[llength [lindex $litem 4]] > 0} { + incr numsrchboxes + if {$numsrchboxes > 1} { + break + } + } + } + if {$numsrchboxes == 1} { + set onetruebox 1 + } + + cgi_table_row class=\"gradient\" { + cgi_table_data align=left class=indexhdr colspan=2 { + cgi_put "Full Name" + } + cgi_table_data align=left class=indexhdr height=30 { + cgi_put "Address (Click to Compose To)" + } + } + + foreach litem $retdata { + set name [lindex $litem 0] + set email [lindex $litem 4] + set nomail 0 + if {$whitebg == 1} { + set bgcolor #FFFFFF + set whitebg 0 + } else { + set bgcolor #EEEEEE + set whitebg 1 + } + + if {[llength $email] < 1} { + set nomail 1 + } + + if {[llength $email]} { + set rowspan rowspan=[llength $email] + } else { + set rowspan "" + } + + cgi_table_row bgcolor=$bgcolor { + + cgi_table_data valign=top nowrap $rowspan { + regsub -all "<" $name "\\<" name + regsub -all ">" $name "\\>" name + # cgi_puts "$name" + cgi_puts "[WPurl "ldapentry.tcl?dir=${dir}&qn=${qn}&si=${srchindex}&ni=${nameindex}&email=[llength $email]" "" "$name" ""]" + } + + cgi_table_data $rowspan { + cgi_puts [cgi_img [WPimg dot2] width=8] + } + + cgi_table_data nowrap height=20px { + if {[llength $email] >= 1} { + set extrarows [lrange $email 1 end] + cgi_put [cgi_url [cgi_font size=-1 face=courier [lindex $email 0]] compose.tcl?ldap=1&dir=${dir}&qn=${qn}&si=${srchindex}&ni=${nameindex}&ei=0&cid=[WPCmd PEInfo key]&oncancel=addrbook] + } else { + cgi_puts [cgi_italic "<No email information>"] + } + } + } + + if {[info exists extrarows] && [llength $extrarows]} { + cgi_table_row bgcolor=$bgcolor { + set ei 0 + foreach extra $extrarows { + cgi_table_data height=20px { + cgi_put [cgi_url [cgi_font size=-1 face=courier $extra] compose.tcl?ldap=1&dir=${dir}&qn=${qn}&si=${srchindex}&ni=${nameindex}&ei=0&cid=[WPCmd PEInfo key]&oncancel=addrbook] + } + } + } + + unset extrarows + } + + incr nameindex + } + } + } + } + incr srchindex + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/main.tcl b/web/cgi/alpine/1.0/main.tcl new file mode 100755 index 00000000..24881868 --- /dev/null +++ b/web/cgi/alpine/1.0/main.tcl @@ -0,0 +1,84 @@ +# $Id: main.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +# Input: + +# Output: +# + +proc save_hack {} { + if {[catch {WPImport f_name "x"}] == 0 && [catch {WPImport f_colid "x"}] == 0} { + append parms "&f_name=${f_name}&f_colid=${f_colid}" + + if {[catch {WPImport send "x"}] == 0} { + append parms "&send=${send}" + } + + return $parms + } + + error "not saving" +} + +cgi_http_head { + WPStdHttpHdrs + WPExportCookie sessid "$_wp(sessid)@[info hostname]" $_wp(appdir)/$_wp(ui1dir) +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "WebPine" + } + + cgi_frameset "cols=112,*" frameborder=0 framespacing=0 { + cgi_frame gen=common.tcl?m=[WPCmd PEMailbox mailboxname]&c=[WPCmd PEInfo key]&v=[WPScriptVersion common]&q=[WPCmd PEInfo feature quit-without-confirm] title="Navigation Commands" + + if {[catch {WPCmd PEInfo set wp_spec_script} script]} { + set script fr_index.tcl + } + + set parms "" + + if {[info exists frame_vars]} { + foreach v $frame_vars { + if {[string length [subst $[lindex $v 0]]]} { + append parms "&[lindex $v 0]=[subst $[lindex $v 0]]" + } + } + } + + switch -regexp $script { + ^fr_view.tcl$ { + if {[catch {save_hack} x] == 0} { + append parms "&$x" + } + + if {[catch {WPCmd PEInfo set uid} uid] == 0} { + append parms "&uid=$uid" + } + + if {[catch {WPCmd PEInfo set op} op] == 0} { + append parms "&op=$op" + } + } + ^fr_index.tcl$ - + ^fr_main.tcl$ { + if {[catch {save_hack} x] == 0} { + append parms "&$x" + } + } + } + + cgi_frame spec=${script}?c=[WPCmd PEInfo key]${parms} frameborder=0 title="Message List and View" + } +} diff --git a/web/cgi/alpine/1.0/open.tcl b/web/cgi/alpine/1.0/open.tcl new file mode 100755 index 00000000..2add6db5 --- /dev/null +++ b/web/cgi/alpine/1.0/open.tcl @@ -0,0 +1,33 @@ +#!./tclsh +# $Id: open.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# open.tcl +# +# Purpose: CGI script to perform folder opening via folders.tcl + +# Input: +set open_vars { + {cid "Missing Command ID"} + {oncancel "" "folders"} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $open_vars { + source do_open.tcl +} diff --git a/web/cgi/alpine/1.0/post.tcl b/web/cgi/alpine/1.0/post.tcl new file mode 100755 index 00000000..dcd7c37b --- /dev/null +++ b/web/cgi/alpine/1.0/post.tcl @@ -0,0 +1,651 @@ +# $Id: post.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# post.tcl +# +# Purpose: CGI script to perform message posting via compose.tcl +# generated form + +# Input: +set post_vars { + {cid "Missing Command ID"} + {action {} ""} + {send {} 0} + {postpone {} 0} + {cancel {} 0} + {check {} 0} + {br_to {} 0} + {br_cc {} 0} + {br_bcc {} 0} + {br_reply_to {} 0} + {br_fcc {} 0} + {ex_to {} ""} + {ex_cc {} ""} + {ex_bcc {} ""} + {ex_reply_to {} ""} + {sendop {} ""} + {queryattach {} 0} + {attach {} 0} + {detach {} 0} + {extrahdrs {} ""} + {help {} ""} + {postpost {} "main.tcl"} + {fccattach {} 0} + {form_charset {} ""} + {form_flowed {} ""} +} + +# NOT Input +catch { + unset src +} + +# Output: +# + +proc fieldname {name} { + regsub -all -- {-} [string tolower $name] {_} fieldname + return $fieldname +} + +proc expand_address_field {field _msgdata} { + global has_fcc + + upvar 1 $_msgdata msgdata + + set fn [fieldname $field] + for {set i 0} {$i < [llength $msgdata]} {incr i} { + if {[string length [lindex [lindex $msgdata $i] 1]]} { + set fld [lindex $msgdata $i] + if {[string compare [fieldname [lindex $fld 0]] $fn] == 0} { + if {[catch {WPCmd PEAddress expand [lindex $fld 1] fcc} expaddr]} { + WPCmd PEInfo statmsg "Can't expand $field: $expaddr" + } else { + if {[lindex $expaddr 1] != 0} { + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # addresses and ldapaddrs should be set at this point + upvar 1 addresses a + upvar 1 ldapquery l + upvar 1 field f + set a [lindex $expaddr 0] + set l [lindex $expaddr 1] + set f $fn + return 1 + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + break + } + } elseif {[string compare [lindex $expaddr 0] [lindex $fld 1]]} { + set msgdata [lreplace $msgdata $i $i [list [lindex $fld 0] [lindex $expaddr 0]]] + + # set fcc? + set fccfn [lindex $expaddr 2] + set fccdef [WPCmd PECompose fccdefault] + if {[string compare to [string tolower $fn]] == 0 && [string length $fccfn] + && (![info exists has_fcc] || 0 == [string compare [lindex $fccdef 1] [lindex $has_fcc 1]])} { + for {set j 0} {$j < [llength $msgdata]} {incr j} { + if {[string compare fcc [fieldname [lindex [lindex $msgdata $j] 0]]] == 0} { + set fcc_index $j + break + } + } + + set colid [lindex $fccdef 0] + if {[info exists fcc_index]} { + if {[string compare $fccfn [lindex [lindex [lindex $msgdata $fcc_index] 1] 1]]} { + lappend msgdata [list postoption [list fcc-set-by-addrbook 1]] + } + + set msgdata [lreplace $msgdata $fcc_index $fcc_index [list Fcc [list $colid $fccfn]]] + } else { + lappend msgdata [list Fcc [list $colid $fccfn]] + lappend msgdata [list postoption [list fcc-set-by-addrbook 1]] + } + + set has_fcc [list $colid $fccfn] + } + } + } + } + } + } + + return 0 +} + +proc chartest_value {entity} { + global _cgi + + if {[catch {cgi_import_as ke_${entity} tc}] == 0} { + set tcval "" + if {[set j [string length $tc]]} { + for {set i 0} {$i < $j} {incr i} { + binary scan [string index $tc $i] c x + set x [expr ($x & 0xff)] + lappend tcval [format {%o} $x] + } + } + + return $tcval + } else { + error "Unset testchar_$entity" + } +} + +## read vars +foreach item $post_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + error [list _action Postpone "Invalid Operation ID" "Click Back button to try again."] +} + +# collect message data + +# For now the input headers have to match the postheaders +# list. Any outside the list are ignored (and probably should +# be to avoid hostile input). Note, postheaders is a +# super-set of composeheaders as not all headers are meant +# to be shown the user for composition +if {[catch {WPCmd PECompose userhdrs} headers]} { + error [list _action "User Headers" $headers "Click browser's Back button to try again."] +} + +if {[catch {WPCmd PECompose syshdrs} otherhdrs]} { + error [list _action "System Headers" $otherhdrs "Click browser's Back button to try again."] +} else { + eval "lappend headers $otherhdrs" +} + +foreach field $headers { + set hdr [string tolower [lindex $field 0]] + regsub -all -- {-} $hdr {_} hdr + WPLoadCGIVarAs $hdr val + switch -- $hdr { + attach { + # disregard: u/i convenience (attachments marshalled below) + } + fcc { + if {[string length $val]} { + WPLoadCGIVar colid + set has_fcc [list $colid $val] + lappend msgdata [list Fcc $has_fcc] + } + } + default { + if {[string length $val] || [lsearch -exact {subject} $hdr] >= 0} { + set hdrvals($hdr) $val + lappend msgdata [list [lindex $field 0] $val] + if {[lsearch -exact {to cc bcc} $hdr] >= 0} { + set has_$hdr 1 + } + } + } + } +} + +if {[info exists env(REMOTE_ADDR)]} { + lappend msgdata [list x-auth-received "from \[$env(REMOTE_ADDR)\] by [info hostname] via HTTP; [clock format [clock seconds] -format "%a, %d %b %Y %H:%M:%S %Z"]"] +} + +if {[catch {cgi_import attachments}] == 0} { + foreach id [split $attachments ","] { + lappend msgdata [list attach $id] + } +} + +WPLoadCGIVar body +lappend msgdata [list body [split $body "\n"]] + + +switch -exact -- $fccattach { + 0 - + 1 { + lappend msgdata [list postoption [list fcc-without-attachments [expr {!$fccattach}]]] + } +} + +# pass on form's charset? +# TURNED OFF since all compose form interaction BETTER be UTF-8 +if {0 && [string length $form_charset]} { + # messy charset heuristics + # idea is to look for planted HTML entities and see if known + # encoding transliterations have occured. inspired by: + # <http://www.cs.tut.fi/~jkorpela/chars.html#encinfo> + + # test for: + # entity values + # euro (#8364) + # cyrillic shcha (#1060) + # iso-8859-15 (Latin0): euro IS 200 + # iso-8859-1 (Latin1): thorn IS 376 or U+C3BE BUT NOT “ þ OR þ + # Unicode literal full width yen: U+FFE5 IS 215F (ISO-2022-JP), A1EF (EUC-JP), or 818F (Shift-JIS) and so on + + # remember, the first element of each group MUST appear in compose.tcl, too + set cstests {} + set xcstests { + {#8364 {{{40 254} ISO-10646} {{342 202 254} UTF-8} {244 ISO-8859-15} {325 IBM-850}} {}} + {#1066 {{{377} KOI8-R} {312 ISO-8859-5}} {}} + {thorn {{376 ISO-8859-1}} {{303 276} UTF-8} {iso-8859-1 {{46 43 70 62 62 60 73} {46 43 62 65 64 73} {46 164 150 157 162 156 73}}}} + {tcedil {{376 ISO-8859-2}} {{46 164 143 145 144 151 154 73}}} + {#65509 {{{302 245} UTF-8} {{241 315} EUC-KR} {{243 244} GB2312} {{242 104} BIG5} {{241 357} EUC-JP} {{201 217} Shift-JIS} {{33 44 102 41 157 33 50 102} ISO-2022-JP}} {}} + } + + catch {unset test_charset} + foreach cs $cstests { + # asked for test entity available? + if {[catch {chartest_value [lindex $cs 0]} ctest] == 0} { + # test for positive [re]encoding assertions + foreach testpos [lindex $cs 1] { + if {[regexp "^[lindex $testpos 0]\$" $ctest]} { + set test_charset [lindex $testpos 1] + break + } + } + + if {![info exists test_charset]} { + set csneg [lindex [lindex $cs 2] 0] + foreach testneg [lindex [lindex $cs 2] 1] { + if {[regexp "^$testneg\$" $ctest]} { + if {[info exists form_charset] + && [string compare [string tolower $form_charset] $csneg] == 0} { + unset form_charset + break + } + } + } + } else { + break + } + } + } + + if {[info exists test_charset]} { + lappend msgdata [list postoption [list charset $test_charset]] + } elseif {[info exists form_charset]} { + lappend msgdata [list postoption [list charset $form_charset]] + } else { + lappend msgdata [list postoption [list charset "X-UNKNOWN"]] + } +} else { + lappend msgdata [list postoption [list charset "UTF-8"]] +} + +# pass on text fomat=flowed? +if {[string length $form_flowed]} { + lappend msgdata [list postoption [list flowed yes]] +} + +# figure out what to do with data +if {[string compare OK [string trim $action]] == 0 && ($send || [string compare $sendop send] == 0)} { + if {[info exists has_to] || [info exists has_cc] || [info exists has_bcc] || [info exists has_fcc]} { + # expand any nicknames + if {[catch { + set fccdef [WPCmd PECompose fccdefault] + for {set i 0} {$i < [llength $msgdata]} {incr i} { + if {[string length [lindex [lindex $msgdata $i] 1]]} { + set fld [lindex $msgdata $i] + set fn [string tolower [lindex $fld 0]] + switch -- $fn { + [Ff]cc { + if {[string length [lindex [lindex $fld 1] 1]]} { + # setup for send confirmation + set colidval [lindex [lindex $fld 1] 0] + set fccval [lindex [lindex $fld 1] 1] + } + } + to - + cc - + bcc - + reply-to { + set expaddr [WPCmd PEAddress expand [lindex $fld 1] {}] + if {[string compare [lindex $expaddr 0] [lindex $fld 1]]} { + set msgdata [lreplace $msgdata $i $i [list [lindex $fld 0] [lindex $expaddr 0]]] + + # if expanded, update fcc? + if {[string compare to $fn] == 0 && [string length $fn]} { + set expanded_fcc [lindex $expaddr 2] + } + } + } + body { + if {[string length $form_flowed]} { + set ws "\[ \t]" + set nws "\[^ \t]" + + set nextline [lindex [lindex $fld 1] 0] + for {set j 1} {$j <= [llength [lindex $fld 1]]} {incr j} { + set line $nextline + # space stuff? + if {[regexp "^${ws}+" $line]} { + set line " $line" + } + + set nextline [lindex [lindex $fld 1] $j] + if {[regexp {^-- $} $line] == 0} { + catch {unset linetext} + # trim trailing WS from lines preceding those with LWS (space-stuff as needed) + if {[string length $nextline] == 0 || [regexp "^${ws}+(${nws}?.*)\$" $nextline dummy linetext]} { + set line [string trimright $line] + if {[info exists linetext] == 0 || [string length $linetext] == 0} { + set nextline "" + } + } + + # break overly long lines in a flowed way + if {[regexp {^[^>]} $line] && [string length $line] > 1000} { + while {[regexp "^(${ws}*${nws}+${ws}+)$nws" [string range $line 900 end] dummy linex]} { + set cliplen [expr {900 + [string length $linex]}] + lappend newbody [string range $line 0 [expr {$cliplen - 1}]] + set line [string range $line $cliplen end] + } + } + } + + lappend newbody $line + } + + set msgdata [lreplace $msgdata $i $i [list body $newbody]] + } + } + default { + } + } + } + } + } result]} { + WPCmd PEInfo statmsg "Address problem: $result" + } else { + # update fcc? + if {[info exists expanded_fcc] + && (![info exists has_fcc] || 0 == [string compare [lindex $fccdef 1] [lindex $has_fcc 1]])} { + for {set j 0} {$j < [llength $msgdata]} {incr j} { + if {[string compare fcc [fieldname [lindex [lindex $msgdata $j] 0]]] == 0} { + set fcc_index $j + break + } + } + + set colid [lindex $fccdef 0] + if {[info exists fcc_index]} { + set msgdata [lreplace $msgdata $fcc_index $fcc_index [list Fcc [list $colid $expanded_fcc]]] + } else { + lappend msgdata [list Fcc [list $colid $expanded_fcc]] + } + } + + # do the sending... + set verb Send + set verbpast Sent + set postcmd PECompose + set postcmdopt post + } + } else { + WPCmd PEInfo statmsg "Send MUST include Recipients (To, Cc, Bcc, or Fcc)" + } +} elseif {[string compare OK [string trim $action]] == 0 && ($postpone || [string compare $sendop postpone] == 0)} { + set verb Postpone + set verbpast Postponed + set postcmd PEPostpone + set postcmdopt append +} elseif {$help == 1 || [string compare "get help" [string tolower $help]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + _cgi_set_uservar oncancel "compose&restore=1" + set src help + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$check == 1 || [string compare spell [string tolower [string range $check 0 4]]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + set src spell + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$queryattach == 1 || [string compare "add attachment" [string tolower $queryattach]] == 0 || [string compare "attach" [string tolower $queryattach]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + set src askattach + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$br_to == 1 || [string compare browse [string tolower $br_to]] == 0 || [string compare to [string tolower $br_to]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + set oncancel compose + _cgi_set_uservar op browse + _cgi_set_uservar field to + set src addrbrowse + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$br_cc == 1 || [string compare browse [string tolower $br_cc]] == 0 || [string compare cc [string tolower $br_cc]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + set oncancel compose + _cgi_set_uservar op browse + _cgi_set_uservar field cc + set src addrbrowse + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$br_bcc == 1 || [string compare browse [string tolower $br_bcc]] == 0 || [string compare bcc [string tolower $br_bcc]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + set oncancel compose + _cgi_set_uservar op browse + _cgi_set_uservar field bcc + set src addrbrowse + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$br_reply_to == 1 || [string compare browse [string tolower $br_reply_to]] == 0 || [string compare "reply_to" [string tolower $br_reply_to]] == 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + set oncancel compose + _cgi_set_uservar op browse + _cgi_set_uservar field reply-to + set src addrbrowse + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {$br_fcc == 1 || ($br_fcc > 0 && [string length $br_fcc] > 0)} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + # fake cgi input for script + _cgi_set_uservar onselect compose + _cgi_set_uservar oncancel compose + set src fldrbrowse + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {[string compare expand [string tolower $ex_to]] == 0} { + if {[expand_address_field To msgdata]} { + set src ldapbrowse + } +} elseif {[string compare expand [string tolower $ex_cc]] == 0} { + if {[expand_address_field Cc msgdata]} { + set src ldapbrowse + } +} elseif {[string compare expand [string tolower $ex_bcc]] == 0} { + if {[expand_address_field Bcc msgdata]} { + set src ldapbrowse + } +} elseif {[string compare expand [string tolower $ex_reply_to]] == 0} { + if {[expand_address_field Reply-To msgdata]} { + set src ldapbrowse + } +} elseif {[string length $extrahdrs] > 0} { + # save msgdata to servlet + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + if {[catch {WPCmd PEInfo set wp_extra_hdrs} extras] || $extras == 1} { + set toggle 0 + } else { + set toggle 1 + } + + catch {WPCmd PEInfo set wp_extra_hdrs $toggle} + + _cgi_set_uservar restore 1 + set src compose + } else { + # else fall thru back into composer + WPCmd PEInfo statmsg "Compose Error: $errstr" + } +} elseif {[string compare OK [string trim $action]] == 0 && ($cancel || [string compare $sendop cancel] == 0)} { + # clean up attachments + WPCmd PEInfo statmsg "Message cancelled" + catch {WPCmd PEInfo unset suspended_composition} + catch {WPCmd PEInfo unset wp_extra_hdrs} + set src "" +} else { + # check for per-attachment ops + if {[info exists attachments]} { + set a [split $attachments ","] + for {set i 0} {$i < [llength $a]} {incr i} { + if {[catch {cgi_import detach_[lindex $a $i].x}] == 0} { + if {[catch {WPCmd PECompose unattach [lindex $a $i]} result]} { + WPCmd PEInfo statmsg "Unattach: $result" + } else { + set attachment_deleted [lindex $a $i] + + set a [lreplace $a $i $i] + set attachments [join $a ","] + + for {set i 0} {$i < [llength $msgdata]} {incr i} { + if {[string compare attach [lindex [lindex $msgdata $i] 0]] == 0 && [lindex [lindex $msgdata $i] 1] == $attachment_deleted} { + set msgdata [lreplace $msgdata $i $i] + break + } + } + + WPCmd PEInfo statmsg "Attachment Removed" + } + + break + } + } + } + + if {![info exists attachment_deleted]} { + WPCmd PEInfo statmsg "Unrecognized Action" + } +} + +#do what was asked +if {[info exists postcmd]} { + if {[info exists msgdata]} { + if {[catch {WPCmd $postcmd $postcmdopt $msgdata} errstr]} { + # if auth problem, save msgdata for after we ask for credentials + if {([string compare NOPASSWD [string range $errstr 0 7]] == 0 || [string compare BADPASSWD [string range $errstr 0 8]] == 0) + && [catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + + if {[catch {WPCmd PEInfo authrequestor} server]} { + append reason "Unknown server asking for authentication. Press cancel to abort if you think this message is in error." + } else { + append reason "[cgi_nl]Enter Username and Password to connect to [cgi_bold $server]" + lappend params [list server $server] + } + + if {[catch {WPCmd PESession creds 0 "{$server}"} creds] == 0 && $creds != 0} { + catch {WPCmd PEInfo statmsg "Invalid Username or Password"} + WPCmd PESession nocred 0 "{$server}" + } + + WPCmd set reason "The server ($server) used to send this message requires authentication.[cgi_nl]" + + WPCmd set cid [WPCmd PEInfo key] + WPCmd set authcol 0 + WPCmd set authfolder "{$server}" + WPCmd set authpage [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=dosend"] + WPCmd set authcancel [WPPercentQuote "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=compose&restore=1&cid=$cid"] + + set src auth + + } else { + # regurgitate the compose window + set style "" + set title "$verb Error: [cgi_font class=notice "$errstr"]" + if {[string length $errstr]} { + set notice "$verb FAILED: $errstr" + } else { + set notice "$verb FAILED: [WPCmd PEInfo statmsg]" + } + + WPCmd PEInfo statmsg "$notice" + + # regurgitate the compose window + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + _cgi_set_uservar restore 1 + set src compose + + unset body + } else { + } + + set src compose + } + } else { + catch {WPCmd PEInfo unset suspended_composition} + WPCmd PEInfo statmsg "Message $verbpast!" + } + } else { + WPCmd PEInfo statmsg "No Message $verbpast!" + } + + if {[info exists delete_me]} { + foreach i $delete_me { + catch {file delete $i} + } + } +} elseif {![info exists src]} { + set style "" + set title "Compose Message" + catch {unset attachments} + + # regurgitate the compose window + if {[catch {WPCmd PEInfo set suspended_composition $msgdata} errstr] == 0} { + _cgi_set_uservar restore 1 + set src compose + + unset body + } +} + +if {[info exists src] && [string length $src]} { + source [WPTFScript $src] +} else { + cgi_redirect "[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=$postpost" +} diff --git a/web/cgi/alpine/1.0/promptsave.tcl b/web/cgi/alpine/1.0/promptsave.tcl new file mode 100755 index 00000000..c7e7c2d8 --- /dev/null +++ b/web/cgi/alpine/1.0/promptsave.tcl @@ -0,0 +1,149 @@ +#!./tclsh +# $Id: promptsave.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# promptsave.tcl +# +# Purpose: CGI script to generate html form used to gather folder +# name and collection for aggregate save + +# Input: +# conftext : +# params : array of key/value pairs to submit with form +# oncancel : url to reference should user cancel dialog +set psave_vars { + {uid "" 0} +} + +# Output: +# +# HTML/CSS data representing the form for save folder dialog + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * OK * * * * + cgi_image_button save=[WPimg but_save] border=0 alt="Save" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] wp.tcl?${oncancel}] + } + } + } +} + +WPEval $psave_vars { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Aggregate Save" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context promptsave} + catch {WPCmd PEInfo set wp_index_script fr_promptsave.tcl} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text page=body type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data align=center valign=top class=dialog { + cgi_table width="80%" { + cgi_table_row { + cgi_table_data colspan=2 { + cgi_center { + cgi_puts "[cgi_nl][cgi_nl]This page provides a way to save messages to a folder" + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center nowrap class=dialog colspan=2 { + cgi_puts [cgi_font face=tahoma,verdana,geneva "Save for messages "] + + cgi_put "Save " + + if {!$uid} { + set n [WPCmd PEMailbox selected] + cgi_put "all [cgi_bold [WPcomma $n]] marked message[WPplural $n] " + if {[catch {WPCmd PEMessage $uid savedefault} savedefault]} { + set savedefault [list 1 saved-messages] + } + } else { + set savedefault [list 1 saved-messages] + } + + cgi_put "to " + cgi_br + + cgi_text "savename=[lindex $savedefault 1]" type=text size=14 maxlength=256 class=aggop style=vertical-align:middle onFocus=this.select() + if {[catch {WPCmd PEFolder collections} collections] == 0 && [llength $collections] > 1} { + cgi_put "[cgi_nbspace]in " + cgi_select savecolid class=aggop style=vertical-align:middle { + set defcol [lindex $savedefault 0] + set j 0 + foreach i $collections { + if {$j == $defcol} { + set selected selected + } else { + set selected {} + } + if {[string length [set f [lindex $i 1]]] > 12} { + set f "[string range $f 0 10]..." + } + + cgi_option $f value=$j $selected + incr j; + } + } + } else { + cgi_text "savecolid=0" type=hidden notab + } + + cgi_br + cgi_puts "[cgi_nl]Click [cgi_italic Save] to save the message the folder, or [cgi_italic Cancel] to abort the save." + } + } + + cgi_table_row { + cgi_table_data class=dialog align=center colspan=2 { + cgi_br + cgi_submit_button save=Save + cgi_submit_button savecancel=Cancel + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/prune.tcl b/web/cgi/alpine/1.0/prune.tcl new file mode 100755 index 00000000..c35552e3 --- /dev/null +++ b/web/cgi/alpine/1.0/prune.tcl @@ -0,0 +1,74 @@ +# $Id: prune.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# post.tcl +# +# Purpose: CGI script to perform monthly message pruning via prunetime.tcl +# generated form + +# Input: +set prune_vars { + {cid "Missing Command ID"} + {mvcnt "Missing Move Count"} + {delList "" ""} +} + +# Output: +# + +## read vars +foreach item $prune_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {$cid != [WPCmd PEInfo key]} { + error [list _action Postpone "Invalid Operation ID" "Click Back button to try again."] +} + +set mvvals {} +for {set i 0} {$i < $mvcnt} {incr i} { + WPLoadCGIVarAs "mv${i}" tmpmv + if {[string compare $tmpmv ""]} { + lappend mvvals $tmpmv + } +} + +foreach mvval $mvvals { + set mvfrm [lindex $mvval 1] + set mvto [lindex $mvval 2] + + if {[catch {WPCmd PEFolder rename default $mvfrm $mvto} result]} { + set msg "Can't Rename $mvfrm: $result" + } else { + set msg "Renaming \"${mvfrm}\" at start of month" + catch {WPCmd PEFolder create default $mvfrm} result + } + WPCmd PEInfo statmsg $msg +} + +foreach delfldr $delList { + set msg "" + if {[catch {WPCmd PEFolder delete default $delfldr} result]} { + set msg "Can't delete ${delfldr}: $result" + } else { + set msg "Deleted $delfldr" + } + WPCmd PEInfo statmsg $msg +} + +source [WPTFScript main] diff --git a/web/cgi/alpine/1.0/queryattach.tcl b/web/cgi/alpine/1.0/queryattach.tcl new file mode 100755 index 00000000..9cd7028c --- /dev/null +++ b/web/cgi/alpine/1.0/queryattach.tcl @@ -0,0 +1,145 @@ +#!./tclsh +# $Id: queryattach.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryattach.tcl +# +# Purpose: CGI script to generate html form used to ask for +# attachment to composition + +# Input: + +# Output: +# +# HTML/CSS data representing the form + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +# make sure form's in Unicode +set charset "UTF-8" + +set query_menu { + { + {} + { + { + cgi_puts "Get Help" + } + } + } + { + {expr 0} + { + { + # * * * * OK * * * * + cgi_submit_button "attach=Add Attachment" class="navbar" + } + } + } + { + {expr 0} + { + { + # * * * * CANCEL * * * * + cgi_submit_button cancel=Cancel class="navbar" + } + } + } + { + {expr 0} + { + { + # * * * * Address/Cancel * * * * + cgi_submit_button doit=Done class="navbar" + cgi_br + cgi_select attachop class=navtext { + cgi_option "Action..." value=null + cgi_option Attach value=attach + cgi_option Cancel value=cancel + } + } + } + } +} + +WPEval {} { + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=\"$charset\"" + } + + cgi_html { + cgi_head { + cgi_http_equiv Content-Type "text/html; charset=$charset" + WPStdHtmlHdr "Attach" + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".filename { font-family: Courier, monospace ; font-size: 10pt }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data target=_top { + cgi_text page=attach type=hidden notab + cgi_text cid=[WPCmd PEInfo key] type=hidden notab + if {[info exists params]} { + foreach p $params { + cgi_text "[lindex $p 0]=[lindex $p 1]" type=hidden notab + } + } + + cgi_table border=0 cellpadding=0 cellspacing=0 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data align=center valign=top class=dialog { + cgi_table border=0 width=75% cellpadding=15 { + cgi_table_row { + cgi_table_data align=center { + cgi_puts "To attach a file to your message, enter its path and file name below, or use the [cgi_italic Browse] button to choose the file, then click [cgi_italic "Add Attachment"], or click [cgi_italic Cancel] to return to your composition without attaching anything." + } + } + cgi_table_row { + cgi_table_data align=center { + cgi_file_button file "accept=*/*" size=30 class=filename + } + } + cgi_table_row { + cgi_table_data align=center { + cgi_puts "You can also provide a short description to help the message's recipient figure out what the attachment is :" + } + } + cgi_table_row { + cgi_table_data align=center { + cgi_text description= maxlength=256 size=40 class=filename + } + } + cgi_table_row { + cgi_table_data align=center { + cgi_submit_button "attach=Add Attachment" + cgi_submit_button cancel=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querycreate.tcl b/web/cgi/alpine/1.0/querycreate.tcl new file mode 100755 index 00000000..b3057ab3 --- /dev/null +++ b/web/cgi/alpine/1.0/querycreate.tcl @@ -0,0 +1,114 @@ +#!./tclsh +# $Id: querycreate.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querycreate.tcl +# +# Purpose: CGI script to generate html form used to confirm folder +# creation for Save + +# Input: +# conftext : +# params : array of key/value pairs to submit with form +# oncancel : url to reference should user cancel confirmation +set qcreate_vars { +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * OK * * * * + cgi_image_button create=[WPimg but_create] border=0 alt="Create" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] wp.tcl?${oncancel}] + } + } + } +} + +WPEval $qcreate_vars { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Confirm Creation" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + if {[catch {WPCmd PEInfo set querycreate_state} qstate]} { + + } else { + catch {WPCmd PEInfo unset querycreate_state} + + set folder [lindex $qstate 0] + set params [lindex $qstate 1] + + catch {WPCmd PEInfo set help_context create_save} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=spec { + if {[info exists params]} { + foreach p $params { + cgi_text "[lindex $p 0]=[lindex $p 1]" type=hidden notab + } + } + + cgi_table border=0 cellspacing=0 cellpadding=30 width="100%" height="100%" class=dialog { + cgi_table_row { + cgi_table_data align=center valign=top { + cgi_table width="80%" border=0 { + cgi_table_row { + cgi_table_data valign=top align=center { + cgi_puts "You are attempting to Save to a folder, [cgi_bold $folder], that does not exist." + cgi_br + cgi_puts "[cgi_nl]Click [cgi_italic Create] to create [cgi_bold $folder] and save the message, or [cgi_italic Cancel] to create nothing and return to the Message View." + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_br + cgi_submit_button create=Create + cgi_submit_button savecancel=Cancel + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querydelfldr.tcl b/web/cgi/alpine/1.0/querydelfldr.tcl new file mode 100755 index 00000000..e0fa960a --- /dev/null +++ b/web/cgi/alpine/1.0/querydelfldr.tcl @@ -0,0 +1,121 @@ +#!./tclsh +# $Id: querydelfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querydelfldr.tcl +# +# Purpose: CGI script to generate html form used to confirm +# folder deletion + +# Input: +set fldr_vars { + {fid "No Folder Specified"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put "Get Help" + } + } + } +} + +WPEval $fldr_vars { + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Confirm Delete" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "fid=$fid" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "frestore=1" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="75%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_nl][cgi_nl][cgi_nl][cgi_nl] + + regsub -all { } [lindex $fid end] {\ } dfn + + cgi_puts "Please confirm that you would like to permanently remove [cgi_bold $dfn]" + + if {[llength $fid] > 2} { + if {[catch {WPCmd PEFolder delimiter [lindex $fid 0]} delim]} { + set delim / + } + + set dirname "" + for {set i 1} {$i < ([llength $fid] - 1)} {incr i} { + append dirname "[lindex $fid $i]$delim" + } + + if {[string length $dirname]} { + cgi_put " from the directory [cgi_bold $dirname] " + } + } + if {[llength $collections] > 1} { + cgi_put "in the collection '[lindex [lindex $collections [lindex $fid 0]] 1]'." + } else { + cgi_put "." + } + + cgi_br + cgi_br + cgi_puts "Click [cgi_italic Delete] to remove the folder permanently, or [cgi_italic Cancel] to return to the Folder List." + cgi_br + cgi_br + cgi_submit_button delete=Delete + cgi_submit_button delete=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/queryexpunge.tcl b/web/cgi/alpine/1.0/queryexpunge.tcl new file mode 100755 index 00000000..c3e552d6 --- /dev/null +++ b/web/cgi/alpine/1.0/queryexpunge.tcl @@ -0,0 +1,203 @@ +#!./tclsh +# $Id: queryexpunge.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryexpunge.tcl +# +# Purpose: CGI script to generate html form used to confirm +# deleted message expunge + +# Input (Assumed set by sourcing script): +# fn : Name of folder getting expunged +# delcount : Number of deleted messages + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl + +WPEval {} { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Confirm Expunge" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context expunge} + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data valign=top align=center class=dialog { + cgi_form $_wp(appdir)/$_wp(ui1dir)/fr_index method=get name=confirm target=spec { + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + set mbn [WPCmd PEMailbox mailboxname] + cgi_table border=0 cellspacing=8 cellpadding=8 width="75%" { + + if {[catch {WPCmd PEMailbox flagcount deleted} delcount] == 0 && $delcount > 0 + && [catch {WPCmd PEMailbox messagecount} messcount] == 0} { + + cgi_table_row { + cgi_table_data align=center valign=middle height=50 { + cgi_table bgcolor=yellow background=[WPimg dstripe] cellpadding=6 { + cgi_table_row { + cgi_table_data { + cgi_table bgcolor=black cellpadding=6 { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_font size=+2 color=yellow [cgi_bold "CAUTION!"]] + } + } + } + } + } + } + } + } + + if {$delcount == $messcount} { + switch $delcount { + 1 { + set m1 "The [cgi_bold only] message in the folder [cgi_bold $mbn] is deleted." + set m2 "that [cgi_bold single] message" + } + 2 { + set m1 "[cgi_bold Both] messages in the folder [cgi_bold $mbn] are deleted." + set m2 "[cgi_bold "both"] messages" + } + default { + set m1 "[cgi_span "style=font-weight: bold; color: red" "All $messcount messages"] in the folder [cgi_bold $mbn] are marked for deletion. This includes any messages that might <u>not</u> be <u>visible</u> on the screen." + set m2 "[cgi_bold [cgi_span "style=font-size: bigger; color: red; text-decoration: underline" "all messages"]]" + } + } + + append m1 "[cgi_nl][cgi_nl]Expunge now will leave this folder " + append m1 "[cgi_span "style=font-weight: bold; color: red" empty]. " + #append m1 "[cgi_nl][cgi_nl]Please acknowledge below that you understand there will be [cgi_span "style=font-weight: bold; color: red" "no more messages"] within this folder when the expunge is complete." + append m1 "[cgi_nl][cgi_nl][cgi_buffer {cgi_checkbox "emptyit=1"}] " + append m1 "I acknowledge expunge will leave folder [cgi_bold $mbn] [cgi_span "style=font-weight: bold; color: red" empty]." + set style "style=\"border: 1px solid #663333; background-color: #ffcc66;\"" + set m3 ALL + } else { + if {$delcount > 1} { + set whch are + set plrl "s" + } else { + set whch is + set plrl "" + } + + set m1 "Your folder [cgi_bold $mbn] contains $messcount messages, of which [cgi_bold $delcount] $whch deleted." + set m2 "[cgi_span "style=font-size: bigger; font-weight: bold" $delcount] message${plrl}" + set m3 $delcount + set style "" + } + + cgi_table_row { + cgi_table_data align=center $style { + cgi_puts $m1 + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "Do you wish to [cgi_span "style=color: red ; font-weight: bold" "permanently remove"] $m2 now?" + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_submit_button "expunge=Yes, Remove $m3 message[WPplural $delcount]" tabindex=2 + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_submit_button "cancel=No, Return to '$mbn'" tabindex=1 checked selected default + } + } + } else { + cgi_table_row { + cgi_table_data align=center { + cgi_puts "There are [cgi_bold no] messages currently marked for deletion in the folder [cgi_bold [WPCmd PEMailbox mailboxname]]." + } + } + + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + switch [WPCmd PEInfo aggtabstate] { + 0 { + lappend methods "Click the [cgi_img [WPimg slideout] style=vertical-align:middle] tab to expose aggregate operations" + lappend methods "Place a mark in the checkbox next to each desired message" + lappend methods "Click the [cgi_italic Delete] button" + } + 1 { + lappend methods "Place a mark in the checkbox next to each desired message" + lappend methods "Click the [cgi_italic Delete] button" + } + 2 { + lappend methods "Place a mark in the checkbox next to each desired message" + lappend methods "Within the Message Status box, choose [cgi_bold Deleted] from the drop-down list of flag choices" + lappend methods "Click the [cgi_italic Set] button" + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "To mark a message for deletion while viewing it, simply click the [cgi_italic Delete] button at the top of the Message View page." + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "To mark messages for deletion in the Message List:" + cgi_number_list { + foreach i $methods { + cgi_li $i + } + } + } + } + } else { + cgi_table_row { + cgi_table_data align=center { + cgi_puts "To mark a message for deletion, click the [cgi_italic Delete] button while viewing the message." + } + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "Click [cgi_italic OK] to return to the Message List." + cgi_br + cgi_br + cgi_submit_button cancel=OK + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/queryimport.tcl b/web/cgi/alpine/1.0/queryimport.tcl new file mode 100755 index 00000000..1f40bad2 --- /dev/null +++ b/web/cgi/alpine/1.0/queryimport.tcl @@ -0,0 +1,146 @@ +#!./tclsh +# $Id: queryimport.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryimport.tcl +# +# Purpose: CGI script to generate html form used to ask for +# importing a folder + +# Input: +set import_vars { + {fid "No Collection Specified"} +} + +# Output: +# +# HTML/CSS data representing the form + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {expr {0}} + { + { + cgi_puts "Get Help" + } + } + } +} + +WPEval $import_vars { + + set colid [lindex $fid 0] + if {[llength $fid] > 1} { + set fpath [eval "file join [lrange $fid 1 end]"] + } else { + set fpath "" + } + + if {[catch {WPCmd PEFolder collections} collections]} { + catch {WPCmd PEInfo statmsg "Can't Import: $collections"} + cgi_http_head { + cgi_redirect [cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders.tcl + } + } elseif {$colid < 0 || $colid > [llength $collections]} { + catch {WPCmd PEInfo statmsg "Can't Import: Invalid collection: $colid"} + cgi_http_head { + cgi_redirect [cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=folders.tcl + } + } else { + + if {[string length $fpath]} { + set coldesc "the directory [cgi_bold $fpath] within " + } + + append coldesc "the collection [cgi_bold [lindex [lindex $collections $colid] 1]]" + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Import" + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".filename { font-family: Courier, monospace ; font-size: 10pt }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data target=_top { + cgi_text page=folders type=hidden notab + cgi_text cid=[WPCmd PEInfo key] type=hidden notab + cgi_text fid=$fid type=hidden notab + + cgi_table border=0 cellpadding=0 cellspacing=0 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data align=center valign=top class=dialog { + cgi_table border=0 width=75% cellpadding=15 { + cgi_table_row { + cgi_table_data align=center "style=\"padding-top:30\"" { + cgi_puts "Folder Import copies a mail folder, typically created by the Export command, from the computer your browser is running on into a new Web Alpine folder. [cgi_nbspace]Successful Import consists of three steps." + cgi_p + cgi_puts "First, enter the path and filename of the folder below. Use the [cgi_italic Browse] button to help choose the file." + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_file_button file "accept=*/*" size=30 class=filename + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "Second, provide a [cgi_bold unique] name for the imported folder to be assigned within $coldesc:" + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_text iname= maxlength=256 size=40 class=filename + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_puts "Finally, click [cgi_italic "Import File"] to copy the folder into WebPine, or [cgi_italic Cancel] to return to the folder list." + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_submit_button "import=Import File" class=navtext + cgi_submit_button cancel=Cancel class=navtext + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querynewdir.tcl b/web/cgi/alpine/1.0/querynewdir.tcl new file mode 100755 index 00000000..e2adeaae --- /dev/null +++ b/web/cgi/alpine/1.0/querynewdir.tcl @@ -0,0 +1,113 @@ +#!./tclsh +# $Id: querynewdir.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querynewfldr.tcl +# +# Purpose: CGI script to generate html form used to confirm +# folder creation + +# Input: +set fldr_vars { + {fid "No Collection Specified"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put "Get Help" + } + } + } +} + +WPEval $fldr_vars { + + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Creation" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context diradd} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden + cgi_text "fid=$fid" type=hidden + cgi_text "frestore=1" type=hidden + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="70%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_nl][cgi_nl][cgi_nl][cgi_nl] + cgi_puts "Please enter the name of the directory you would like to add" + if {[llength $fid] > 1} { + cgi_put " to the directory '[join [lrange $fid 1 end] /]'" + } + if {[llength $collections] > 1} { + cgi_put "in the collection '[lindex [lindex $collections [lindex $fid 0]] 1]'." + } else { + cgi_put "." + } + cgi_br + cgi_br + cgi_put "New directory name: " + cgi_text directory= maxlength=64 size=25% + cgi_br + cgi_br + cgi_puts "Click 'Create' to add a new directory by that name, or 'Cancel' to return to the Folder List." + cgi_br + cgi_br + cgi_submit_button newdir=Create + cgi_submit_button newdir=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querynewfldr.tcl b/web/cgi/alpine/1.0/querynewfldr.tcl new file mode 100755 index 00000000..598b6db6 --- /dev/null +++ b/web/cgi/alpine/1.0/querynewfldr.tcl @@ -0,0 +1,112 @@ +#!./tclsh +# $Id: querynewfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querynewfldr.tcl +# +# Purpose: CGI script to generate html form used to confirm +# folder creation + +# Input: +set fldr_vars { + {fid "No Collection Specified"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put [cgi_url "Get Help" wp.tcl?page=help&oncancel=folders class=navbar target=_top] + } + } + } +} + +WPEval $fldr_vars { + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Creation" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context foldadd} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "fid=$fid" type=hidden + cgi_text "cid=[WPCmd PEInfo key]" type=hidden + cgi_text "frestore=1" type=hidden + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="70%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_nl][cgi_nl][cgi_nl][cgi_nl] + cgi_puts "Please enter the name of the folder you would like to add" + if {[llength $fid] > 1} { + cgi_put " to the directory '[join [lrange $fid 1 end] /]'" + } + if {[llength $collections] > 1} { + cgi_put " in the collection '[lindex [lindex $collections [lindex $fid 0]] 1]'." + } else { + cgi_put "." + } + cgi_br + cgi_br + cgi_put "New folder name: " + cgi_text folder= maxlength=64 size=25% + cgi_br + cgi_br + cgi_puts "Click 'Create' to add a new folder by that name, or 'Cancel' to return to the Folder List." + cgi_br + cgi_br + cgi_submit_button newfolder=Create + cgi_submit_button newfolder=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querynewfoldir.tcl b/web/cgi/alpine/1.0/querynewfoldir.tcl new file mode 100755 index 00000000..13c20126 --- /dev/null +++ b/web/cgi/alpine/1.0/querynewfoldir.tcl @@ -0,0 +1,131 @@ +#!./tclsh +# $Id: querynewfoldir.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querynewfoldir.tcl +# +# Purpose: CGI script to generate html form used to confirm +# folder and directory creation +# Input: +set fldr_vars { + {fid "No Collection Specified"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put [cgi_url "Get Help" wp.tcl?page=help&oncancel=folders class=navbar target=_top] + } + } + } +} + +WPEval $fldr_vars { + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Creation" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context foldiradd} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "fid=$fid" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "frestore=1" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + if {[llength $fid] > 1} { + set Dirpref "Subd" + set dirpref "subd" + } else { + set Dirpref "D" + set dirpref "d" + } + + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="70%" { + + cgi_table_row { + cgi_table_data align=center { + cgi_br + cgi_put "Folders are used to contain messages. Typically, messages are placed in folders when you [cgi_italic Save] them from the Message View" + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + cgi_puts " or Message List pages." + } else { + cgi_puts "page." + } + + cgi_put "To create a new folder" + + if {[llength $fid] > 1} { + cgi_put " within the directory [cgi_bold [join [lrange $fid 1 end] /]]" + } + if {[llength $collections] > 1} { + cgi_put " in the collection [cgi_bold [lindex [lindex $collections [lindex $fid 0]] 1]]" + } + + cgi_put ", enter the name below and click [cgi_italic "Create New Folder"]." + cgi_br + cgi_br + + cgi_put "Furthermore, folders can be created within directories. The directory can either be one that now exists " + cgi_put " or one that you wish to create along with the new folder. " + cgi_put "Simply specify the directory name before the folder name separating the two with a "[WPCmd PEFolder delimiter [lindex $fid 0]]" character." + cgi_br + cgi_br + cgi_put "New folder name: " + cgi_text folder= maxlength=64 size=25% + cgi_br + cgi_br + cgi_submit_button "newfolder=Create New Folder" "style=\"margin-right: 10px\"" + cgi_submit_button cancelled=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querynick.tcl b/web/cgi/alpine/1.0/querynick.tcl new file mode 100755 index 00000000..1e794822 --- /dev/null +++ b/web/cgi/alpine/1.0/querynick.tcl @@ -0,0 +1,171 @@ +#!./tclsh +# $Id: querynick.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querynick.tcl +# +# Purpose: CGI script to generate html form used to deal +# with existing/taken nickname collision +# + +# Input: +set nick_vars { + {book "Missing address book"} + {nick {} ""} + {add {} 0} + {fn {} ""} + {addrs {} ""} + {fcc {} ""} + {comment {} ""} + {take {} 0} + {newnick {} ""} + {ai {} -1} +} + +# Output: +# + +# Command Menu +set nick_menu { +} + +set common_menu { + { + {} + { + { + cgi_puts "Get Help" + } + } + } +} + + +# Output: +# Query prompt to deal with existing/taken nickname collision +# +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $nick_vars { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Take to New Entry or List" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + #catch {WPCmd PEInfo set help_context samenick} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=samenick target=_top { + + cgi_table border=0 cellspacing=0 cellpadding=2 height="100%" { + cgi_table_row { + cgi_table_data valign=top class=navbar { + cgi_table bgcolor=$_wp(menucolor) border=0 cellspacing=0 cellpadding=2 { + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar { + WPTFCommandMenu nick_menu common_menu + } + } + } + } + } + + cgi_table_data valign=top class=navbar { + + cgi_text "page=addrsave" type=hidden notab + cgi_text "oncancel=main" type=hidden notab + cgi_text "take=1" type=hidden notab + cgi_text "ai=${ai}" type=hidden notab + cgi_text "book=${book}" type=hidden notab + cgi_text "nick=${nick}" type=hidden notab + cgi_text "fn=${fn}" type=hidden notab + cgi_text "addrs=${addrs}" type=hidden notab + cgi_text "fcc=${fcc}" type=hidden notab + cgi_text "comment=${comment}" type=hidden notab + cgi_text "newnick=${newnick}" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=15 width="75%" { + cgi_table_row { + cgi_table_data align=center colspan=2 "xstyle=padding-top:20;padding-bottom:20" { + cgi_puts "An address book entry with the nickname \"[cgi_bold $newnick]\" already exists. At this point you may click either:" + } + } + + cgi_table_row { + cgi_table_data align=right { + cgi_submit_button "replace=Replace Entry" + } + cgi_table_data "xstyle=padding:15" { + cgi_puts "Replace the \"[cgi_bold $newnick]\" address book entry with your [cgi_italic Take] selection." + } + } + + cgi_table_row { + cgi_table_data align=right { + cgi_submit_button "replace=Add to Entry" + } + cgi_table_data "xstyle=padding:15" { + if {[string first "," $addrs] >= 0} { + set plur "es" + } else { + set plur "" + } + + cgi_puts "Add the address${plur} from your [cgi_italic Take] selection to the existing entry's addresses to create a list." + } + } + + cgi_table_row { + cgi_table_data align=right { + cgi_submit_button "replace=Edit" + } + cgi_table_data "xstyle=padding:15" { + cgi_puts "Go back to editing your [cgi_italic Take] selection." + } + } + + cgi_table_row { + cgi_table_data align=right { + cgi_submit_button "cancel=Cancel" + } + cgi_table_data "xstyle=padding:15" { + cgi_puts "Or, Cancel your [cgi_italic Take] selection altogether." + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/queryprune.tcl b/web/cgi/alpine/1.0/queryprune.tcl new file mode 100755 index 00000000..896bc333 --- /dev/null +++ b/web/cgi/alpine/1.0/queryprune.tcl @@ -0,0 +1,170 @@ +#!./tclsh +# $Id: queryprune.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryprune.tcl +# +# After we've already determined that it's the +# beginning of the month (logon.tcl), we check +# what folders need pruning and offer them to +# the user. Currently doesn't do automatic +# reload. + +# Input: +set prunetime_vars { + {cid "Missing Command ID"} + {start "Missing Start Page"} + {nojs "" 0} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set prune_menu { + { + {} + { + { + # * * * * DONE * * * * + cgi_submit_button prune=Continue + } + } + } +} + + +WPEval $prunetime_vars { + catch {WPCmd PEInfo prunetime} prunefldrs + set allclean 1 + set delstuff 0 + set askstuff 0 + foreach prunefldr $prunefldrs { + if {[llength [lindex $prunefldr 1]] > 0 || [llength [lindex $prunefldr 2]] > 0} { + set allclean 0 + } + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Monthly Folder Pruning" + WPStdScripts + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + cgi_form [file join $_wp(appdir) $_wp(ui1dir) wp] method=post name=pruneit target=_top { + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + + cgi_table_row { + # next comes the menu down the left side + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu prune_menu {} + } + } + + cgi_table_data valign=top align=center class=dialog "style=\"padding: 20\"" { + + if {$allclean == 1} { + catch {WPCmd PEInfo statmsg "Pruning Failed: $prunefldrs"} + cgi_puts "No folders appear to need cleaning up this month." + cgi_br + cgi_puts "Please click [cgi_url "here" $start target=_top] to continue your session." + } else { + cgi_puts "At the beginning of every month, you are asked if you would like to clean up your sent-mail folder(s). Please answer the following questions and click [cgi_italic Continue]." + cgi_text "sessid=$_wp(sessid)" type=hidden notab + cgi_text "op=pruneit" type=hidden notab + cgi_text "cid=${cid}" type=hidden notab + cgi_text "page=prune" type=hidden notab + set cnt 0 + foreach prunefldr $prunefldrs { + set type [lindex $prunefldr 0] + set mv [lindex $prunefldr 1] + set dellist [lindex $prunefldr 2] + + cgi_table border=0 cellpadding=8 cellspacing=0 "style=\"padding-top: 8\"" { + if {[llength $mv] > 1} { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_bold "Move current "[lindex $mv 0]" to "[lindex $mv 1]"?"] + } + } + cgi_table_row { + cgi_table_data { + cgi_table "style=\"padding-left: 20\"" { + cgi_table_data { + cgi_radio_button "mv${cnt}=mv [lindex $mv 0] [lindex $mv 1]" checked class=body + } + cgi_table_data { + cgi_puts "Yes" + } + cgi_table_data { + cgi_radio_button "mv${cnt}=" class=body + } + cgi_table_data { + cgi_puts "No" + } + } + } + } + incr cnt + } + if {[llength $dellist] > 0} { + cgi_table_row { + cgi_table_data { + set plurtxt "" + set typetxt "" + if {[llength $dellist] > 1} { + set plurtxt "s" + } + if {[string compare $type ""] != 0} { + set typetxt "[string toupper $type] " + } + cgi_puts "[cgi_bold "To save disk space, delete the following ${typetxt}mail folder${plurtxt}:"] (Check to delete)" + } + } + + cgi_table_row { + cgi_table_data { + cgi_table "style=\"padding-left: 20\"" { + foreach del $dellist { + cgi_table_row { + cgi_table_data { + cgi_checkbox "delList=$del" "style=\"background-color: #FFFFFF; padding-right: 8\"" + cgi_puts "$del " + } + } + } + } + } + } + } + } + } + cgi_text "mvcnt=${cnt}" type=hidden notab + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/queryquit.tcl b/web/cgi/alpine/1.0/queryquit.tcl new file mode 100755 index 00000000..8c86078c --- /dev/null +++ b/web/cgi/alpine/1.0/queryquit.tcl @@ -0,0 +1,196 @@ +#!./tclsh +# $Id: queryquit.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryquit.tcl +# +# Purpose: CGI script to generate html form used to confirm quitting +# webpine while offering to expunge deleted + +# Input: +# conftext : +# params : array of key/value pairs to submit with form +# oncancel : url to reference should user cancel confirmation +set quit_vars { + {cid "Command ID"} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * OK * * * * + cgi_image_button quit=[WPimg but_create] border=0 alt="Create" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] wp.tcl?${oncancel}] + } + } + } +} + +WPEval $quit_vars { + + if {$cid != [WPCmd PEInfo key]} { + error "Invalid Command ID" + } + + catch {WPCmd PESession expungecheck quit} prompts + + set qhid "" + set delsexist 0 + set askinbox 1 + set askcurrent 1 + set ewc [WPCmd PEInfo feature expunge-without-confirm] + set ewce [WPCmd PEInfo feature expunge-without-confirm-everywhere] + + foreach prompt $prompts { + if {[lindex $prompt 1] > 0} { + set delsexist 1 + } + if {[lindex $prompt 1] > 0 && ($ewc || $ewce) && [lindex $prompt 2] == 1} { + set askinbox 0 + lappend qhid [cgi_buffer {cgi_text expinbox=1 type=hidden notab}] + } elseif {[lindex $prompt 1] > 0 && [lindex $prompt 2] == 0 && ($ewce || ($ewc && [lindex $prompt 3] == 1))} { + set askcurrent 0 + lappend qhid [cgi_buffer {cgi_text expcurrent=1 type=hidden notab}] + } + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Quitting Web Alpine" + WPStdScripts + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".expungebox { background-color:AntiqueWhite }" + cgi_put ".clickit { cursor: pointer }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + #catch {WPCmd PEInfo set help_context quit} + cgi_table width=100% height=100% cellspacing=0 cellpadding=0 { + cgi_table_row { + cgi_table_data width=112 bgcolor=$_wp(bordercolor) { + cgi_put [cgi_img [WPimg dot2]] + } + + cgi_table_data align=center valign=top bgcolor="$_wp(dialogcolor)" { + + cgi_form $_wp(appdir)/$_wp(ui1dir)/do_quit method=get id=quitting target=_top { + cgi_text cid=$cid type=hidden notab + cgi_text sessid=$sessid type=hidden notab + foreach q $qhid { + cgi_puts $q + } + + cgi_table border=0 cellspacing=0 cellpadding=10 width="70%" class=dialog "style=padding-top:12%" { + cgi_table_row { + cgi_table_data valign=top { + cgi_puts [cgi_font size=+1 "Really Quit WebPine?"] + } + } + cgi_table_row { + cgi_table_data valign=top { + cgi_table cellpadding=10 border=0 { + if {$delsexist} { + cgi_table_row { + cgi_table_data valign=middle class=expungebox "style=\"border: 1px solid red\"" { + if {[llength $prompts] > 1} { + set ftext "[lindex [lindex $prompts 0] 0] and [lindex [lindex $prompts 1] 0]" + } else { + set ftext "[lindex [lindex $prompts 0] 0]" + } + + cgi_put "This is a good opportunity to permanently remove from ${ftext} all of the messages you have marked for deletion." + cgi_br + cgi_br + cgi_table border=0 cellpadding=4 { + set expiexists 0 + set expcexists 0 + set inbhit 0 + set curhit 0 + foreach prompt $prompts { + set numdels [lindex $prompt 1] + set fname [lindex $prompt 0] + set inboxflag [lindex $prompt 2] + set incflag [lindex $prompt 3] + if {$inboxflag} { + incr inbhit + } else { + incr curhit + } + if {$numdels && (($askinbox && $inboxflag) || ($askcurrent && $inboxflag == 0))} { + cgi_table_row { + set cbn "cb[expr {$inbhit + $curhit}]" + cgi_table_data align=right valign=top { + if {$inboxflag} { + cgi_checkbox "expinbox" class=expungebox id=$cbn checked + incr expiexists + } else { + cgi_checkbox "expcurrent" class=expungebox id=$cbn checked + incr expcexists + } + } + cgi_table_data align=left { + set t "Expunge ${numdels} deleted message[expr {($numdels > 1) ? "s" : ""}] from ${fname}." + cgi_put [cgi_span class=clickit onclick=\"flipCheck('$cbn')\" $t] + } + } + } + } + } + } + } + } + } + } + } + + cgi_table_row { + cgi_table_data align=center valign=middle { + cgi_br + cgi_submit_button "quit=Yes, Quit Now" + cgi_put [cgi_img [WPimg dot2] width=10] + cgi_submit_button "cancel=No, Return to [WPCmd PEMailbox mailboxname]" + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/queryrenfldr.tcl b/web/cgi/alpine/1.0/queryrenfldr.tcl new file mode 100755 index 00000000..d84b303d --- /dev/null +++ b/web/cgi/alpine/1.0/queryrenfldr.tcl @@ -0,0 +1,109 @@ +#!./tclsh +# $Id: queryrenfldr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryrenfldr.tcl +# +# Purpose: CGI script to generate html form used to confirm +# folder creation + +# Input: +set fldr_vars { + {fid "No Collection Specified"} +} + +# Output: +# +# HTML/CSS data representing the message specified +# by the 'uid' argument + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * HELP * * * * + cgi_put "Get Help" + } + } + } +} + +WPEval $fldr_vars { + if {[catch {WPCmd PEFolder collections} collections]} { + error [list _action "Collection list" $collections] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Folder Creation" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=confirm target=_top { + cgi_text "page=folders" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden + cgi_text "fid=$fid" type=hidden + cgi_text "frestore=1" type=hidden + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=2 width="70%" { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_nl][cgi_nl][cgi_nl][cgi_nl] + cgi_puts "Please enter the new name of the folder '[lindex $fid end]'" + if {[llength $fid] > 2} { + cgi_put " in the directory '[join [lrange $fid 1 [expr {[llength $fid] - 2}]]]'" + } + if {[llength $collections] > 1} { + cgi_put " in the collection '[lindex [lindex $collections [lindex $fid 0]] 1]'." + } else { + cgi_put "." + } + cgi_br + cgi_br + cgi_put "Rename [cgi_bold [lindex $fid end]] to: " + cgi_text folder= maxlength=64 size=25% + cgi_br + cgi_br + cgi_puts "Click 'Rename' to permanently change the folder name, or 'Cancel' to return to the Folder List." + cgi_br + cgi_br + cgi_submit_button rename=Rename + cgi_submit_button rename=Cancel + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/querysave.tcl b/web/cgi/alpine/1.0/querysave.tcl new file mode 100755 index 00000000..0bfdf59d --- /dev/null +++ b/web/cgi/alpine/1.0/querysave.tcl @@ -0,0 +1,98 @@ +#!./tclsh +# $Id: querysave.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# querysave.tcl +# +# Purpose: CGI script to generate html form used to gather folder +# name and collection for aggregate save + +# Input: +# conftext : +# params : array of key/value pairs to submit with form +# oncancel : url to reference should user cancel dialog +set qsave_vars { +} + +# Output: +# +# HTML/CSS data representing the form for save folder dialog + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +set query_menu { + { + {} + { + { + # * * * * OK * * * * + cgi_image_button save=[WPimg but_save] border=0 alt="Save" + } + } + } + { + {} + { + { + # * * * * CANCEL * * * * + cgi_puts [cgi_url [cgi_img [WPimg but_cancel] border=0 alt="Cancel"] wp.tcl?${oncancel}] + } + } + } +} + +WPEval $qsave_vars { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Aggregate Save" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get { + if {[info exists params]} { + foreach p $params { + cgi_text "[lindex $p 0]=[lindex $p 1]" type=hidden notab + } + } + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data valign=top align=center class=dialog { + cgi_text "page=selsave" type=hidden notab + cgi_text "by=text" type=hidden notab + cgi_text "postpage=index" type=hidden notab + + cgi_puts [cgi_nl][cgi_nl][cgi_nl][cgi_nl] + cgi_puts "You are attempting to Save to a folder, '$folder', that does not exist." + cgi_br + cgi_puts "[cgi_nl]Click 'Create' to create the folder and save the message, or 'Cancel' to abort the save." + } + cgi_table_row { + cgi_table_data { + cgi_submit_button save=Save + cgi_submit_button cancel=Cancel + } + } + } + } + } + } + } + +} diff --git a/web/cgi/alpine/1.0/resume.tcl b/web/cgi/alpine/1.0/resume.tcl new file mode 100755 index 00000000..7a45333a --- /dev/null +++ b/web/cgi/alpine/1.0/resume.tcl @@ -0,0 +1,169 @@ +#!./tclsh +# $Id: resume.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# resume.tcl +# +# Purpose: CGI script to browse postponed messages + +# Input: +set resume_vars { + {oncancel "" main.tcl} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +set resume_cmds { + { + {} + { + { + cgi_puts [cgi_url "Get Help" wp.tcl?page=help&oncancel=resume target=_top class=navbar] + } + } + } +} + +WPEval $resume_vars { + + if {![info exists oncancel]} { + WPLoadCGIVarAs oncancel oncancel + } + + if {[catch {WPCmd PEPostpone list} postponed]} { + error [list _action Resume $postponed "Click Back button to try again."] + } + + set charset [lindex $postponed 1] + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=\"$charset\"" + } + + cgi_html { + cgi_head { + cgi_http_equiv Content-Type "text/html; charset=$charset" + WPStdHtmlHdr "Postponed Messages" + WPStyleSheets + cgi_puts "<style type='text/css'>" + cgi_puts ".gradient { background-image: url('[WPimg indexhdr]') ; background-repeat: repeat-x }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context resume} + + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + cgi_table_row { + # next comes the menu down the left side + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu resume_cmds {} + } + } + + cgi_table_data width=100% valign=top class=dialog { + + cgi_table border=0 cellspacing=0 cellpadding=0 width=100% { + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post target=_top { + cgi_text "page=compose" type=hidden notab + cgi_text "style=Postponed" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "oncancel=$oncancel" type=hidden notab + + + set n 1 + set fmt {{to Recipient} {date Date} {subj Subject}} + cgi_table_row class=\"gradient\" { + cgi_table_data class=indexhdr height=$_wp(indexheight) { + cgi_puts [cgi_nbspace] + } + + foreach i $fmt { + cgi_table_data class=indexhdr { + cgi_puts [lindex $i 1] + } + } + } + + set checked "" + set last [llength [lindex $postponed 0]] + for {set i 0} {$i < $last} {incr i} { + + # cgi_html_comment [lindex [lindex $postponed 0] $i] + array set pa [join [lindex [lindex $postponed 0] $i]] + + if {[info exists pa(uid)] == 0} { + continue; + } + + if {$i % 2} { + set bgcolor #EEEEEE + } else { + set bgcolor #FFFFFF + } + + if {[expr $i + 1] == $last} { + set checked checked + } + + cgi_table_row bgcolor=$bgcolor { + cgi_table_data valign=top nowrap bgcolor=$bgcolor { + cgi_radio_button "uid=$pa(uid)" style="background-color:$bgcolor" $checked + } + + foreach j $fmt { + cgi_table_data bgcolor=$bgcolor { + if {[info exists pa([lindex $j 0])]} { + cgi_puts $pa([lindex $j 0]) + } else { + cgi_puts [cgi_nbspace] + } + } + } + } + + set checked "" + } + + cgi_table_row { + cgi_table_data align=center colspan=24 { + cgi_br + cgi_submit_button "resume=Resume Chosen Message" + } + } + } + + cgi_table_row { + cgi_table_data align=center colspan=24 { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=_top { + cgi_text "page=$oncancel" type=hidden notab + cgi_br + cgi_submit_button "cancel=Cancel" + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/ripcord.tcl b/web/cgi/alpine/1.0/ripcord.tcl new file mode 100755 index 00000000..3514d20e --- /dev/null +++ b/web/cgi/alpine/1.0/ripcord.tcl @@ -0,0 +1,64 @@ +#!./tclsh +# $Id: ripcord.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# ripcord.tcl +# +# Purpose: CGI script to generate html page used to arm +# short server timeout + +# Input: +set rip_vars { + {t "" 10} + {cid "Command ID"} +} + +# Output: +# +# HTML/CSS data representing the form + +# inherit global config +source ./alpine.tcl + +WPEval $rip_vars { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Adjusting Session Timeout" + } + + cgi_body BGCOLOR=#ffffff { + if {[string compare $cid [WPCmd PEInfo key]]} { + cgi_put "Messing around, heh?" + } else { + cgi_put "Making Web Alpine Server Adjustments." + cgi_br + cgi_put "This should only take a momment..." + if {[catch {WPCmd PESession abandon 10}] == 0} { + set gonow 1 + } + } + + cgi_script type="text/javascript" language="JavaScript" { + if {[info exists gonow]} { + cgi_puts "window.close();" + } else { + cgi_puts "window.setInterval('window.close()',5000);" + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/seldate.tcl b/web/cgi/alpine/1.0/seldate.tcl new file mode 100755 index 00000000..e8e07c6f --- /dev/null +++ b/web/cgi/alpine/1.0/seldate.tcl @@ -0,0 +1,193 @@ +#!./tclsh +# $Id: seldate.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# seldate.tcl +# +# Purpose: CGI script to generate html form used to gather info +# for date selection + +# Input: +set select_vars { + {uid "" 0} +} + +# Output: +# +# HTML/CSS data representing form for date select input + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $select_vars { + + if {$uid} { + if {[catch {WPCmd PEMessage $uid number} thisnum]} { + set uid 0 + } + } else { + set thisnum "" + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Search By Date" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set wp_index_script fr_seldate.tcl} + catch {WPCmd PEInfo set help_context seldate} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text page=index type=hidden notab + cgi_text doselect=1 type=hidden notab + cgi_text by=date type=hidden notab + if {![WPCmd PEMailbox selected]} { + cgi_text result=broad type=hidden notab + } + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data align=center valign=top class=dialog { + cgi_table width="80%" { + cgi_table_row { + cgi_table_data { + cgi_center { + cgi_puts "[cgi_nl]This page provides a way to search for messages in [cgi_bold [WPCmd PEMailbox mailboxname]] based on arrival time." + cgi_puts "[cgi_nl][cgi_nl]Messages arriving [cgi_italic On] the date entered below will be marked with a check in the box next to their line in the Message List. Choosing [cgi_italic Since] marks messages arriving between today and the giving date (including the given date). Choosing [cgi_italic Before] marks messages arriving before (but not on) the given date." + cgi_puts "[cgi_nl][cgi_nl]Choose a date below and click 'Search' to choose messages, or 'Cancel' to return to the Message List.[cgi_nl][cgi_nl]" + } + } + } + + if {[WPCmd PEMailbox selected]} { + cgi_table_row class=dialog { + cgi_table_data colspan=2 align=center valign=middle class=dialog { + cgi_put [cgi_font face=tahoma,verdana,geneva "Since some messages are already marked, choose whether criteria specified here should "] + cgi_select result { + cgi_option "search all messages in '[WPCmd PEMailbox mailboxname]'" value=broad selected + cgi_option "search within marked messages only." value=narrow + cgi_option "discard previous marks and search anew." value=new + } + + cgi_br + cgi_br + cgi_br + } + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center class=dialog { + cgi_put [cgi_font face=tahoma,verdana,geneva "Messages dated "] + + cgi_select datecase { + foreach i {On Since Before} { + cgi_option $i value=[string tolower $i] + } + } + + cgi_br + cgi_br + + cgi_select datemon { + if {$uid} { + set today [string tolower [WPCmd PEMessage $uid date month]] + } else { + set today [string tolower [clock format [clock seconds] -format %b]] + } + + set months { + January jan + February feb + March mar + April Apr + May may + June jun + July jul + August aug + September sep + October oct + November nov + December dec + } + + foreach {x y} $months { + if {$y == $today} { + cgi_option $x value=$y selected + } else { + cgi_option $x value=$y + } + } + } + + cgi_select dateday { + if {$uid} { + set today [WPCmd PEMessage $uid date day] + } else { + set today [clock format [clock seconds] -format %d] + } + + for {set i 1} {$i <= 31} {incr i} { + set v [format "%.2d" $i] + if {$v == $today} { + cgi_option $i value=$v selected + } else { + cgi_option $i value=$v + } + } + } + + cgi_put ",[cgi_nbspace]" + cgi_select dateyear { + if {$uid} { + set now [WPCmd PEMessage $uid date year] + } else { + set now [clock format [clock seconds] -format "%Y"] + } + + cgi_option $now value=$now selected + for {set n [expr $now - 1]} {$n >= 1970} {incr n -1} { + cgi_option $n value=$n + } + } + } + } + + cgi_table_row { + cgi_table_data align=center { + cgi_br + cgi_submit_button ok=Search + cgi_submit_button cancel=Cancel + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center class=dialog { + cgi_puts [cgi_nl][cgi_nl][cgi_font size=-1 "Note, if the number of messages in this folder is larger than the number of lines in the Message List, then some matching messages may not be visible without paging/scrolling."] + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/select.tcl b/web/cgi/alpine/1.0/select.tcl new file mode 100755 index 00000000..915254c7 --- /dev/null +++ b/web/cgi/alpine/1.0/select.tcl @@ -0,0 +1,303 @@ +#!./tclsh +# $Id: select.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# select.tcl +# +# Purpose: CGI script to generate html form used to gather info +# for message searching selection + +# Input: +set select_vars { +} + +# Output: +# +# HTML/CSS data representing form for text select input + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $select_vars { + set selcount [WPCmd PEMailbox selected] + + # given a uid, called from View page so use it for defaults + # otherwise if only one selected, use it for defaults + set thisuid 0 + # leave disabled for now + if {0 && $uid > 0} { + set thisuid $uid + } elseif {$selcount == 1} { + } + + if {$thisuid} { + if {[catch {WPCmd PEMessage $thisuid number} thisnum]} { + set thisuid 0 + } + } else { + set thisnum "" + } + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Select By Text" + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".standout { width: 90%; text-align: center; font-size: smaller; border: 1px solid #663333; background-color: #ffcc66; padding-bottom: 8; margin-top: 8; margin-bottom: 12 }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" class=dialog "style=\"padding-left: 8%; padding-right: 8%\"" { + + #catch {WPCmd PEInfo set wp_index_script fr_select.tcl} + catch {WPCmd PEInfo set help_context select} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text "page=index" type=hidden notab + cgi_text "doselect=1" type=hidden notab + set mailboxname [WPCmd PEMailbox mailboxname] + cgi_division align=center class=dialog "style=\"padding-top:6; padding-bottom:8\"" { + cgi_puts "This page provides a way to search for specific messages within the currently open folder, [cgi_bold $mailboxname]. Simply fill in the criteria below and click the associated [cgi_italic Search] button. All messages matching the criteria will be marked with a check in the box next to their line in the Message List.[cgi_nl][cgi_nl]" + cgi_puts "Click [cgi_italic Cancel] to return to the Message List without searching." + } + + if {$selcount > 0} { + cgi_center { + cgi_division class=standout { + cgi_put "The folder '$mailboxname' has ${selcount} message" + if {[string length [WPplural $selcount]]} { + cgi_put "s with their checkboxes marked." + } else { + cgi_put " with its checkbox marked." + } + + cgi_put "[cgi_nl]The Search specified below should" + + cgi_select result { + cgi_option "apply to entire folder, adding result to those now marked" value=broad selected + cgi_option "apply only to marked messages, unmarking messages not matched" value=narrow + cgi_option "discard previous marks and search anew" value=new + } + } + } + } else { + cgi_text result=broad type=hidden notab + } + + cgi_put "<fieldset>" + cgi_put "<legend>[cgi_bold "Search for Text in Message Headers or Body"]</legend>" + cgi_center { + cgi_put [cgi_font class=dialog "Select messages with text "] + cgi_select textcase { + cgi_option "in" value=ton + cgi_option "NOT in" value=not + } + + cgi_br + cgi_br + + cgi_put [cgi_font face=tahoma,verdana,geneva "the message's "] + if {$thisuid} { + set fromaddr [WPCmd PEMessage $thisuid fromaddr] + set deftext $fromaddr + } else { + if {[catch {WPCmd PEInfo set wp_def_search_text} deftext]} { + set deftext "" + } + } + + set fields { + {Subject: field} subj "" + {From: field} from selected + {To: field} to "" + {Cc: field} cc "" + {recipient fields} recip "" + {participant fields} partic "" + {text, anywhere} any "" + } + + cgi_select field { + foreach {x y z} $fields { + cgi_option $x value=$y $z + } + } + + cgi_br + cgi_br + cgi_put [cgi_font face=tahoma,verdana,geneva "matching "] + cgi_text text=$deftext size=20 maxlength=256 + + if {$thisuid} { + set ft [WPJSQuote $fromaddr] + set tt [WPJSQuote [WPCmd PEMessage $thisuid toaddr]] + set st [WPJSQuote [WPCmd PEMessage $thisuid subject]] + if {[string length $ft] || [string length $tt] || [string length $st]} { + cgi_put "[cgi_nl]Using " + cgi_select defs { + cgi_option "- Nothing -" "" + if {[string length $ft]} { + cgi_option "From Address" value=$ft selected + } + if {[string length $tt]} { + cgi_option "To Address" value=$tt + } + if {[string length $st]} { + cgi_option "Subject Text" value=$st + } + } + cgi_put " of message ${thisnum}" + } + } + + cgi_br + cgi_br + cgi_submit_button "selectop=Search Text" + cgi_submit_button cancel=Cancel + } + cgi_put "</fieldset>" + + cgi_put "<fieldset>" + cgi_put "<legend>[cgi_bold "Search for Messages by Date"]</legend>" + cgi_center { + cgi_put "Messages dated " + + cgi_select datecase { + foreach i {On Since Before} { + cgi_option $i value=[string tolower $i] + } + } + + cgi_br + cgi_br + + cgi_select datemon { + if {$thisuid} { + set today [string tolower [WPCmd PEMessage $thisuid date month]] + } else { + set today [string tolower [clock format [clock seconds] -format %b]] + } + + set months { + January jan + February feb + March mar + April Apr + May may + June jun + July jul + August aug + September sep + October oct + November nov + December dec + } + + foreach {x y} $months { + if {$y == $today} { + cgi_option $x value=$y selected + } else { + cgi_option $x value=$y + } + } + } + + cgi_select dateday { + if {$thisuid} { + set today [WPCmd PEMessage $thisuid date day] + } else { + set today [clock format [clock seconds] -format %d] + } + + for {set i 1} {$i <= 31} {incr i} { + set v [format "%.2d" $i] + if {$v == $today} { + cgi_option $i value=$v selected + } else { + cgi_option $i value=$v + } + } + } + + cgi_put ",[cgi_nbspace]" + cgi_select dateyear { + if {$thisuid} { + set now [WPCmd PEMessage $thisuid date year] + } else { + set now [clock format [clock seconds] -format "%Y"] + } + + cgi_option $now value=$now selected + for {set n [expr $now - 1]} {$n >= 1970} {incr n -1} { + cgi_option $n value=$n + } + } + + cgi_br + cgi_br + cgi_submit_button "selectop=Search Date" + cgi_submit_button cancel=Cancel + } + cgi_put "</fieldset>" + + cgi_put "<fieldset>" + cgi_put "<legend>[cgi_bold "Search for Messages with Certain Status Settings"]</legend>" + cgi_center { + cgi_puts [cgi_font face=tahoma,verdana,geneva "Messages "] + cgi_select statcase { + cgi_option "flagged" value=ton + cgi_option "NOT flagged" value=not + } + + cgi_puts "[cgi_font face=tahoma,verdana,geneva " :"][cgi_nl][cgi_nl]" + + cgi_table border=0 cellpadding=2 cellspacing=0 { + set statuses { + Important imp + New new + Answered ans + Deleted del + } + + foreach {x y} $statuses { + cgi_table_row { + cgi_table_data align=right width="42%" { + cgi_radio_button flag=$y + } + + cgi_table_data align=left { + cgi_put $x + } + } + } + } + + cgi_br + cgi_submit_button "selectop=Search Status" + cgi_submit_button cancel=Cancel + } + cgi_put "</fieldset>" + + cgi_center { + cgi_division class=standout { + cgi_puts "Note, if the number of messages in this folder is larger than the number of lines in the Message[cgi_nbspace]List, then some matching messages may not be visible without paging/scrolling." + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/select2.tcl b/web/cgi/alpine/1.0/select2.tcl new file mode 100755 index 00000000..745254e7 --- /dev/null +++ b/web/cgi/alpine/1.0/select2.tcl @@ -0,0 +1,318 @@ +#!./tclsh +# $Id: select2.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# select.tcl +# +# Purpose: CGI script to generate html form used to gather info +# for message searching selection + +# Input: +set select_vars { +} + +# Output: +# +# HTML/CSS data representing form for text select input + +# coerce uid to zero since there's not method in WPL yet to initiate +# a search from a particular message. +set uid 0 + + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $select_vars { + if {$uid} { + if {[catch {WPCmd PEMessage $uid number} thisnum]} { + set uid 0 + } + } else { + set thisnum "" + } + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Select By Text" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set wp_index_script fr_select.tcl} + catch {WPCmd PEInfo set help_context select} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text "page=index" type=hidden notab + cgi_text "doselect=1" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data align=center valign=top class=dialog { + cgi_table width="80%" { + cgi_table_row { + cgi_table_data { + cgi_center { + cgi_puts "[cgi_nl][cgi_nl]This page provides a way to search for specific messsages within the currently open folder, [cgi_bold [WPCmd PEMailbox mailboxname]]. Simply fill in the criteria below and click the assoicated [cgi_italic Search] button. All messages matching the criteria will be marked with a check in the box next to their line in the Message List.[cgi_nl][cgi_nl]" + cgi_puts "Click [cgi_italic Cancel] to return to the Message List without searching.[cgi_nl]" + } + } + } + + if {[WPCmd PEMailbox selected]} { + cgi_table_row class=dialog { + cgi_table_data colspan=2 align=center valign=middle class=dialog { + cgi_put [cgi_font face=tahoma,verdana,geneva "Since some messages are already marked, choose whether criteria specified here should "] + cgi_select result { + cgi_option "search all messages in '[WPCmd PEMailbox mailboxname]'" value=broad selected + cgi_option "search within marked messages only." value=narrow + cgi_option "discard previous marks and search anew." value=new + } + + cgi_br + cgi_br + } + } + } else { + cgi_text result=broad type=hidden notab + } + + cgi_table_row class=dialog { + cgi_table_data { + cgi_table width=100% border=2 cellpadding=8 { + cgi_table_row { + cgi_table_data bgcolor=#CC9900 { + cgi_radio_button by=text + } + + cgi_table_data valign=top align=center nowrap class=dialog { + cgi_put [cgi_bold "Search for Text in Message Headers or Body"] + cgi_br + cgi_br + cgi_put "Select messages with text " + cgi_select textcase { + cgi_option "in" value=ton + cgi_option "NOT in" value=not + } + + cgi_br + cgi_br + + cgi_put [cgi_font face=tahoma,verdana,geneva "the message's "] + if {$uid} { + set fromaddr [WPCmd PEMessage $uid fromaddr] + set deftext $fromaddr + } else { + set deftext "" + } + + set fields { + {Subject: field} subj "" + {From: field} from selected + {To: field} to "" + {Cc: field} cc "" + {recipient fields} recip "" + {participant fields} partic "" + {text, anywhere} any "" + } + + cgi_select field { + foreach {x y z} $fields { + cgi_option $x value=$y $z + } + } + + cgi_br + cgi_br + cgi_put [cgi_font face=tahoma,verdana,geneva "matching "] + cgi_text text=$deftext size=20 maxlength=256 + + if {$uid} { + set ft [WPJSQuote $fromaddr] + set tt [WPJSQuote [WPCmd PEMessage $uid toaddr]] + set st [WPJSQuote [WPCmd PEMessage $uid subject]] + if {[string length $ft] || [string length $tt] || [string length $st]} { + cgi_put "[cgi_nl]Using " + cgi_select defs { + cgi_option "- Nothing -" "" + if {[string length $ft]} { + cgi_option "From Address" value=$ft selected + } + if {[string length $tt]} { + cgi_option "To Address" value=$tt + } + if {[string length $st]} { + cgi_option "Subject Text" value=$st + } + } + cgi_put " of message ${thisnum}" + } + } + } + } + + cgi_table_row class=dialog { + cgi_table_data bgcolor=#CC9900 { + cgi_radio_button by=date + } + + cgi_table_data valign=top align=center class=dialog { + cgi_put [cgi_bold "Search for Messages by Date"] + cgi_br + cgi_br + cgi_put "Messages dated " + + cgi_select datecase { + foreach i {On Since Before} { + cgi_option $i value=[string tolower $i] + } + } + + cgi_br + cgi_br + + cgi_select datemon { + if {$uid} { + set today [string tolower [WPCmd PEMessage $uid date month]] + } else { + set today [string tolower [clock format [clock seconds] -format %b]] + } + + set months { + January jan + February feb + March mar + April Apr + May may + June jun + July jul + August aug + September sep + October oct + November nov + December dec + } + + foreach {x y} $months { + if {$y == $today} { + cgi_option $x value=$y selected + } else { + cgi_option $x value=$y + } + } + } + + cgi_select dateday { + if {$uid} { + set today [WPCmd PEMessage $uid date day] + } else { + set today [clock format [clock seconds] -format %d] + } + + for {set i 1} {$i <= 31} {incr i} { + set v [format "%.2d" $i] + if {$v == $today} { + cgi_option $i value=$v selected + } else { + cgi_option $i value=$v + } + } + } + + cgi_put ",[cgi_nbspace]" + cgi_select dateyear { + if {$uid} { + set now [WPCmd PEMessage $uid date year] + } else { + set now [clock format [clock seconds] -format "%Y"] + } + + cgi_option $now value=$now selected + for {set n [expr $now - 1]} {$n >= 1970} {incr n -1} { + cgi_option $n value=$n + } + } + } + } + + cgi_table_row class=dialog { + cgi_table_data bgcolor=#CC9900 { + cgi_radio_button by=status + } + + cgi_table_data class=dialog align=center { + cgi_put [cgi_bold "Search for Messages with Certain Flag Settings"] + cgi_br + cgi_br + cgi_puts [cgi_font face=tahoma,verdana,geneva "Messages "] + cgi_select statcase { + cgi_option "flagged" value=ton + cgi_option "NOT flagged" value=not + } + + cgi_puts [cgi_font face=tahoma,verdana,geneva " :"] + + cgi_table { + set statuses { + Important imp + New new + Answered ans + Deleted del + } + + foreach {x y} $statuses { + cgi_table_row { + cgi_table_data align=right width="42%" { + cgi_radio_button flag=$y + } + + cgi_table_data align=left { + cgi_put $x + } + } + } + } + } + } + } + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center nowrap class=dialog { + cgi_br + cgi_submit_button ok=Search + cgi_submit_button cancel=Cancel + } + } + + cgi_table_row class=dialog { + cgi_table_data colspan=2 valign=top align=center class=dialog { + cgi_br + cgi_br + cgi_puts [cgi_nl][cgi_nl][cgi_font size=-1 "Note, if the number of messages in this folder is larger than the number of lines in the Message List, then some matching messages may not be visible without paging/scrolling."] + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/selstat.tcl b/web/cgi/alpine/1.0/selstat.tcl new file mode 100755 index 00000000..0af0be61 --- /dev/null +++ b/web/cgi/alpine/1.0/selstat.tcl @@ -0,0 +1,156 @@ +#!./tclsh +# $Id: selstat.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# selstat.tcl +# +# Purpose: CGI script to generate html form used to gather info +# for status selection + +# Input: +set select_vars { + {uid "" 0} +} + +# Output: +# +# HTML/CSS data representing form for status select input + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $select_vars { + if {$uid} { + if {[catch {WPCmd PEMessage $uid number} thisnum]} { + set uid 0 + } + } else { + set thisnum "" + } + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Search By Status" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set help_context selstat} + catch {WPCmd PEInfo set wp_index_script fr_selstat.tcl} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text page=index type=hidden notab + cgi_text doselect=1 type=hidden notab + cgi_text by=status type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data align=center valign=top class=dialog { + cgi_table width="80%" { + cgi_table_row { + cgi_table_data colspan=2 { + cgi_center { + cgi_puts "[cgi_nl][cgi_nl]This page provides a way to search for messages in [cgi_bold [WPCmd PEMailbox mailboxname]] based on their status flags. Messages matching the status selected below will be marked with a check in the box next to their line in the Message List." + cgi_puts "[cgi_nl][cgi_nl]Choose the status criteria below and click 'Search', or 'Cancel' to return to the Message List.[cgi_nl][cgi_nl]" + } + } + + if {[WPCmd PEMailbox selected]} { + cgi_table_row class=dialog { + cgi_table_data colspan=2 align=center valign=middle class=dialog colspan=2 { + cgi_put [cgi_font face=tahoma,verdana,geneva "Since some messages are already marked, choose whether criteria specified here should "] + cgi_select result { + cgi_option "search all messages in '[WPCmd PEMailbox mailboxname]'" value=broad selected + cgi_option "search within marked messages only." value=narrow + cgi_option "discard previous marks and search anew." value=new + } + + cgi_br + cgi_br + } + } + } else { + cgi_text result=broad type=hidden notab + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center nowrap class=dialog colspan=2 { + cgi_puts [cgi_font face=tahoma,verdana,geneva "Search for messages "] + cgi_select statcase { + cgi_option "flagged" value=ton + cgi_option "NOT flagged" value=not + } + + cgi_puts [cgi_font face=tahoma,verdana,geneva " :"] + } + } + + set statuses { + Important imp + New new + Answered ans + Deleted del + } + + if {0} { + cgi_table_row { + cgi_table_data align=center colspan=2 { + cgi_select flag { + foreach {x y} $statuses { + cgi_option $x value=$y + } + } + } + } + } else { + foreach {x y} $statuses { + cgi_table_row { + cgi_table_data align=right width="42%" { + cgi_radio_button flag=$y + } + + cgi_table_data align=left { + cgi_put $x + } + } + } + } + + cgi_table_row { + cgi_table_data class=dialog align=center colspan=2 { + cgi_br + cgi_submit_button ok=Search + cgi_submit_button cancel=Cancel + } + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center class=dialog colspan=2 { + cgi_puts [cgi_nl][cgi_nl][cgi_font size=-1 "Note, if the number of messages in this folder is larger than the number of lines in the Message List, then some matching messages may not be visible without paging/scrolling."] + } + } + } + } + } + } + } + } + } +} + diff --git a/web/cgi/alpine/1.0/seltext.tcl b/web/cgi/alpine/1.0/seltext.tcl new file mode 100755 index 00000000..e0ce33bb --- /dev/null +++ b/web/cgi/alpine/1.0/seltext.tcl @@ -0,0 +1,181 @@ +#!./tclsh +# $Id: seltext.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# seltext.tcl +# +# Purpose: CGI script to generate html form used to gather info +# for text selection + +# Input: +set select_vars { +} + +# Output: +# +# HTML/CSS data representing form for text select input + +# coerce uid to zero since there's not method in WPL yet to initiate +# a search from a particular message. +set uid 0 + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +WPEval $select_vars { + if {$uid} { + if {[catch {WPCmd PEMessage $uid number} thisnum]} { + set uid 0 + } + } else { + set thisnum "" + } + + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Search for Text" + WPStyleSheets + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + + catch {WPCmd PEInfo set wp_index_script fr_seltext.tcl} + catch {WPCmd PEInfo set help_context seltext} + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get name=auth target=body { + cgi_text "page=index" type=hidden notab + cgi_text "doselect=1" type=hidden notab + cgi_text "by=text" type=hidden notab + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + cgi_table_data align=center valign=top class=dialog { + cgi_table width="80%" { + cgi_table_row { + cgi_table_data { + cgi_center { + cgi_puts "[cgi_nl][cgi_nl]This page provides a way to search for specific text in the messsages contained in [cgi_bold [WPCmd PEMailbox mailboxname]]. Enter your selection criteria below, and click [cgi_italic Search]. All messages matching the criteria will be marked with a check in the box next to their line in the Message List." + cgi_br + cgi_br + cgi_puts "Click [cgi_italic Cancel] to return to the Message List without searching.[cgi_nl][cgi_nl]" + } + } + } + + + if {[WPCmd PEMailbox selected]} { + cgi_table_row class=dialog { + cgi_table_data colspan=2 align=center valign=middle class=dialog { + cgi_put [cgi_font face=tahoma,verdana,geneva "Since some messages are already marked, choose whether criteria specified here should "] + cgi_select result { + cgi_option "search all messages in '[WPCmd PEMailbox mailboxname]'" value=broad selected + cgi_option "search within marked messages only." value=narrow + cgi_option "discard previous marks and search anew." value=new + } + + cgi_br + cgi_br + } + } + } else { + cgi_text result=broad type=hidden notab + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center nowrap class=dialog { + cgi_put [cgi_font face=tahoma,verdana,geneva "Search for messages with text "] + cgi_select textcase { + cgi_option "in" value=ton + cgi_option "NOT in" value=not + } + + cgi_br + cgi_br + + cgi_put [cgi_font face=tahoma,verdana,geneva "the message's "] + if {$uid} { + set fromaddr [WPCmd PEMessage $uid fromaddr] + set deftext $fromaddr + } else { + set deftext "" + } + + set fields { + {Subject: field} subj "" + {From: field} from selected + {To: field} to "" + {Cc: field} cc "" + {recipient fields} recip "" + {participant fields} partic "" + {text, anywhere} any "" + } + + cgi_select field { + foreach {x y z} $fields { + cgi_option $x value=$y $z + } + } + + cgi_br + cgi_br + cgi_put [cgi_font face=tahoma,verdana,geneva "matching "] + cgi_text text=$deftext size=30 maxlength=256 + + if {$uid} { + set ft [WPJSQuote $fromaddr] + set tt [WPJSQuote [WPCmd PEMessage $uid toaddr]] + set st [WPJSQuote [WPCmd PEMessage $uid subject]] + if {[string length $ft] || [string length $tt] || [string length $st]} { + cgi_put "[cgi_nl]Using " + cgi_select defs { + cgi_option "- Nothing -" "" + if {[string length $ft]} { + cgi_option "From Address" value=$ft selected + } + if {[string length $tt]} { + cgi_option "To Address" value=$tt + } + if {[string length $st]} { + cgi_option "Subject Text" value=$st + } + } + cgi_put " of message ${thisnum}" + } + } + } + } + cgi_table_row class=dialog { + cgi_table_data valign=top align=center nowrap class=dialog { + cgi_br + cgi_submit_button ok=Search + cgi_submit_button cancel=Cancel + } + } + + cgi_table_row class=dialog { + cgi_table_data valign=top align=center class=dialog { + cgi_puts [cgi_nl][cgi_nl][cgi_font size=-1 "Note, if the number of messages in this folder is larger than the number of lines in the Message List, then some matching messages may not be visible without paging/scrolling."] + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/spellcheck.tcl b/web/cgi/alpine/1.0/spellcheck.tcl new file mode 100755 index 00000000..ac1f9fe5 --- /dev/null +++ b/web/cgi/alpine/1.0/spellcheck.tcl @@ -0,0 +1,399 @@ +#!./tclsh +# $Id: spellcheck.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# spellcheck.tcl +# +# Purpose: CGI script to generate html form used to check +# body text spelling in the webpine-lite composer + +# Input: +set query_vars { + {repqstr "" ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the page to correct spelling + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + + +set check_menu { + { + {expr 0} + { + { + # * * * * DONE * * * * + cgi_puts "<fieldset>" + + cgi_puts [cgi_font size=-1 "When finished, choose action below, then click [cgi_italic OK].[cgi_nl][cgi_nl]"] + cgi_radio_button spell=spell + cgi_puts "[cgi_nbspace][cgi_font color=white face=Helvetica size=-1 Correct][cgi_nl]" + cgi_radio_button spell=cancel + cgi_puts "[cgi_nbspace][cgi_font color=white face=Helvetica size=-1 Cancel][cgi_nl]" + cgi_br + #cgi_image_button action=[WPimg but_s_do] border=0 alt="Do" + cgi_division "style=padding-bottom:4" align=center { + cgi_submit_button "action=OK" class=navtext + } + cgi_puts "</fieldset>" + } + } + } + { + {} + { + { + # * * * * Done * * * * + cgi_submit_button "spell=Apply" class=navtext + } + } + } + { + {} + { + { + # * * * * Cancel * * * * + cgi_submit_button "spell=Cancel" class=navtext + } + } + } + { + {expr 0} + { + { + # * * * * Help * * * * + cgi_submit_button "help=Get Help" class=navtext + } + } + } +} + +set done 0 +set first 1 +set spellresult {} +set line {} + +proc spelled {pipe} { + global done spellresult line first + + if {[eof $pipe]} { + catch {close $pipe} + set done 1 + return + } + + gets $pipe w + + if {$first == 0} { + if {[string length $w]} { + lappend line $w + } else { + lappend spellresult $line + set line {} + } + } else { + set first 0 + } +} + + +WPEval $query_vars { + if {[catch {WPCmd PEInfo set suspended_composition} msgdata]} { + set problem "Can't read message text" + } else { + foreach p $msgdata { + if {[string compare [lindex $p 0] body] == 0} { + set body [lindex $p 1] + break + } + } + + if {![info exists body]} { + set problem "Can't find body in message text" + } else { + # spell check and gather results + # set tmpfile + for {set i 0} {$i < 5} {incr i} { + set tmpfile [file join $_wp(sockdir) "sc[pid][expr rand()]"] + if {[file exists $tmpfile] == 0} { + if {[catch {open $tmpfile w} ofp] == 0} { + break + } + } + unset tmpfile + } + + if {![info exists tmpfile]} { + set problem "Can't create temporary file" + } + } + } + + if {![info exists problem]} { + if {[string length $repqstr]} { + set quoter $repqstr + } else { + set quoter "> " + } + + foreach l $body { + if {[string compare $l "---------- Forwarded message ----------"] == 0} { + break; + } elseif {[regexp "^$quoter" $l]} { + puts $ofp "" + } else { +# regsub -all {\$} $l {\$} l + puts $ofp "^${l}" + } + } + + close $ofp + + set cmd [list $_wp(ispell) "-a"] + set pipe [open "|$cmd < $tmpfile 2> /dev/null" r] + + fileevent $pipe readable [list spelled $pipe] + + vwait done + + catch {file delete $tmpfile} + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Check Spelling" + WPStyleSheets + cgi_put "<style type='text/css'>" + cgi_put ".correction { font-family: geneva, arial, sans-serif ; font-size: 9pt }" + cgi_puts "</style>" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post enctype=multipart/form-data target=_top { + cgi_text "page=compose" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "restore=1" type=hidden notab + cgi_text "style=Spell" type=hidden notab + cgi_text "last_line=[llength $spellresult]" type=hidden notab + if {[string length $repqstr]} { + cgi_text "repqstr=$repqstr" type=hidden notab + } + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu check_menu {} + } + } + + cgi_table_data valign=top class=dialog { + + set badlines {} + array set badwords {} + set badcount 0 + for {set n 0} {$n < [llength $spellresult]} {incr n} { + set words {} + foreach ms [lindex $spellresult $n] { + if {[regexp {& ([a-zA-Z0-9]*) [0-9]+ ([0-9]+):[ ]?(.*)$} $ms match w o s]} { + incr badcount + if {[regsub -all {, } $s { } sugs] < 0} { + continue + } + + lappend words [list $w [expr {$o - 1}] $sugs] + if {[info exists badwords($w)]} { + incr badwords($w) + } else { + set badwords($w) 1 + } + } elseif {[regexp {# ([a-zA-Z0-9]*) ([0-9]+)$} $ms match w o]} { + incr badcount + lappend words [list $w [expr {$o - 1}] {}] + if {[info exists badwords($w)]} { + incr badwords($w) + } else { + set badwords($w) 1 + } + } + } + + if {[llength $words]} { + lappend badlines [list $n $words] + } + } + + if {[info exists problem] || $badcount <= 0} { + cgi_table align=center valign=top height="100%" { + cgi_table_row { + cgi_table_data align=center valign=bottom heigh="20%" { + if {[info exists problem]} { + cgi_puts "Problem detected: $problem" + } else { + cgi_puts "No misspelled words found." + } + } + } + cgi_table_row { + cgi_table_data align=center valign=top { + cgi_put "Click " + cgi_submit_button "cancel=Continue" class=navtext + cgi_put " to return to your composition." + } + } + } + } else { + cgi_table width="95%" border=0 align=center valign=top { + cgi_table_row { + cgi_table_data align=center "style=padding-top:10;padding-bottom:10" { + cgi_puts "Web Alpine found [cgi_bold $badcount] possibly misspelled word[WPplural $badcount]." + cgi_puts "Grouped by the line on which they were found, misspelled words can be corrected by either selecting from the list of suggestions, when available (note, first option always blank), or entering the corrected spelling directly." + cgi_puts "When finished click [cgi_italic Apply] to correct the text, or [cgi_italic Cancel] to return to the composition unchanged." + } + } + + foreach sl $badlines { + set lnum [lindex $sl 0] + set locs {} + + cgi_table_row { + cgi_table_data bgcolor=white align=left height=20 class=view "style=font-family:courier;padding:8" { + set ol [lindex $body $lnum] + set l "" + set o 0 + foreach w [lindex $sl 1] { + set offset [lindex $w 1] + set word [lindex $w 0] + set wordlen [string length $word] + append l "[cgi_quote_html [string range $ol $o [expr {$offset - 1}]]][cgi_url $word "#${lnum}_[lindex $w 1]_${wordlen}" class=mispell]" + set o [expr {$offset + $wordlen}] + } + + append l [string range $ol $o end] + + cgi_put $l + } + } + + cgi_table_row { + cgi_table_data { + cgi_table width=90% align=center border=0 { + + foreach w [lindex $sl 1] { + set word [lindex $w 0] + set wordlen [string length $word] + set wordloc "${lnum}_[lindex $w 1]_${wordlen}" + + cgi_table_row { + + if {[llength [lindex $w 2]] > 0} { + cgi_table_data align=left class=correction nowrap { + cgi_put "Replace [cgi_anchor_name $wordloc][cgi_bold $word] with " + } + + cgi_table_data align=left class=correction nowrap { + cgi_select s_${wordloc} class=correction { + cgi_option "" value= + foreach sug [lindex $w 2] { + cgi_option $sug value=$sug + } + } + } + + cgi_table_data align=left class=correction nowrap { + cgi_put " or change to " + } + } else { + cgi_table_data align=left class=correction nowrap { + cgi_put "Change [cgi_anchor_name $wordloc][cgi_bold $word] to " + } + } + + cgi_table_data align=left class=correction nowrap { + cgi_text r_${wordloc}= "size=[expr {$wordlen + 4}]" maxlength=64 class=correction + } + + cgi_table_data align=left class=correction width=90% colspan=3 { + + if {$badwords($word) > 1} { + if {![info exists badseen($word)]} { + switch $badwords($word) { + 2 { set badtimes both } + default { set badtimes "all $badwords($word)" } + } + + cgi_put " and " + cgi_checkbox a_${wordloc} + cgi_put " apply to $badtimes occurrences" + set badseencount($word) 1 + } else { + incr badseencount($word) + switch $badseencount($word) { + 2 { set bad1 "second " ; set bad2 "" } + 3 { set bad1 "third " ; set bad2 "" } + 4 { set bad1 "fourth " ; set bad2 "" } + 5 { set bad1 "fifth " ; set bad2 "" } + 6 { set bad1 "sixth " ; set bad2 "" } + default { set bad1 "" ; set bad2 " $badseencount($word)" } + } + cgi_put "(${bad1}occurrence${bad2})" + } + + lappend badseen($word) $wordloc + } else { + cgi_put [cgi_img [WPimg dot2]] + } + } + + lappend locs $wordloc + } + } + + cgi_table_row { + cgi_table_data height=8 { + cgi_text "l_$lnum=[join $locs {,}]" type=hidden notab + } + } + } + } + } + } + + cgi_table_row { + cgi_table_data align=center height=50 { + foreach l [array names badseen] { + set m $badseen($l) + cgi_text "e_[lindex $m 0]=[join [lrange $m 1 end] {,}]" type=hidden notab + } + + cgi_submit_button "spell=Apply" class=navtext + cgi_submit_button "spell=Cancel" class=navtext + } + } + } + } + } + } + } + } + } + } +} + diff --git a/web/cgi/alpine/1.0/takeaddr.tcl b/web/cgi/alpine/1.0/takeaddr.tcl new file mode 100755 index 00000000..328febb6 --- /dev/null +++ b/web/cgi/alpine/1.0/takeaddr.tcl @@ -0,0 +1,215 @@ +#!./tclsh +# $Id: takeaddr.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# takeaddr.tcl +# +# Purpose: CGI script to take addresses to address book + +# Input: +set takeaddr_vars { + {uid "Missing UID"} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +# Command Menu definition for Message View Screen +set take_menu { +} + +set common_menu { + { + {} + { + { + cgi_put [cgi_url "Get Help" wp.tcl?page=help&topic=take&index=none&oncancel=view%2526op%253DTake class=navbar target=_top] + } + } + } +} + +WPEval $takeaddr_vars { + + if {[catch {WPCmd PEInfo noop} result]} { + error [list _action "No Op" $result "Please close this window."] + } + + if {$uid > 0 && [catch {WPCmd PEMessage $uid takeaddr} tainfo]} { + error [list _action "takeaddr $uid" $tainfo "Click Browsers Back Button."] + } + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Take Address" + WPStyleSheets + } + + cgi_body bgcolor=$_wp(bordercolor) { + cgi_table border=0 cellspacing=0 cellpadding=0 height="100%" { + cgi_table_row { + cgi_table_data valign=top class=navbar width=112 { + cgi_table bgcolor=$_wp(menucolor) border=0 "style=\"padding-left: 2\"" { + # next comes the menu down the left side, with suitable + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) class=navbar { + WPTFCommandMenu take_menu common_menu + } + } + } + } + } + + cgi_table_data valign=top class=navbar { + cgi_table border=0 cellspacing=0 cellpadding=2 align=center valign=top height="100%" { + cgi_table_row { + cgi_table_data valign=top class=dialog { + cgi_table align=center border=0 width=75% height=80 class=dialog { + cgi_table_row { + cgi_table_data class=dialog align=center valign=middle { + set txt "Select the address that you would like to take to your address book" + if {[llength $tainfo] > 1} { + set txt "$txt, or select multiple addresses to create a list." + } else { + set txt "$txt." + } + append txt "When finished, click [cgi_italic "Take Address"] to create an entry" + append txt " or [cgi_italic "Cancel"] to return, creating nothing." + #cgi_puts [cgi_bold $txt ] + cgi_puts $txt + } + } + } + } + } + + cgi_table_row { + cgi_table_data valign=top height=99% class=dialog { + + set books [WPCmd PEAddress books] + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post target=_top name=takeaddr { + cgi_text page=view type=hidden notab + cgi_text uid=$uid type=hidden notab + cgi_text cid=[WPCmd PEInfo key] type=hidden notab + if {[llength $books] <= 1} { + cgi_text "book=0" type=hidden notab + } + + cgi_table border=0 cellspacing=0 cellpadding=2 align=center valign=top width="70%" height="100%" { + if {[llength $books] > 1} { + cgi_table_row { + cgi_table_data colspan=2 valign=top align=center class=dialog { + cgi_table border=0 cellspacing=0 cellpadding=0 "style=padding-top:20;padding-bottom:20" { + cgi_table_row { + cgi_table_data align=right { + cgi_puts [cgi_bold "Take to address book"] + } + cgi_table_data align=right valign=top { + cgi_puts [cgi_bold "[cgi_nbspace]:[cgi_nbspace]"] + } + cgi_table_data align=left { + cgi_select book { + foreach book $books { + cgi_option [lindex $book 1] value=[lindex $book 0] + } + } + } + } + } + } + } + } + + set linenum 1 + foreach taline $tainfo { + set printstr [lindex $taline 0] + set addr [lindex $taline 1] + set sugs [lindex $taline 2] + if {[llength $addr] == 0 && [llength $sugs] == 0} { + cgi_table_row { + cgi_table_data align=center class=dialog colspan=2 "style=xpadding-left:8%;xpadding-right:8%;padding-top:20;padding-bottom:20" { + cgi_put $printstr + } + } + + continue + } + + if {[incr linenum] % 2} { + set bgcolor #EEEEEE + } else { + set bgcolor #FFFFFF + } + + cgi_table_row bgcolor=$bgcolor { + cgi_table_data align=right { + cgi_checkbox "taList=tl${linenum}" style=background-color:$bgcolor + if {[llength $addr] > 0} { + if {[set tmp [lindex $addr 0]] != {}} { + cgi_text "tl${linenum}p=$tmp" type=hidden notab + } + if {[set tmp [lindex $addr 1]] != {}} { + cgi_text "tl${linenum}m=$tmp" type=hidden notab + } + if {[set tmp [lindex $addr 2]] != {}} { + cgi_text "tl${linenum}h=$tmp" type=hidden notab + } + } + if {[llength $sugs] > 0} { + if {[set tmp [lindex $sugs 0]] != {}} { + cgi_text "tl${linenum}n=$tmp" type=hidden notab + } + if {[set tmp [lindex $sugs 1]] != {}} { + cgi_text "tl${linenum}fn=$tmp" type=hidden notab + } + if {[set tmp [lindex $sugs 2]] != {}} { + cgi_text "tl${linenum}fcc=$tmp" type=hidden notab + } + if {[set tmp [lindex $sugs 3]] != {}} { + cgi_text "tl${linenum}c=$tmp" type=hidden notab + } + } + } + cgi_table_data align=left { + regsub -all "<" $printstr "\\<" printstr + regsub -all ">" $printstr "\\>" printstr + cgi_puts $printstr + } + } + } + + cgi_table_row { + cgi_table_data height="99%" colspan=2 valign=top align=center class=dialog "style=padding-top:16" { + cgi_submit_button "op=Take Address" + cgi_submit_button takecancel=Cancel + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/tclsh b/web/cgi/alpine/1.0/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/alpine/1.0/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/tconfig.tcl b/web/cgi/alpine/1.0/tconfig.tcl new file mode 100755 index 00000000..6274e849 --- /dev/null +++ b/web/cgi/alpine/1.0/tconfig.tcl @@ -0,0 +1,1183 @@ +# $Id: tconfig.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# tconfig.tcl +# +# Purpose: CGI script to configure features/variables + +# Input: +set conf_vars { + {newconf {} 0} + {oncancel "Nothing set for oncancel"} + {wv "" general} + {vlavar "" ""} +} + +# Output: +# + +# read config +source genvars.tcl + +set confs { + {general General g genconf} + {msgl "Message List" ml mlconf} + {msgv "Message View" mv mvconf} + {composer Composer c compconf} + {address "Address Books" ab abconf} + {folder "Folders" f fldrconf} + {rule "Rules" r ruleconf} +} + + +set var_menu { + { + {} + { + { + # * * * * Save Config * * * * + #cgi_image_button save=[WPimg but_save] border=0 alt="Save Config" + cgi_submit_button save=Save + } + } + } + { + {} + { + { + # * * * * Close * * * * + #cgi_image_button cancel=[WPimg but_cancel] border=0 alt="Cancel" + cgi_submit_button cancel=Cancel + } + } + } +} + +## read vars +foreach item $conf_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} result]} { + if {[llength $item] > 2} { + set [lindex $item 0] [lindex $item 2] + } else { + error [list _action [lindex $item 1] $result] + } + } + } else { + set [lindex $item 0] 1 + } +} + +set type $wv +WPCmd set conf_page $type +switch -- $type { + msgl { + set goodvars $msglist_vars + } + msgv { + set goodvars $msgview_vars + } + address { + set goodvars $address_vars + } + folder { + set goodvars $folder_vars + } + composer { + set goodvars $composer_vars + } + general { + set goodvars $general_vars + } + rule { + set goodvars $rule_vars + } +} +set typeexp "General" + +proc button_text {but butno fg bg text} { + if {[string length $fg]} { + set fg "color: #${fg};" + } + + if {[string length $bg]} { + set bg "background-color: #${bg}" + } + + cgi_puts "<script><!-- " + cgi_puts "document.write('<a href=\\\'#\\\' style=\\\"text-decoration: none;\\\" onClick=\"return setop(\\\'${but}\\\',$butno)\">');// -->" + cgi_puts "</script>" + + cgi_put [cgi_span "style=$fg $bg" $text] + + cgi_puts "<script><!-- " + cgi_puts "document.write('</a>');// -->" + cgi_puts "</script>" +} + +proc button_checked {def but} { + if {[string compare $def $but]} { + return "" + } else { + return checked + } +} + +foreach conf $confs { + if {[string compare $type [lindex $conf 0]] == 0} { + append ttitle [cgi_imglink "[lindex $conf 2]tab"] + lappend conftitle [list [cgi_imglink "[lindex $conf 2]tab"] {} {}] + set typeexp [lindex $conf 1] + set _wp(helpname) [lindex $conf 3] + } else { + append ttitle "<input type=image name=\"[lindex $conf 2]tab\" src=\"[WPimg "tabs/[lindex $conf 2]dtab"]\" border=0 alt=\"[lindex $conf 1]\">"; + } +} + +cgi_http_head { + WPStdHttpHdrs +} + +if {$newconf == 1} { + WPCmd PEConfig newconf +} + +cgi_html { + cgi_head { + WPStdHtmlHdr "Configuration" + WPStyleSheets + + cgi_put "<style type='text/css'>" + cgi_put ".vtext { font-size: 10pt; font-family: courier, 'new courier', monospace ; font-weight: medium ; padding-left: 6; border-left: 1px solid black}" + cgi_put ".instr { font-size: 10pt; font-weight: bold}" + cgi_puts "</style>" + + cgi_javascript { + cgi_put "function setop(b,i){" + cgi_put " eval('document.varconfig.'+b+'\['+i+'\].checked = true');" + cgi_put " return false;" + cgi_put "}" + } + } + + cgi_body BGCOLOR="$_wp(bordercolor)" { + set postjs "" + + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=post name=varconfig enctype=multipart/form-data target=_top { + cgi_text "oncancel=$oncancel" type=hidden notab + cgi_text "cid=[WPCmd PEInfo key]" type=hidden notab + cgi_text "page=conf_process" type=hidden notab + + cgi_table width="100%" cellpadding=0 cellspacing=0 { + cgi_table_row { + cgi_table_data width=112 bgcolor=$_wp(menucolor) { + cgi_puts [cgi_img [WPimg dot2] width=1 height=1] + } + cgi_table_data align=right nowrap background="[WPimg [file join tabs tabbg]]" { + cgi_put $ttitle + } + } + } + if {0} { + cgi_division align=right { + cgi_put $ttitle + } + } + cgi_table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%" { + + cgi_table_row { + # + # next comes the menu down the left side + # + eval { + cgi_table_data $_wp(menuargs) rowspan=4 { + WPTFCommandMenu var_menu {} + } + } + + # + # In main body of screen goe confg list + # + cgi_table_data valign=top width="100%" class=dialog "style=\"padding-left: 6\"" { + cgi_h2 [cgi_bold "${typeexp} configuration settings:"] + switch -- $type { + msgl { + cgi_text "wv=msgl" type=hidden notab + } + msgv { + cgi_text "wv=msgv" type=hidden notab + } + address { + cgi_text "wv=address" type=hidden notab + } + folder { + cgi_text "wv=folder" type=hidden notab + } + composer { + cgi_text "wv=composer" type=hidden notab + } + general { + cgi_text "wv=general" type=hidden notab + } + rule { + cgi_text "wv=rule" type=hidden notab + } + } + set setfeatures [WPCmd PEConfig featuresettings] + set icnt 0 + cgi_table border=0 cellspacing=0 cellpadding=5 width=98% { + foreach tmpvar $goodvars { + set vtypeinp [lindex $tmpvar 0] + set varname [lindex $tmpvar 1] + set vardesc [lindex $tmpvar 2] + + if {[catch {WPCmd PEConfig varget $varname} section] == 0} { + set varvals [lindex $section 0] + set vartype [lindex $section 1] + set vtvals [lindex $section 2] + set v_is_default [lindex $section 3] + set v_is_fixed [lindex $section 4] + } else { + # UNKNOWN VAR: configure disabled? + continue + } + + switch -- $vtypeinp { + var { + cgi_table_row { + + cgi_table_data align=right valign=top nowrap width=50% { + if {[info exists varname]} { + # set script "help.tcl?vn=$varname" + # set js "cOpen('$script', 'help', 'scrollbars=yes', 600, 400); return false;" + # set js "return vh('$varname')" + # cgi_puts [WPurl null "" $varname "" onClick=$js] + # cgi_puts [WPurl null "" $vardesc "" onClick=$js] + # cgi_submit_button varhelp=$vardesc class=lnkbt + cgi_puts [cgi_font class=cfvn $vardesc] + } + } + cgi_table_data valign=top { + cgi_image_button "hlp.$varname=[WPimg cf_help]" alt="Help for $vardesc" + } + cgi_table_data align=left colspan=2 width=50% { + switch -- $vartype { + listbox { + cgi_select $varname align=left { + foreach tmpvt $vtvals { + set tmpvttxt [lindex $tmpvt 0] + set tmpvtval $tmpvttxt + if {[llength $tmpvt] > 1} { + set tmpvtval [lindex $tmpvt 1] + } + if {[string compare $tmpvtval [lindex $varvals 0]]} { + if {[llength $tmpvt] > 1} { + cgi_option "${tmpvttxt}" "value=${tmpvtval}" + } else { + cgi_option "${tmpvttxt}" "value=${tmpvttxt}" + } + } else { + if {[llength $tmpvt] > 1} { + cgi_option "$tmpvttxt" "value=${tmpvtval}" selected + } else { + cgi_option "$tmpvttxt" selected + } + } + } + } + } + textarea { + cgi_table border=0 cellpadding=0 cellspacing=0 { + set addfield 0 + set tiwidth 30 + foreach varval $varvals { + if {[string length $varval] > [expr {[info exists maxwidth] ? $maxwidth : 0}]} { + set maxwidth [string length $varval] + incr maxwidth 5 + } + } + if {[info exists maxwidth]} { + set tiwidth $maxwidth + } + if {$tiwidth < 20} { + set tiwidth 20 + } elseif {$tiwidth > 50} { + set tiwidth 50 + } + cgi_table_row { + cgi_table_data colspan=4 { + cgi_image_button vla.$varname=[WPimg cf_add] alt="Add Value" + } + } + if {[string compare $vlavar $varname] == 0} { + set addfield 1 + cgi_table_row { + cgi_table_data { + cgi_text "varlistadd=$varname" type=hidden notab + cgi_text "$varname-add=" type=text size=$tiwidth + } + cgi_table_data colspan=3 { + cgi_puts [cgi_font class=cfntc "(The value entered here will be added.)"] + } + } + } + set i 0 + set vvsz [llength $varvals] + foreach varval $varvals { + cgi_table_row { + cgi_table_data { + cgi_text vle.$varname.$i=$varval type=text size=$tiwidth + } + cgi_table_data { + cgi_image_button vld.$varname.$i=[WPimg cf_delete] alt="Delete Value" + } + cgi_table_data { + if {$i < [expr {$vvsz - 1}]} { + cgi_image_button vlsd.$varname.$i=[WPimg cf_shdown] alt="Shuffle Down" + } else { + cgi_puts [cgi_nbspace] + } + } + cgi_table_data width=50% { + if {$i || $addfield} { + cgi_image_button vlsu.$varname.$i=[WPimg cf_shup] alt="Shuffle Up" + } else { + cgi_puts [cgi_nbspace] + } + } + } + incr i + } + cgi_text "$varname-sz=$i" type=hidden notab + } + } + default { + set size [string length [lindex $varvals 0]] + if {$size == 0} { + set size 20 + } else { + incr size 5 + } + cgi_text "$varname=[lindex $varvals 0]" type=text size=$size tableindex=1 + } + } + } + } + } + feat { + cgi_table_row { + cgi_table_data align=right width=50% { + if {[info exists varname]} { + # cgi_submit_button feathelp=$vardesc class=lnkbt + cgi_puts [cgi_font class=cfvn $vardesc] + } + } + cgi_table_data { + cgi_image_button "hlp.$varname=[WPimg cf_help]" alt="Help for $vardesc" + } + cgi_table_data align=left colspan=3 width=50% { + if {[lsearch $setfeatures $varname] >= 0} { + cgi_checkbox $varname checked class=dialog + } else { + cgi_checkbox $varname class=dialog + } + } + } + + } + special { + switch -- $varname { + wp-columns { + cgi_table_row { + cgi_table_data align=right valign=top nowrap { + cgi_puts [cgi_font class=cfvn $vardesc] + } + cgi_table_data valign=top { + cgi_image_button "hlp.${varname}=[WPimg cf_help]" alt="Help for $vardesc" + } + cgi_table_data align=left colspan=2 { + set cols [WPCmd PEConfig columns] + cgi_select columns align=left { + for {set i 20} {$i <= 128} {incr i 4} { + if {$i == $cols} { + cgi_option $i "value=$i" selected + } else { + cgi_option $i "value=$i" + } + } + } + } + } + } + left-column-folders { + cgi_table_row { + cgi_table_data align=right valign=top nowrap { + cgi_puts [cgi_font class=cfvn $vardesc] + } + cgi_table_data valign=top { + cgi_puts [cgi_nbspace] + } + cgi_table_data align=left colspan=2 { + if {[catch {WPSessionState left_column_folders} cols]} { + set cols $_wp(fldr_cache_def) + } + + cgi_select fcachel align=left { + for {set i 0} {$i <= $_wp(fldr_cache_max)} {incr i} { + if {$i == $cols} { + cgi_option $i "value=$i" selected + } else { + cgi_option $i "value=$i" + } + } + } + } + } + } + signature { + cgi_table_row { + cgi_table_data colspan=4 align=center { + cgi_puts "<fieldset>" + cgi_puts "<legend>Signature</legend>" + + set rawsig [join [WPCmd PEConfig rawsig] "\n"] + cgi_textarea signature=$rawsig rows=8 cols=80 wrap=off + + cgi_puts "</fieldset>" + } + } + + } + filters - + scores - + indexcolor - + collections { + set flt 0 + set cll 0 + switch $varname { + filters { + set flt 1 + set descsing "Filter" + set filts [WPCmd PEConfig filters] + set lvals $filts + set varhelp 1 + } + scores { + set flt 1 + set descsing "Scores" + set filts [WPCmd PEConfig scores] + set lvals $filts + set varhelp 1 + } + indexcolor { + set flt 1 + set descsing "Index Colors" + set filts [WPCmd PEConfig indexcolors] + set lvals $filts + set varhelp 1 + } + default { + set cll 1 + set descsing "Collection" + set colls [WPCmd PEConfig collections] + set lvals $colls + } + } + set tasize [llength $lvals] + cgi_table_row { + cgi_table_data align=center colspan=4 width=50% { + cgi_table border=0 cellpadding=3 cellspacing=0 width=100% { + cgi_table_row { + cgi_table_data width=50% { + cgi_puts [cgi_bold $vardesc] + } + if {[info exists varhelp]} { + cgi_table_data valign=top { + cgi_image_button "hlp.$varname=[WPimg cf_help]" alt="Help for $vardesc" + } + } + cgi_table_data "style=\"padding-left: 10px\"" { + cgi_image_button vla.$varname=[WPimg cf_add] alt="Add $descsing" + } + } + set i 0 + foreach lval $lvals { + cgi_table_row { + cgi_table_data "style=\"padding-left: 8px\"" { + if {$flt} { + cgi_puts [cgi_font class=cfvn "[cgi_nbspace]$lval"] + } else { + cgi_puts "[cgi_font class=cfvn [lindex $lval 0]]<br>[cgi_span class=cfval "style=margin-left: 8px" [lindex $lval 1]]" + } + } + + cgi_table_data "style=\"padding-left: 10px\"" valign=top width=30% { + cgi_unbreakable { + cgi_image_button vle.$varname.$i=[WPimg cf_edit] alt="Edit $descsing" + + cgi_image_button vld.$varname.$i=[WPimg cf_delete] alt="Delete $descsing" + + if {$i < [expr {$tasize - 1}]} { + cgi_image_button vlsd.$varname.$i=[WPimg cf_shdown] alt="Shuffle Down" + } else { + cgi_puts [cgi_img [WPimg dot2] width=18] + } + + if {$i} { + cgi_image_button vlsu.$varname.$i=[WPimg cf_shup] alt="Shuffle Up" + } + } + } + } + incr i + } + cgi_text "$varname-sz=$i" type=hidden notab + } + } + } + } + index-format { + cgi_table_row { + cgi_table_data align=left colspan=4 { + cgi_puts "<fieldset style=\"margin-left:1%; margin-right:1%\">" + #set helpbut [cgi_buffer {cgi_image_button "hlp.$varname=[WPimg cf_help]" alt="Help for $vardesc"}] + cgi_puts "<legend>Message Line Format</legend>" + + set varval [WPCmd PEConfig varget $varname] + if {[llength [lindex $varval 0]]} { + set fmt "" + foreach fms [lindex [lindex $varval 0] 0] { + if {[regexp {^([a-zA-Z]+[0-9]*)\(([0-9]+[%]?)\)$} $fms dummy f w]} { + lappend fmt [list $f $w] + } elseif {[regexp {^([a-zA-Z]+[0-9]*)$} $fms dummy f]} { + lappend fmt [list $f ""] + } + } + } else { + set fmt [WPCmd PEMailbox indexformat] + } + + cgi_text "index-format=$fmt" type=hidden notab + + cgi_table cellpadding=0 cellspacing=0 width=100% align=center "bgcolor=#999999" "style=\"border: 1px solid black \"" border=0 { + cgi_table_row "bgcolor=#999999" { + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + cgi_td [cgi_img [WPimg dot2]] + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + + foreach fme $fmt { + set f [lindex $fme 0] + set w [lindex $fme 1] + cgi_td xcolspan=3 [cgi_span "style=font-size: 10px; color: white;" $f] + if {[regexp {[0123456789]+[%]} $w]} { + cgi_td xcolspan=2 align=right [cgi_span "style=font-size: 10px; color: white; padding-right: 4" "(${w})"] + } else { + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + } + + cgi_table_row { + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + cgi_table_data background="[WPimg bg_index]" align=center valign=middle "style=\"padding-left: 4; padding-right: 4\"" { + cgi_checkbox bogus + } + + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + + foreach fme $fmt { + set f [lindex $fme 0] + set w [lindex $fme 1] + + switch -regexp $w { + [0123456789]+[%] { + set width width=$w + } + "" { + set r [WPTFIndexWidthRatio $fmt $f] + switch $r { + 1 { set width "" } + default { + set width "width=[expr {round((100/[llength $fmt]) * $r)}]%" + } + } + } + } + + set align "" + set class "" + switch [string toupper [lindex $f 0]] { + TO { + set varval [WPCmd PEConfig varget personal-name] + if {[string length [lindex $varval 0]]} { + set ftext "To: [lindex $varval 0]" + } else { + set ftext "To: <sender@foo.bar.com>" + } + } + FROM - + FROMORTO { + set varval [WPCmd PEConfig varget personal-name] + if {[string length [lindex $varval 0]]} { + set ftext [lindex $varval 0] + } else { + set ftext "<sender@foo.bar.com>" + } + } + FULLSTATUS - + IMAPSTATUS - + STATUS { + set ftext "+N" + set align "align=center" + } + MSGNO { + set ftext [WPcomma [WPCmd PEMailbox messagecount]] + set align "align=center" + } + SIZE { + set ftext [cgi_span class=isize "(1234)"] + set class class=isize + set align "align=center" + } + KSIZE { + set ftext [cgi_span class=isize "(1K)"] + set class class=isize + set align "align=center" + } + SIZECOMMA { + set ftext [cgi_span class=isize "(1,234)"] + set class class=isize + set align "align=center" + } + DESCRIPSIZE { + set ftext "(short+)" + set align "align=center" + } + SIZENARROW { + set ftext (1K) + } + DATE { + set ftext [clock format [clock seconds] -format "%b %d"] + set align "align=center" + } + DATEISO { + set ftext [clock format [clock seconds] -format "%Y-%m-%d"] + set align "align=center" + } + SHORTDATE1 { + set ftext [clock format [clock seconds] -format "%m/%d/%y"] + set align "align=center" + } + SHORTDATE2 { + set ftext [clock format [clock seconds] -format "%d/%m/%y"] + set align "align=center" + } + SHORTDATE3 { + set ftext [clock format [clock seconds] -format "%d.%m.%y"] + set align "align=center" + } + SHORTDATE4 { + set ftext [clock format [clock seconds] -format "%y.%m.%d"] + set align "align=center" + } + SHORTDATEISO { + set ftext [clock format [clock seconds] -format "%y-%m-%d"] + set align "align=center" + } + SMARTTIME - + SMARTDATETIME - + TIME12 { + regsub {^0*(.*)$} [string tolower [clock format [clock seconds] -format "%I:%M%p"]] {\1} ftext + set align "align=center" + } + TIME24 { + set ftext [clock format [clock seconds] -format "%H:%M"] + set align "align=center" + } + TIMEZONE { + set ftext [clock format [clock seconds] -format "%z"] + set align "align=center" + } + SUBJECT { + set ftext "Re: Config changes..." + } + ATT { + set ftext "1" + } + CC { + set ftext "user@domain" + } + FROMORTONOTNEWS { + set ftext "news.group" + } + LONGDATE { + set ftext [clock format [clock seconds] -format "%b %d, %Y"] + set align "align=center" + } + MONTHABBREV { + set ftext [clock format [clock seconds] -format "%b"] + set align "align=center" + } + NEWS { + set ftext "news.group" + } + SENDER - + RECIPS - + NEWSANDTO - + RECIPSANDNEWS - + NEWSANDRECIPS { + set ftext "user@domain" + } + SCORE { + set ftext "50" + } + SMARTDATE { + set ftext "Today" + } + TOANDNEWS { + set ftext TOANDNEWS + } + default { + set ftext [lindex $f 0] + } + } + cgi_td $align $class $width nowrap height=34 colspan=2 "style=\"padding-right: 4; padding-left: 4\"" background="[WPimg bg_index]" $ftext + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + } + + cgi_table_row { + if {[WPCmd PEInfo feature enable-aggregate-command-set]} { + cgi_table_data "bgcolor=#ffffff" { + cgi_put [cgi_img [WPimg dot2]] + } + + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + + set cols 2 + } else { + set cols 0 + } + + set fmturl "wp.tcl?page=conf_process&wv=msgl&adjust=Change&cid=[WPCmd PEInfo key]&oncancel=$oncancel&index-format=[WPPercentQuote $fmt]" + foreach fme $fmt { + cgi_table_data colspan=2 nowrap "bgcolor=#ffffff" align=center valign=middle { + set cellurl "${fmturl}&ifield=[lindex $fme 0]" + cgi_puts [cgi_url [cgi_img [WPimg if_left] border=0 "alt=Move Field Left" height=11 width=11] "${cellurl}&iop=left" target=_top] + cgi_puts [cgi_url [cgi_img [WPimg if_wider] border=0 "alt=Widen Field" height=11 width=11] "${cellurl}&iop=widen" target=_top] + cgi_puts [cgi_url [cgi_img [WPimg if_remove] border=0 "alt=Remove Field" height=11 width=11] "${cellurl}&iop=remove" target=_top] + cgi_puts [cgi_url [cgi_img [WPimg if_narrow2] border=0 "alt=Narrow Field" height=11 width=11] "${cellurl}&iop=narrow" target=_top] + cgi_puts [cgi_url [cgi_img [WPimg if_right] border=0 "alt=Move Field Right" height=11 width=11] "${cellurl}&iop=right" target=_top] + } + + cgi_td width=1 [cgi_img [WPimg dot2] width=1] + } + } + } + + if {[catch {WPCmd PEConfig indextokens} tokens] == 0} { + cgi_division align=center {style="margin-top: 16; margin-bottom: 10"} { + cgi_submit_button "indexadd=Add Field" + cgi_image_button "hlp.index_tokens=[WPimg cf_help]" alt="Help for $vardesc" + cgi_select indexaddfield { + cgi_option {[ Choose Field to Insert ]} "value=" + + foreach af [lsort -dictionary $tokens] { + if {[lsearch $fmt $af] < 0} { + if {[string compare $af MSGNO]} { + cgi_option $af "value=$af" + } else { + cgi_option $af "value=$af" selected + } + } + } + } + } + } + + cgi_puts "</fieldset>" + } + } + } + view-colors { + cgi_table_row { + cgi_table_data colspan=4 { + cgi_puts "<fieldset style=\"margin-left:1%; margin-right:1%\">" + #set helpbut [cgi_buffer {cgi_image_button "hlp.$varname=[WPimg cf_help]" alt="Help for $vardesc"}] + cgi_puts "<legend>Color Settings </legend>" + + cgi_division class=instr "style=\"padding-bottom: 6\"" { + cgi_put [cgi_span "style=padding: 2; background-color: #ffcc66; border: 1px solid black" "1"] + cgi_put " Choose text below to color, or[cgi_nbspace]enter[cgi_nbspace]field[cgi_nbspace]" + cgi_text newfield= class=instr size=12 maxlength=32 + cgi_put "[cgi_nbspace]to[cgi_nbspace]" + cgi_submit_button "addfield=add to colored headers" + } + + set std_hdrs [list Date From To Cc Subject] + set samp_hdrs $std_hdrs + set samp_text [list normal quote1 quote2 quote3] + set colors {} + + foreach goodkolor $samp_text { + set tcolor [WPCmd PEConfig colorget "${goodkolor}"] + lappend colors [list $goodkolor [lindex $tcolor 0] [lindex $tcolor 1]] + } + + set hcolors [WPCmd PEConfig colorget "viewer-hdr-colors"] + set hi 0 + foreach hcolor $hcolors { + set i 0 + set dhdr 0 + foreach samp_hdr $samp_hdrs { + if {[string compare [string tolower [lindex $hcolor 0]] [string tolower [lindex $samp_hdr 0]]] == 0} { + if {[string length [lindex $hcolor 3]] == 0} { + switch -- $samp_hdr { + Date { + set samptxt [clock format [clock seconds] -format "%a, %d %b %Y %H:%M:%S %Z"] + } + From { + set samptxt [WPCmd PECompose from] + } + Subject { + set samptxt "Your colors are Fabulous!" + } + default { + set samptxt Sample + } + } + lappend samp_hdr [list [lindex $hcolor 1] [lindex $hcolor 2] $samptxt "" $hi] + set samp_hdrs [lreplace $samp_hdrs $i $i $samp_hdr] + set dhdr 1 + break + } else { + lappend samp_hdr [list [lindex $hcolor 1] [lindex $hcolor 2] [lindex $hcolor 3] [lindex $hcolor 3] $hi] + set samp_hdrs [lreplace $samp_hdrs $i $i $samp_hdr] + set dhdr 1 + break + } + } + incr i + } + if {$dhdr == 0} { + set smptxt "Sample" + if {[string compare "" [lindex $hcolor 3]]} { + set smptxt [lindex $hcolor 3] + } + lappend samp_hdrs [list [lindex $hcolor 0] [list [lindex $hcolor 1] [lindex $hcolor 2] $smptxt [lindex $hcolor 3] $hi]] + } + incr hi + } + + set dfgc "ffffff" + set dbgc "000000" + set dq1fgc "ffffff" + set dq1bgc "000000" + set dq2fgc "ffffff" + set dq2bgc "000000" + set dq3fgc "ffffff" + set dq3bgc "000000" + + foreach color $colors { + switch -- [lindex $color 0] { + normal { + set dfgc [lindex $color 1] + set dbgc [lindex $color 2] + } + quote1 { + set dq1fgc [lindex $color 1] + set dq1bgc [lindex $color 2] + } + quote2 { + set dq2fgc [lindex $color 1] + set dq2bgc [lindex $color 2] + } + quote3 { + set dq3fgc [lindex $color 1] + set dq3bgc [lindex $color 2] + } + } + + set colarr([lindex $color 0]) [list [lindex $color 1] [lindex $color 2]] + } + + foreach hcolor $hcolors { + set colarr([lindex $color 0]) [list [lindex $color 1] [lindex $color 2]] + } + + set butno -1 + if {[catch {WPCmd PEInfo set config_defground} defground] || ![string length $defground]} { + set defground f + } + + if {[catch {WPCmd PEInfo set config_deftext} deftext] || ![string length $deftext]} { + set deftext normal + } + + # paint example text + cgi_table cellpadding=0 cellspacing=0 width=100% align=center border=0 { + cgi_table_row { + cgi_table_data align=center { + + cgi_table border=0 cellpadding=0 cellspacing=0 width=100% align=center bgcolor=#${dbgc} "style=\"border-right: 1px solid black\"" { + + cgi_table_row { + cgi_td class=dialog [cgi_img [WPimg dot2]] + cgi_td height=1 "bgcolor=#000000" [cgi_img [WPimg dot2] height=1] + } + + foreach samp_hdr $samp_hdrs { + set field [string tolower [lindex $samp_hdr 0]] + incr butno + cgi_table_row { + cgi_table_data class=dialog align=center nowrap { + cgi_radio_button text=hdr.${field} [button_checked $deftext ${field}] + if {[llength $samp_hdr] == 1} { + set hdrfg $dfgc + set hdrbg $dbgc + } else { + set cp [lindex $samp_hdr end] + set hdrfg [lindex $cp 0] + set hdrbg [lindex $cp 1] + } + + cgi_text "dfg.${field}=$hdrfg" type=hidden notab + cgi_text "dbg.${field}=$hdrbg" type=hidden notab + } + + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc};\"" { + cgi_put "[lindex $samp_hdr 0]: " + + if {[llength $samp_hdr] == 1} { + switch -- [lindex $samp_hdr 0] { + Date { + set samptxt [clock format [clock seconds] -format "%a, %d %b %Y %H:%M:%S %Z"] + } + From { + set samptxt [WPCmd PECompose from] + } + default { + set samptxt Sample + } + } + + button_text text $butno $dfgc $dbgc [cgi_quote_html $samptxt] + cgi_text "add.${field}=1" type=hidden notab + } else { + cgi_text "hi.${field}=[lindex [lindex $samp_hdr end] end]" type=hidden notab + + set pref "" + foreach cp [lrange $samp_hdr 1 end] { + button_text text $butno $hdrfg $hdrbg [cgi_quote_html "${pref}[lindex $cp 2]"] + set pref ", " + } + } + } + } + } + + if {0} { + cgi_table_row { + cgi_td class=dialog [cgi_nbspace] + cgi_table_data { + cgi_text newfield= class=vtext + cgi_submit_button "addfield=Add New Header Field" class=vtext + } + } + } + + cgi_table_row { + cgi_td class=dialog [cgi_nbspace] + cgi_td class=vtext [cgi_nbspace] + } + + cgi_table_row { + cgi_table_data class=dialog align=center { + incr butno + cgi_radio_button text=normal [button_checked $deftext normal] + cgi_text "dfg.normal=$dfgc" type=hidden notab + cgi_text "dbg.normal=$dbgc" type=hidden notab + } + + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + button_text text $butno $dfgc $dbgc "This is a rather silly message." + } + } + + cgi_table_row { + cgi_td class=dialog [cgi_nbspace] + cgi_td class=vtext [cgi_nbspace] + } + + cgi_table_row { + cgi_td class=dialog [cgi_img [WPimg dot2]] + cgi_table_data colspan=2 class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + cgi_put "On Apr 1, 2001, Sample wrote:</a>" + } + } + + cgi_table_row { + cgi_table_data class=dialog align=center { + incr butno + cgi_radio_button text=quote3 [button_checked $deftext quote3] + cgi_text "dfg.quote3=[lindex $colarr(quote3) 0]" type=hidden notab + cgi_text "dbg.quote3=[lindex $colarr(quote3) 1]" type=hidden notab + } + + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + cgi_put [cgi_span "style=color: #[lindex $colarr(quote1) 0]; background-color: #[lindex $colarr(quote1) 1]" "> "] + cgi_put [cgi_span "style=color: #[lindex $colarr(quote2) 0]; background-color: #[lindex $colarr(quote2) 1]" "> "] + button_text text $butno [lindex $colarr(quote3) 0] [lindex $colarr(quote3) 1] "> This is an example of text that is quoted 3 times" + } + } + + cgi_table_row { + cgi_table_data class=dialog align=center { + incr butno + cgi_radio_button text=quote2 [button_checked $deftext quote2] + cgi_text "dfg.quote2=[lindex $colarr(quote2) 0]" type=hidden notab + cgi_text "dbg.quote2=[lindex $colarr(quote2) 1]" type=hidden notab + } + + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + cgi_put [cgi_span "style=color: #[lindex $colarr(quote1) 0]; background-color: #[lindex $colarr(quote1) 1]" "> "] + button_text text $butno [lindex $colarr(quote2) 0] [lindex $colarr(quote2) 1] "> This is an example of text that is quoted 2 times" + } + } + + cgi_table_row { + cgi_table_data class=dialog align=center { + incr butno + cgi_radio_button text=quote1 [button_checked $deftext quote1] + cgi_text "dfg.quote1=[lindex $colarr(quote1) 0]" type=hidden notab + cgi_text "dbg.quote1=[lindex $colarr(quote1) 1]" type=hidden notab + } + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + button_text text $butno [lindex $colarr(quote1) 0] [lindex $colarr(quote1) 1] "> This is an example of text that is quoted 1 time" + } + } + + if {[llength [WPCmd PEInfo signature]]} { + cgi_table_row "style=\"border-right: 1px solid black\"" { + cgi_td class=dialog [cgi_img [WPimg dot2]] + cgi_table_data class=vtext "style=\"color: #${dfgc}\; background-color: #${dbgc}\"" { + foreach i [WPCmd PEInfo signature] { + cgi_puts "$i[cgi_nl]" + } + } + } + } + + cgi_table_row { + cgi_td class=dialog [cgi_img [WPimg dot2]] + cgi_td height=1 "bgcolor=#000000" [cgi_img [WPimg dot2] height=1] + } + } + } + } + + cgi_table_row { + cgi_table_data align=center "style=\"padding-top: 16\"" { + cgi_table width=100% border=0 { + + cgi_table_row colspan=2 { + cgi_td valign=top align=left xrowspan=3 class=instr "style=\"padding-right: 4; background-color: #ffcc66; border: 1px solid black\"" [cgi_span "style=padding: 2;" "2"] + cgi_td width=30% colspan=2 valign=top class=instr "Choose fore- or background..." + cgi_td rowspan=3 width=3% [cgi_img [WPimg dot2]] + cgi_td valign=top align=left xrowspan=3 class=instr "style=\"padding-right: 4; background-color: #ffcc66; border: 1px solid black\"" [cgi_span "style=padding: 2;" "3"] + cgi_table_data valign=middle class=instr nowrap { + cgi_put "Choose item's color below, or[cgi_nbspace]" + cgi_submit_button "reset=restore its default colors" + } + } + + cgi_table_row { + cgi_td rowspan=2 [cgi_img [WPimg dot2]] + cgi_table_data align=right { + if {[string compare $defground f] == 0} { + set checked checked + } else { + set checked "" + } + + cgi_radio_button ground=f $checked + } + + cgi_table_data "style=\"font-size: 10pt\"" { + button_text ground 0 "" "" Foreground + } + + cgi_td rowspan=2 [cgi_img [WPimg dot2]] + cgi_table_data rowspan=2 { + cgi_image_button "colormap=[WPimg nondither10x10]" alt="Color Pattern" "style=\"border: 1px solid black\"" + } + } + + cgi_table_row { + cgi_table_data align=right { + if {[string compare $defground b] == 0} { + set checked checked + } else { + set checked "" + } + + cgi_radio_button ground=b $checked + } + + cgi_table_data "style=\"font-size: 10pt\"" { + button_text ground 1 "" "" [cgi_span "style=color: black; background-color: #FFCC66; padding: 4" "Background"] + } + } + } + } + } + + cgi_table_row { + cgi_table_data colspan=2 align=center class=instr nowrap "style=\"padding-top: 16; padding-bottom: 10;\"" { + cgi_puts "Alternatively, you can also " + cgi_submit_button "reset=Restore All Color Defaults" + } + } + + if {0} { + cgi_table_row { + cgi_table_data class=instr nowrap "style=\"padding-top: 16; padding-bottom: 10;\"" { + cgi_put [cgi_span "style=padding: 2; background-color: #ffcc66; border: 1px solid black" "OR"] + cgi_put " Enter header name[cgi_nbspace]" + cgi_text newfield= class=vtext + cgi_put "[cgi_nbspace]to[cgi_nbspace]" + cgi_submit_button "addfield=Add to Those Being Colored" + } + } + } + } + + cgi_puts "</fieldset>" + } + } + } + } + } + } + incr icnt + } + } + } + } + } + } + } +} diff --git a/web/cgi/alpine/1.0/view.tcl b/web/cgi/alpine/1.0/view.tcl new file mode 100755 index 00000000..cf290e43 --- /dev/null +++ b/web/cgi/alpine/1.0/view.tcl @@ -0,0 +1,920 @@ +# $Id: view.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# view.tcl +# +# Purpose: CGI script to generate html output associated +# with a message's particular text displayed in +# the "body" frame + +# Input: +set view_vars { + {message {} 0} + {first {} 1} + {top {} 0} + {bod_first {} 0} + {bod_prev {} 0} + {bod_next {} 0} + {bod_last {} 0} + {fullhdr {} ""} + {reload {} 0} + {uid {} 0} + {cid {} 0} + {goto {} ""} + {gonum {} 0} + {save {} ""} + {f_name {} ""} + {f_colid {} 0} + {takecancel {} ""} + {savecancel {} 0} + {auths {} 0} + {user {} ""} + {pass {} ""} + {create {} 0} + {flipdelete {} 0} + {delete {} ""} + {undelete {} ""} + {replyall {} ""} + {replytext {} ""} + {submitted {} 0} + {printable {} 0} + {op {} ""} + {showimg {} ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + +#set use_icon_for_status 1 + +set hacktoken __URL__TEXT__ + +## read vars +foreach item $view_vars { + if {[catch {cgi_import [lindex $item 0].x}]} { + if {[catch {eval WPImport $item} errstr]} { + error [list _action "Impart Variable" $errstr] + } + } else { + set [lindex $item 0] 1 + } +} + +if {[catch {WPCmd PEInfo key} webpine_key]} { + error [list _action "command ID" $webpine_key] +} + +# make sure message to be "viewed" is still available +catch {unset errstr} +if {[catch {WPCmd PEMailbox messagecount} messagecount]} { + set errstr $messagecount +} elseif {$uid > 0 && [catch {WPCmd PEMessage $uid number} message]} { + set errstr $message +} elseif {$message > 0 && $message <= $messagecount && [catch {WPCmd PEMailbox uid $message} uid]} { + set errstr $uid +} elseif {!($message && $uid)} { + set errstr "Unknown message number" +} + +if {[info exists errstr]} { + switch $op { + Reply - + Forward { + catch {WPCmd set wp_spec_script fr_view.tcl} + catch {WPCmd set uid $uid} + source [WPTFScript main] + } + default { + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=view" + WPStyleSheets + } + + cgi_body bgcolor=#ffffff { + cgi_table border=0 width="100%" height="100%" { + cgi_table_row { + cgi_table_data width="20%" { + cgi_put [cgi_img [WPimg dot2] border=0 height=1] + } + cgi_table_data bgcolor=#ffffff class=notice { + cgi_puts "\[[cgi_nbspace]" + if {[string first "PEMessage: UID " $errstr] >= 0} { + cgi_puts "The message referred to is no" + cgi_puts "longer available." + cgi_p + cgi_puts "An error has been detected that indicates you may" + cgi_puts "have WebPine running in multiple browser windows." + cgi_p + cgi_puts "Please close all other windows that are displaying" + cgi_puts "WebPine pages." + } else { + cgi_puts "Message Unavailable: $errstr." + } + cgi_p + cgi_puts "Click \"[cgi_url [WPCmd PEMailbox mailboxname] fr_index.tcl target=spec]\" in the column on the left to return to the updated Message List.[cgi_nbspace]\]" + } + cgi_table_data width="20%" { + cgi_put [cgi_img [WPimg dot2] border=0 height=1] + } + } + } + } + } + } + } +} else { + + # make sure any caching doesn't screw this setting + catch {WPCmd set wp_spec_script fr_view.tcl} + + set zoomed [WPCmd PEMailbox zoom] + + set onload "onLoad=" + set onunload "onUnload=" + + if {[info exists _wp(exitonclose)]} { + set closescript [cgi_buffer WPExitOnClose] + append onload "wpLoad();" + append onunload "wpUnLoad();" + } + + # perform any requested actions + if {$flipdelete == 1} { + if {$cid != $webpine_key} { + lappend newmail [list "Can't Delete: Invalid command ID!"] + } elseif {[WPCmd PEMessage $uid flag deleted]} { + if {[catch {WPCmd PEMessage $uid flag deleted 0} result]} { + lappend newmail [list "Error UNdeleting $message: $result"] + } + } else { + if {[catch {WPCmd PEMessage $uid flag deleted 1} result]} { + lappend newmail [list "Error deleting $message: $result"] + } else { + # bug: handle delete-skips-deleted + set message [WPCmd PEMailbox next [WPCmd PEMessage $uid number]] + set uid [WPCmd PEMailbox uid $message] + } + } + } elseif {[string compare "report spam" [string tolower $op]] == 0} { + if {[info exists _wp(spamaddr)] && [string length $_wp(spamaddr)]} { + if {$cid != $webpine_key} { + lappend newmail [list "Can't Spamify: Invalid command ID!"] + } else { + if {[info exists _wp(spamfolder)] && [string length $_wp(spamfolder)] + && [catch { + set savedef [WPCmd PEMailbox savedefault] + if {[WPCmd PEFolder exists [lindex $savedef 0] $_wp(spamfolder)] == 0} { + WPCmd PEFolder create [lindex $savedef 0] $_wp(spamfolder) + } + + WPCmd PEMessage $uid save [lindex $savedef 0] $_wp(spamfolder) + } result]} { + lappend newmail [list "Error spamifying message $message: $result"] + } elseif {[catch {WPCmd PEMessage $uid flag deleted 1} result]} { + lappend newmail [list "Error spamifying message $message: $result"] + } else { + set n [WPCmd PEMessage $uid number] + if {[info exists _wp(spamsubj)]} { + set subj $_wp(spamsubj) + } else { + set subj "" + } + + if {[catch {WPCmd PEMessage $uid spam $_wp(spamaddr) $subj} result]} { + lappend newmail [list "Can't Report Spam: $result"] + } else { + lappend newmail [list "Message $n reported as Spam and flagged for deletion"] + } + } + } + } + } elseif {$delete == 1 || [string compare delete [string tolower $op]] == 0} { + if {$cid != $webpine_key} { + lappend newmail [list "Can't Delete: Invalid command ID!"] + } elseif {[catch {WPCmd PEMessage $uid flag deleted 1} result]} { + lappend newmail [list "Error deleting message $message: $result"] + } else { + set n [WPCmd PEMessage $uid number] + # lappend newmail [list "Message $n deleted"] + # bug: handle delete-skips-deleted + set message [WPCmd PEMailbox next $n] + set uid [WPCmd PEMailbox uid $message] + lappend newmail [list "Message $n flagged for deletion"] + } + } elseif {$delete == 0 || $undelete == 1 || [string compare undelete [string tolower $op]] == 0} { + if {$cid != $webpine_key} { + catch {WPCmd PEInfo statmsg "Invalid command ID!"} + } elseif {[catch {WPCmd PEMessage $uid flag deleted 0}]} { + lappend newmail [list "Error UNdeleting message $message"] + } else { + lappend newmail [list "Deletion mark for message [WPCmd PEMessage $uid number] removed"] + } + } elseif {[string length $goto]} { + if {[regexp {^([0-9]+)$} $gonum n]} { + if {$n > 0 && $n <= [WPCmd PEMailbox last]} { + set message $n + set uid [WPCmd PEMailbox uid $message] + } else { + lappend newmail [list "Jump value out of range: $gonum"] + } + } else { + if {[string length $gonum]} { + lappend newmail [list "Unrecognized Jump value: $gonum"] + } else { + lappend newmail [list "Enter message number, then click 'Jump'"] + } + } + } elseif {$savecancel == 1 || [string compare cancel [string tolower $savecancel]] == 0} { + lappend newmail [list "Save cancelled. Folder not created."] + } elseif {[string compare browse [string tolower $op]] == 0} { + _cgi_set_uservar onselect main + _cgi_set_uservar oncancel main + _cgi_set_uservar controls 2 + source [WPTFScript savebrowse] + set nopage 1 + } elseif {[string compare take [string tolower $op]] == 0} { + source [WPTFScript take] + set nopage 1 + } elseif {[string compare "take address" [string tolower $op]] == 0} { + _cgi_set_uservar take 1 + set addrs "" + if {[catch {cgi_import taList}] == 0} { + foreach ta $taList { + if {[catch {cgi_import_as ${ta}p xp}]} { + set xp "" + } + + if {[catch {cgi_import_as ${ta}m xm}]} { + set xm "" + } + + if {[catch {cgi_import_as ${ta}h xh}]} { + set xh "" + } + + lappend alist [list $xp $xm $xh] + } + + switch [llength $alist] { + 0 { + _cgi_set_uservar addrs "" + } + 1 { + set a [lindex $alist 0] + _cgi_set_uservar fn [lindex $a 0] + _cgi_set_uservar addrs [WPPercentQuote "[lindex $a 1]@[lindex $a 2]"] + } + default { + set addrs "" + foreach a $alist { + if {[string length $addrs]} { + append addrs "," + } + + append addrs [WPPercentQuote "[lindex $a 0] <[lindex $a 1]@[lindex $a 2]>"] + } + + _cgi_set_uservar addrs $addrs + } + } + + source [WPTFScript takeedit] + } else { + WPCmd PEInfo statmsg "Take Address cancelled. No addresses selected." + source [WPTFScript main] + } + + set nopage 1 + } elseif {[string compare cancel [string tolower $takecancel]] == 0} { + source [WPTFScript main] + set nopage 1 + } elseif {[string compare forward [string tolower $op]] == 0} { + _cgi_set_uservar style Forward + source [WPTFScript compose] + set nopage 1 + } elseif {[string compare reply [string tolower $op]] == 0} { + _cgi_set_uservar style Reply + _cgi_set_uservar repqstr [WPCmd PEMessage $uid replyquote] + source [WPTFScript compose] + set nopage 1 + } elseif {[string compare save [string tolower $op]] == 0} { + if {[catch {WPCmd PEMessage $uid save $f_colid $f_name} reason]} { + #statmsg "Save failed: $reason" + lappend newmail [list "Save failed: $reason"] + } else { + set savedef [WPTFSaveDefault $uid] + if {[lindex $savedef 0] == $f_colid} { + WPTFAddSaveCache $f_name + } + + if {[WPCmd PEInfo feature save-will-not-delete] == 0} { + if {[catch {WPCmd PEMessage $uid flag deleted 1} reason]} { + # statmsg "Cannot delete saved message: $reason" + lappend newmail [list "Cannot delete saved message: $reason"] + } + } + } + + } elseif {$bod_first} { + set u $uid + set message [WPCmd PEMailbox first] + set uid [WPCmd PEMailbox uid $message] + if {$zoomed && $u == $uid} { + lappend newmail [list "Already on first of the Marked messages"] + } + } elseif {$bod_prev} { + set u $uid + set message [WPCmd PEMailbox next [WPCmd PEMessage $uid number] -1] + set uid [WPCmd PEMailbox uid $message] + if {$zoomed && $u == $uid} { + lappend newmail [list "Already on first of the Marked messages"] + } + } elseif {$bod_next} { + set u $uid + set message [WPCmd PEMailbox next [WPCmd PEMessage $uid number]] + set uid [WPCmd PEMailbox uid $message] + if {$zoomed && $u == $uid} { + lappend newmail [list "Already on last of the Marked messages"] + } + } elseif {$bod_last} { + set u $uid + set message [WPCmd PEMailbox last] + set uid [WPCmd PEMailbox uid $message] + if {$zoomed && $u == $uid} { + lappend newmail [list "Already on last of the Marked messages"] + } + } + + if {![info exists nopage]} { + switch -exact -- [WPCmd PEMailbox state] { + readonly { + lappend newmail [list [cgi_span "style=color: black; margin: 2 ; border: 1px solid red; background-color: pink; font-weight: bold" "Deleted messages may reapper because [WPCmd PEMailbox mailboxname] is Read Only"]] + } + closed { + lappend newmail [list [cgi_span "style=color: black; border: 1px solid red; background-color: pink; font-weight: bold" "Message body may be blank because [WPCmd PEMailbox mailboxname] is Closed"]] + } + ok - + default {} + } + + if {[catch {WPNewMail $reload ""} newmailmsg]} { + error [list _action "new mail" $newmailmsg] + } else { + foreach i $newmailmsg { + lappend newmail $i + } + + if {[info exists newmail] == 0} { + set newmail "" + } + } + + if {$uid <= 0} { + lappend newmail [list "Message $message has UID 0!"] + } + + if {[WPCmd PEInfo feature enable-full-header-cmd]} { + if {[string length $fullhdr]} { + if {[WPCmd PEInfo mode full-header-mode]} { + if {$fullhdr == 0 || [string compare $fullhdr "off"] == 0} { + WPCmd PEInfo mode full-header-mode 0 + } + } else { + if {$fullhdr == 1 || [string compare $fullhdr "on"] == 0} { + WPCmd PEInfo mode full-header-mode 2 + } + } + } + + if {[WPCmd PEInfo mode full-header-mode]} { + set hmode "fullhdr=off" + set text [cgi_imglink nofullhdr] + } else { + set hmode "fullhdr=on" + set text [cgi_imglink fullhdr] + } + + set hmode_url [cgi_url $text "wp.tcl?page=body&$hmode" name=hmode target=body style=vertical-align:middle] + } + + if {$uid} { + # preserve any new uid val + WPCmd set uid $uid + } + + if {[catch {WPCmd PEMessage $uid charset} charset] + || [string length $charset] == 0 + || [string compare us-ascii [string tolower $charset]] == 0} { + set charset "ISO-8859-1" + } + + catch {fconfigure stdout -encoding binary} + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + cgi_html { + cgi_head { + + cgi_http_equiv Content-Type "text/html; charset=$charset" + + set normalreload [cgi_buffer {WPHtmlHdrReload "$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=body&uid=$uid"}] + if {[info exists _wp(exitonclose)]} { + cgi_puts $closescript + + cgi_script type="text/javascript" language="JavaScript" { + cgi_put "function viewReloadTimer(t){" + cgi_put " reloadtimer = window.setInterval('wpLink(); window.location.replace(\\'[cgi_root]/$_wp(appdir)/$_wp(ui1dir)/wp.tcl?page=body&reload=1\\')', t * 1000);" + cgi_puts "}" + } + + append onload "viewReloadTimer($_wp(refresh));" + cgi_noscript { + cgi_puts $normalreload + } + } else { + cgi_puts $normalreload + } + + if {[info exists _wp(timing)]} { + cgi_script type="text/javascript" language="JavaScript" { + cgi_puts "var loadtime = new Date();" + cgi_puts "var submitted = $submitted;" + cgi_puts "function fini() {var now = new Date(); window.status = 'Page loaded in '+(now.getTime() - loadtime.getTime())/1000+' seconds';}" + } + + append onload "fini();" + } + + WPStyleSheets + + if {$_wp(keybindings)} { + set kequiv { + {{?} {top.location = 'wp.tcl?page=help'}} + {{l} {top.location = 'wp.tcl?page=folders'}} + {{a} {top.location = 'wp.tcl?page=addrbook'}} + {{n} {top.spec.body.location = 'wp.tcl?page=view&bod_next=1'}} + {{p} {top.spec.body.location = 'wp.tcl?page=view&bod_prev=1'}} + {{i} {top.spec.location = 'fr_index.tcl'}} + {{s} {top.spec.cmds.document.saveform.f_name.focus()}} + {{d} {top.spec.cmds.document.delform.op[0].click()}} + {{u} {top.spec.cmds.document.delform.op[1].click()}} + {{r} {top.spec.cmds.document.replform.op.click()}} + {{f} {top.spec.cmds.document.forwform.op.click()}} + } + + lappend kequiv [list {c} "top.location = 'wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key]'"] + + if {[info exists hmode_url]} { + lappend kequiv [list {h} "top.spec.body.location = 'wp.tcl?page=view&$hmode'"] + } + + append onload [WPTFKeyEquiv $kequiv] + } + } + + set fgcolor [set normal_fgcolor [WPCmd PEInfo foreground]] + set bgcolor [WPCmd PEInfo background] + + cgi_body bgcolor=white $onload $onunload { + catch {WPCmd set help_context view} + + set infont 0 + set inurl 0 + + if {[llength $newmail]} { + cgi_division align=center "style=\"border: 1px solid black; background: $_wp(bordercolor)\"" { + WPTFStatusTable $newmail 1 "style=\"padding: 6px 0\"" + } + } + + cgi_table width="100%" border=0 cellpadding=2 cellspacing=0 { + + # Context + cgi_table_row { + if {$zoomed} { + set marked " [cgi_bold marked]" + set c $zoomed + } else { + set marked "" + set c $messagecount + } + + cgi_table_data align=left valign=middle class=context { + # write message number + + if {[catch {WPCmd PEMailbox messagecount before [WPCmd PEMessage $uid number]} prior]} { + set prior 0 + } + + if {[catch {WPCmd PEMailbox messagecount after [WPCmd PEMessage $uid number]} remaining]} { + set remaining 0 + } + + if {$c == 1} { + set msgnotext "Only${marked} Message in [WPCmd PEMailbox mailboxname]" + } elseif {$remaining == 0} { + set msgnotext "[cgi_bold Last] of [WPcomma $c]${marked} message[WPplural $c]" + } elseif {$prior == 0} { + set msgnotext "[cgi_bold First] of [WPcomma $c]${marked} message[WPplural $c]" + } else { + if {[string length $marked]} { + append marked " messages" + set n [expr {$zoomed - $remaining}] + set msgnotext "Message [WPcomma $message] ($n of [WPcomma $c] [cgi_bold marked] messages)" + } else { + set msgnotext "Message [WPcomma $message] of [WPcomma $c]" + } + } + + if {[info exists use_icon_for_status]} { + set staticon "[WPStatusImg $uid] " + set stattext "" + } else { + set staticon "" + switch -regexp [lindex [WPStatusIcon $uid] 0] { + del { + set stattext " (Deleted)" + } + new { + set stattext " (New)" + } + default { + set stattext "" + } + } + } + + cgi_put "${staticon}${msgnotext}${stattext}" + } + + if {$printable} { + cgi_table_data align=right valign=top bgcolor=#bfbfbf class=context { + cgi_puts "Folder: [WPCmd PEMailbox mailboxname]" + } + } else { + if {[info exists common_goto_in_view_specific_frame]} { + cgi_table_data align=right valign=top bgcolor=#bfbfbf class=context { + cgi_form $_wp(appdir)/$_wp(ui1dir)/wp method=get target=body { + cgi_text "page=view" type=hidden notab + cgi_text gonum= type=text size=4 maxlength=4 class=navtext + cgi_submit_button "goto=Jump to Msg" class=navtext + cgi_put [cgi_nbspace] + } + } + } + + cgi_table_data align=right valign=top bgcolor=#bfbfbf class=context { + cgi_put [cgi_url [cgi_img [WPimg printer2] border=0 style=vertical-align:baseline] wp.tcl?page=view&uid=$uid&printable=1 target=_blank "onClick=if(window.print){window.print();return false;}else return true;"] + cgi_put [cgi_img [WPimg dot2] height=1 width=4] + if {[info exists hmode_url]} { + cgi_put $hmode_url + } else { + cgi_put [cgi_imglink dot] + } + } + } + } + + + cgi_table_row { + cgi_table_data valign=top bgcolor=#${bgcolor} class=view width="100%" colspan=2 { + cgi_preformatted "style=\"color:#$normal_fgcolor\"" { + #cgi_division "style=\"color: #$normal_fgcolor; font-family: courier\"" + + set msgtext [WPCmd PEMessage $uid text] + + # pre-scan message text for anything interesting + foreach i $msgtext { + foreach j $i { + switch -exact [lindex $j 0] { + img { + if {![info exists showimages]} { + # ONLY IMG tags in HTML text that reference ATTACHED IMAGE files are allowed + if {[catch {WPCmd PEMessage $uid cid "<[lindex [lindex $j 1] 0]>"} cidpart] == 0 + && [string length $cidpart] + && [catch {WPCmd PEMessage $uid attachinfo $cidpart} attachinfo] == 0 + && [string compare [string tolower [lindex $attachinfo 1]] image] == 0} { + + if {[catch {WPCmd PEMessage $uid fromaddr} fromaddr]} { + set fromaddr "" + } elseif {$showimg == 0} { + if {[catch {WPSessionState allow_cid_images} friends] == 0} { + while {[set findex [lsearch -exact $friends $fromaddr]] >= 0} { + set friends [lreplace $friends $findex $findex] + if {[catch {WPSessionState allow_cid_images $friends} friends]} { + catch {WPCmd PEInfo statmsg "Cannot forget image sender: $friends"} + break; + } + } + } + + set showimg {} + } + + if {[string length $showimg] + || ([catch {WPSessionState allow_cid_images} friends] == 0 + && [lsearch -exact $friends $fromaddr] >= 0)} { + + set showimages 1 + + if {[string length $fromaddr]} { + set bodyleadin "\[ Attached images ARE being displayed \]" + if {$showimg == 1} { + append bodyleadin "[cgi_nl]\[ Always show images from [cgi_url "$fromaddr" "wp.tcl?page=body&showimg=[WPPercentQuote $fromaddr]"] \]" + } else { + append bodyleadin "[cgi_nl]\[ Never show images from [cgi_url "$fromaddr" "wp.tcl?page=body&showimg=0"] \]" + + if {[catch {WPSessionState allow_cid_images} friends] || [llength $friends] == 0} { + set friends $fromaddr + } elseif {[lsearch -exact $friends $fromaddr] < 0} { + lappend friends $fromaddr + } + + if {[catch {WPSessionState allow_cid_images $friends} friends]} { + catch {WPCmd PEInfo statmsg "Cannot remember image sender: $friends"} + } + } + } + } else { + + set showimages 0 + + set bodyleadin "\[ Attached images are NOT being displayed \]" + append bodyleadin "[cgi_nl]\[ Show images [cgi_url "below" "wp.tcl?page=body&showimg=1"]" + if {[string length $fromaddr]} { + append bodyleadin ", or always show images from [cgi_url "$fromaddr" "wp.tcl?page=body&showimg=[WPPercentQuote $fromaddr]"] \]" + } else { + append bodyleadin " \]" + } + + } + } + } + } + default {} + } + } + } + + set inbody 0 + foreach i $msgtext { + + if {!$inbody + && [llength $i] == 1 + && [lindex [lindex $i 0] 0] == "t" + && 0 == [string length [lindex [lindex $i 0] 1]]} { + set inbody 1 + if {[info exists bodyleadin]} { + cgi_puts $bodyleadin + } + } + + foreach j $i { + set ttype [lindex $j 0] + set tdata [lindex $j 1] + + # write anchors by hand + switch -- $ttype { + urlstart { + set href [lindex $tdata 0] + set name [lindex $tdata 1] + + # build links by hand since we don't know where + # they'll terminate + set linktext "<a " + switch -- [lindex [split $href :] 0] { + XXX_mailto { + append linktext "href=\"null.tcl\" onClick=\"composeMsg('mailto','[lindex [split $href :] 1]','$webpine_key'); return false;\"" + } + default { + if {[regexp -- "^\[a-zA-Z\]+:" $href ]} { + append linktext "href=\"$href\" target=_blank" + } ;# no relative links for security + + if {[string length $name]} { + append linktext "name=\"$name\"" + } + } + } + + cgi_put "${linktext}>" + set inurl 1 + } + urlend { + if {$inurl} { + cgi_put "</a>" + } + } + attach { + set attachuid [lindex $tdata 0] + set part [lindex $tdata 1] + set mimetype [lindex $tdata 2] + set mimesubtype [lindex $tdata 3] + if {[string length [lindex $tdata 4]]} { + set file [lindex $tdata 4] + } else { + if {[string length [lindex $tdata 5]]} { + set file "attachment.[lindex $tdata 5]" + } else { + set file "unknown.txt" + } + } + + set attachurl "detach.tcl?uid=${attachuid}&part=${part}" + set saveurl "${attachurl}&download=1" + if {0 == [string compare -nocase $mimetype "text"] + && 0 == [string compare -nocase $mimesubtype "html"]} { + append attachurl "&download=1" + } + + set attachexp "View ${mimetype}/${mimesubtype} Attachment" + + if {0 == [string compare message [string tolower ${mimetype}]] + && 0 == [string compare rfc822 [string tolower ${mimesubtype}]]} { + set attmsgurl "wp.tcl?page=compose&oncancel=main.tcl&cid=[WPCmd PEInfo key]&uid=${attachuid}&part=${part}&style=" + cgi_put [cgi_url [cgi_font size=-1 Fwd] "${attmsgurl}Forward" target=_top] + cgi_put "|[cgi_url [cgi_font size=-1 Reply] "${attmsgurl}Reply&reptext=1&repall=1&repqstr=[WPPercentQuote [WPCmd PEMessage $uid replyquote]]" target=_top]" + + } else { + cgi_put [cgi_url [cgi_font size=-1 View] $attachurl target=_blank] + cgi_put "|[cgi_url [cgi_font size=-1 Save] $saveurl]" + } + + if {[info exists attachurl]} { + set attachtext [WPurl $attachurl {} $hacktoken $attachexp target=_blank] + } + } + img { + if {[info exists showimages] && $showimages == 1 + && [catch {WPCmd PEMessage $uid cid "<[lindex [lindex $j 1] 0]>"} cidpart] == 0 + && [string length $cidpart] + && [catch {WPCmd PEMessage $uid attachinfo $cidpart} attachinfo] == 0 + && [string compare [string tolower [lindex $attachinfo 1]] image] == 0} { + cgi_put [cgi_img detach.tcl?uid=${uid}&part=${cidpart} "alt=\[[lindex $tdata 1]\]"] + } else { + cgi_put "\[[lindex $tdata 1]\]" + } + } + fgcolor { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare $tdata $fgcolor]} { + set fgcolor $tdata + if {[string compare $fgcolor $normal_fgcolor]} { + cgi_put "<font color=#${tdata}>" + set infont 1 + } + } + } + bgcolor { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare $tdata $bgcolor]} { + cgi_put "<font style=\"background: #${tdata}\">" + set bgcolor $tdata + set infont 1 + } + } + color { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare [lindex $tdata 0] $fgcolor] || [string compare [lindex $tdata 1] $bgcolor]} { + cgi_put "<font color=#[lindex $tdata 0] style=\"background: #[lindex $tdata 1]\">" + set bgcolor $tdata + set infont 1 + } + } + italic { + switch $tdata { + on { cgi_put "<i>" } + off { cgi_put "</i>" } + } + } + bold { + switch $tdata { + on { cgi_put "<b>" } + off { cgi_put "</b>" } + } + } + underline { + switch $tdata { + on { cgi_put "<u>" } + off { cgi_put "</u>" } + } + } + strikethru { + switch $tdata { + on { cgi_put "<s>" } + off { cgi_put "</s>" } + } + } + bigfont { + switch $tdata { + on { cgi_put "<font size=\"+1\">" } + off { cgi_put "</font>" } + } + } + smallfont { + switch $tdata { + on { cgi_put "<font size=\"-1\">" } + off { cgi_put "</font>" } + } + } + default { + if {[info exists attachtext] && [set ht [string first $hacktoken $attachtext]] >= 0} { + set firstbit [string range $attachtext 0 [expr {$ht - 1}]] + set lastbit [string range $attachtext [expr {$ht + [string length $hacktoken]}] end] + cgi_put " $firstbit[cgi_quote_html [string trimleft $tdata]]$lastbit" + unset attachtext + } else { + cgi_put [cgi_quote_html $tdata] + } + } + } + } + + cgi_puts "" + } + } + } + } + + if {![info exists attachuid]} { + if {!([catch {WPCmd PEMessage $uid attachinfo 1} typing] + || [string compare [string tolower [lindex $typing 1]] text] + || [string compare [string tolower [lindex $typing 2]] html])} { + cgi_table_row { + cgi_table_data align=center { + cgi_puts [cgi_font font-family=fixed "\[Note: you may also [cgi_url view "detach.tcl?uid=${uid}&part=1" target=_blank] HTML message directly in your browser\]"] + } + } + } + } + } + + if {$infont} { + cgi_put "</font>" + } + + if {$inurl} { + cgi_put "</a>" + } + + if {[info exists _wp(cumulative)]} { + set l [string length $_wp(cumulative)] + if {$l < 6} { + set sl "." + while {$l < 6} { + append sl "0" + incr l + } + append sl $_wp(cumulative) + } else { + set sl "[string range $_wp(cumulative) 0 [expr $l - 7]].[string range $_wp(cumulative) [expr $l - 6] end]" + } + + set servlettime "servlet = $sl" + + if {[info exists wp_global_loadtime]} { + set clickdiff [expr {[clock clicks] - $wp_global_loadtime}] + # 500165 clicks/second + set st [expr ([string range $clickdiff 0 [expr [string length $clickdiff] - 4]] * 1000) / 500] + set l [string length $st] + set scripttime "tcl = [string range $st 0 [expr $l - 4]].[string range $st [expr $l - 3] end], " + } else { + set scripttime "" + } + + cgi_puts [cgi_font size=-2 "style=font-family:sans-serif;font-weight:bold" "\[time: ${scripttime}${servlettime}\]"] + } + } + } + } + }
\ No newline at end of file diff --git a/web/cgi/alpine/1.0/wp.tcl b/web/cgi/alpine/1.0/wp.tcl new file mode 100755 index 00000000..f649ca0a --- /dev/null +++ b/web/cgi/alpine/1.0/wp.tcl @@ -0,0 +1,135 @@ +#!./tclsh +# $Id: wp.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# wp.tcl +# +# Purpose: CGI script to serve as the frame-work for including +# supplied script snippets that generate the various +# javascript-free webpine pages +# +# Input: +set wp_vars { + {page {} "main"} + {uidList {} ""} + {uidpage {} ""} +} + +set wp_global_loadtime [clock clicks] + +# inherit global config +source ./alpine.tcl +source cmdfunc.tcl + +proc sortname {name {current 0}} { + global rev me + + switch -- $name { + Number { set newname "#" } + OrderedSubj { set newname "Ordered Subject" } + Arrival { set newname Arv } + Status { set newname " " } + default { set newname $name } + } + + if {$current} { + if {$rev > 0} { + set text [cgi_imglink increas] + set args rev=0 + } else { + set text [cgi_imglink decreas] + set args rev=1 + } + + append newname [cgi_url $text "wp.tcl?page=body&sortrev=1" "title=Reverse $newname ordering" target=body] + } + + return $newname +} + +proc linecolor {linenum} { + global color + + if {$linenum % 2} { + return $color(line1) + } else { + return $color(line2) + } +} + +proc lineclass {linenum} { + if {$linenum % 2} { + return i0 + } else { + return i1 + } +} + +proc uid_framed {u mv} { + foreach m $mv { + if {$u == [lindex $m 1]} { + return 1 + } + } + return 0 +} + +WPEval $wp_vars { + + # Resolve checked uidList + foreach uid [split $uidpage ","] { + WPCmd PEMessage $uid select [expr [lsearch $uidList $uid] >= 0] + } + + # sourced "page" get's CGI parms from environment + if {[catch {WPTFScript $page} source]} { + switch -regexp -- $page { + addredit { + set source fr_addredit.tcl + } + addrsave { + set source addrsave.tcl + } + addrpick { + set source addrpick.tcl + } + ldappick { + set source ldappick.tcl + } + post { + set source post.tcl + } + prune { + set source prune.tcl + } + noop { + cgi_html { + cgi_head + cgi_body {} + } + unset source + } + default { + WPInfoPage "Web Alpine Error" [font size=+2 "Unknown WebPine page reference: $page."] \ + "Please complain to the [cgi_link Admin]. Click Back button to return to previous page." + } + } + + if {[info exists source]} { + set source [file join $_wp(cgipath) $_wp(appdir) $_wp(ui1dir) $source] + } + } + + if {[info exists source]} { + source $source + } +} diff --git a/web/cgi/alpine/2.0/.htaccess b/web/cgi/alpine/2.0/.htaccess new file mode 100644 index 00000000..dd9da02d --- /dev/null +++ b/web/cgi/alpine/2.0/.htaccess @@ -0,0 +1,7 @@ +# set up default page +DirectoryIndex ./browse + +# extensionless files are scripts +<FilesMatch "^([^\.]+)$"> + SetHandler cgi-script +</FilesMatch> diff --git a/web/cgi/alpine/2.0/alpine.tcl b/web/cgi/alpine/2.0/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/alpine/2.0/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/browse b/web/cgi/alpine/2.0/browse new file mode 100755 index 00000000..9669fd8c --- /dev/null +++ b/web/cgi/alpine/2.0/browse @@ -0,0 +1,336 @@ +#!./tclsh +# $Id: browse 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# browse +# +# Purpose: CGI script that generates a page displaying a message +# list of the indicated folder. +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_first_msg> +# along with possible search parameters: +set browse_args { + {u {} 0} + {pageFirst {} ""} + {pagePrev {} ""} + {pageNext {} ""} + {pageLast {} ""} + {sort {} ""} + {rev {} ""} +} + +# inherit global config +source ./alpine.tcl +source ./common.tcl +source ./foldercache.tcl + +# default browse state +set c 0 +set f INBOX + +# TEST: +proc cgi_suffix {args} { + return "" +} + +# for inserting debug comments at end of page +set dmsgs "" +proc dm {s} { + global dmsgs + lappend dmsgs $s +} + +WPEval $browse_args { + # grok PATH_INFO for collection, 'c', and folder 'f' + if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {![regexp {^/([0-9]+)/(.*)$} $env(PATH_INFO) dummy c f]} { + WPCmd PEInfo statmsg "Cannot open invalid path: $env(PATH_INFO)" + set c 0 + set f INBOX + } + } elseif {[catch {WPCmd PEFolder current} curf] + || [lindex $curf 0] != 0 + || [string compare -nocase [lindex $curf 1] inbox]} { + WPCmd PEInfo statmsg "No Folder Specified, opening INBOX" + } + + # verify or visit specified collection/folder + + if {[catch {setCurrentFolder c f u} result]} { + set authlist [wpHandleAuthException $result [list $c "open folder $f"] $f] + if {0 == [llength $authlist]} { + WPCmd PEInfo statmsg "$result" + set c 0 + set f INBOX + } else { + set opening_folder 1 + } + } + + if {[info exists opening_folder]} { + set n 1 + set u 0 + } else { + # move anything deleted to Trash + if {[catch {WPCmd PEMailbox trashdeleted current} result]} { + WPCmd PEInfo statmsg "Trash move Failed: $result" + } + + # set uid to "current" message? + if {$u <= 0 && 0 == [catch {WPCmd PEMailbox current} cm]} { + set u [lindex $cm 1] + } + } + + # get default sort + if {[catch {WPCmd PEMailbox sort} cursort]} { + set sort date + set rev 1 + } + + # load index drawing routine for this session + # save perpage source, proc overhead + # call to reinstall during debugging: + #catch {WPCmd rename drawMessageList {}} + if {0 == [llength [WPCmd info commands drawMessageList]]} { + set cgidir [file join $_wp(cgipath) $_wp(appdir) $_wp(ui2dir)] + if {[catch { + WPCmd source "$_wp(confdir)/alpine.tcl" + WPCmd source "${cgidir}/common.tcl" + WPCmd source "${cgidir}/messagelist.tcl" + WPCmd source "${cgidir}/messageview.tcl" + WPCmd rename WPCmd {} + WPCmd rename WPEval {} + WPCmd rename WPGetInputAndID {} + WPCmd rename WPCmdEval WPCmd + } result]} { + error [list _action browse "cannot load index lister: $result"] + } + } + + # current context or folder changed? + if {$c == 0 && 0 == [string compare -nocase $f inbox]} { + set f INBOX + } + + # gain situational awareness, UID and number of message that must be on page + if {[catch {WPCmd PEMailbox focus} focused]} { + set mc 0 + set focused 0 + } elseif {$focused > 0} { + set mc $focused + } else { + set mc [WPCmd PEMailbox messagecount] + } + + if {$u == 0} { + # non given, set to first message in folder + set n 1 + if {[catch {WPCmd PEMailbox uid 1} u]} { + set n 0 + set u 0 + } + } elseif {[catch {WPCmd PEMessage $u number} n]} { + set n 0 + set u 0 + } + + # lines per page + if {[catch {WPCmd PEInfo indexlines} ppg] || $ppg <= 0} { + set ppg $_wp(indexlines) + } elseif {$ppg > $_wp(indexlinesmax)} { + set ppg $_wp(indexlinesmax) + } + + # look for image button clicks + foreach item $browse_args { + if {0 == [catch {cgi_import [lindex $item 0].x}]} { + set [lindex $item 0] 1 + } + } + + # preform actions specfied in browse_args + # NOTE: basic stuff only to be executed in absense of JS + if {[string length $pageFirst]} { + set n 1 + set u [WPCmd PEMailbox uid 1] + } elseif {[string length $pagePrev]} { + if {$ppg >= $n} { + set n 1 + } else { + set n [expr {$n - $ppg}] + } + + if {[catch {WPCmd PEMailbox uid $n} u]} { + set u 0 + } + } elseif {[string length $pageNext]} { + if {($n + $ppg) <= $mc} { + incr n $ppg + if {[catch {WPCmd PEMailbox uid $n} u]} { + set u 0 + } + } + } elseif {[string length $pageLast]} { + set n $mc + if {[catch {WPCmd PEMailbox uid $n} u]} { + set u 0 + } + } elseif {[string length $sort]} { + switch $rev { + 0 - + 1 { + } + default { + set rev [lindex $cursort 1] + } + } + + if {[catch {WPCmd PEMailbox sort $sort $rev} cursort]} { + WPCmd PEInfo statmsg "Cannot set sort: $cursort" + set cursort [list nonsense 0] + } else { + # store result + WPCmd set sort [list $sort $rev] + } + } + + # page framing + if {[catch { + set nm [WPCmd PEMailbox flagcount [list unseen undeleted]] + set defcol [WPCmd PEFolder defaultcollection] + wpInitPageFraming u n mc ppg pn pt + }]} { + set pn 1 + set pt 0 + set nm 0 + set defcol 0 + } + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=UTF-8" + } + + cgi_html { + cgi_head { + # WPStdHttpHdrs "text/html; charset=UTF-8" + cgi_title [wpPageTitle "$f, $pn of $pt ($nm)"] + cgi_base "href=$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + cgi_stylesheet css/menu.css + cgi_stylesheet css/cbn/screen.css + cgi_stylesheet css/cbn/folderdialog.css + cgi_stylesheet $_wp(yui)/build/container/assets/container-core.css + cgi_stylesheet $_wp(yui)/build/menu/assets/skins/sam/menu.css + cgi_stylesheet $_wp(yui)/build/button/assets/skins/sam/button.css + # YahooUI libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/menu/menu-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + # local libraries + cgi_script type=text/javascript language="JavaScript" src="lib/common.js" {} + cgi_script type=text/javascript language="JavaScript" src="lib/mailbox.js" {} + # page specfic JS + cgi_javascript { + cgi_puts "YAHOO.alpine.cgi_root = '$_wp(serverpath)';" + cgi_puts "YAHOO.alpine.app_root = '$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)';" + cgi_puts "YAHOO.alpine.current.c = $c;" + cgi_puts "YAHOO.alpine.current.f = \"$f\";" + cgi_puts "YAHOO.alpine.current.u = $u;" + cgi_puts "YAHOO.alpine.current.page = $pn;" + cgi_puts "YAHOO.alpine.current.count = $mc;" + if {[catch { + set mb_sel [WPCmd PEMailbox selected] + set mb_srch [WPCmd PEMailbox searched] + }]} { + set mb_sel 0 + set mb_srch 0 + } + + cgi_puts "YAHOO.alpine.current.selected = $mb_sel;" + cgi_puts "YAHOO.alpine.current.searched = $mb_srch;" + cgi_puts "YAHOO.alpine.current.focused = $focused;" + cgi_puts "function bodyOnLoad(){" + cgi_puts " initMenus();" + cgi_puts " initMorcButton('listMorcButton');" + cgi_puts " initSelection();" + cgi_puts " if(YAHOO.env.ua.gecko > 0){ sizeVPHeight(); window.onresize = resizeVPHeight; }" + wpSetMessageListNewMailCheck + wpStatusAndNewmailJavascript + wpSaveMenuJavascript "browse" $c $f $defcol morcInBrowseDone + cgi_puts " if(self.loadDDElements) loadDDElements();" + + if {[info exists authlist]} { + cgi_puts "YAHOO.alpine.resubmitRequest = function(){ window.location.href = 'browse/$c/$f'; };" + cgi_puts "YAHOO.alpine.cancelRequest = function(){ window.location.href = 'browse/0/INBOX'; };" + reportAuthException $authlist + } + cgi_puts "}" + cgi_puts "browserDetect();" + } + } + + cgi_body class="wap" "onLoad=bodyOnLoad()" { + cgi_division id="skip" { + cgi_put [cgi_url "Skip to Next Page" "\#" "onClick=return newMessageList({control:this,parms:{op:'next'}});"] + cgi_put [cgi_url "Skip to Folders" "folders"] + cgi_put [cgi_url "Skip to Compose" "compose"] + } + + cgi_division id=msgDragProxy { + cgi_put "<b class=b1></b><b class=b2></b><b class=b3></b><b class=b4></b><div id=msgDragProxyText></div><b class=b4></b><b class=b3></b><b class=b2></b><b class=b1></b>" + } + + if {$focused} { + set context "Search Results in [cgi_quote_html $f]" + } else { + set context [cgi_quote_html $f] + } + wpCommonPageLayout browse $c $f $u $context [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/browse/${c}/${f}"] "$f" 1 mailboxSearch()] "" { + cgi_division class=hdrBtns { + cgi_javascript { + cgi_put "if(window.print) document.write('[cgi_buffer {cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"]}]');" + } + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi2" ""][cgi_span "class=hdrBtnText" Settings]" "settings"] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" \# "onClick=return openMailboxHelp();" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"] + } + } { + cgi_division id=listTopMenubar { + cgi_puts [WPCmd cgi_buffer "drawTopListMenuBar $c {$f}"] + } + cgi_division id=viewTopMenubar "style=\"display: none;\"" { + cgi_puts [WPCmd cgi_buffer "drawTopViewMenuBar $c {$f} $u $n"] + } + } { + if {[info exists opening_folder]} { + cgi_puts "Opening $f..." + } else { + cgi_puts [WPCmd cgi_buffer "drawMessageList $c {$f} $n $ppg"] + } + } { + cgi_division id=listBottomMenubar { + cgi_puts [WPCmd cgi_buffer "drawBottomListMenuBar $c {$f} $pn $pt $mc"] + } + cgi_division id=viewBottomMenubar "style=\"display: none;\"" { + cgi_puts [WPCmd cgi_buffer "drawBottomViewMenuBar $c {$f} $u $n $mc"] + } + } + + foreach dmsg $dmsgs { + cgi_html_comment "DEBUG: $dmsg" + cgi_puts "" + } + } + } +} diff --git a/web/cgi/alpine/2.0/common.tcl b/web/cgi/alpine/2.0/common.tcl new file mode 100644 index 00000000..41e58a7a --- /dev/null +++ b/web/cgi/alpine/2.0/common.tcl @@ -0,0 +1,905 @@ +# $Id: common 391 2007-01-25 03:53:59Z mikes@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# common.tcl +# +# Purpose: TCL script snippets that the various CGI script generating pages +# have in common +# + +proc wpSelectedClass {seld unread defclass} { + set class $defclass + if {[expr $seld]} { + append class " sel" + } + + if {$unread} { + append class " bld" + } + + return $class +} + +proc wpPageTitle {page} { + return "$page - Web Alpine 2.0" +} + +proc current_context {page c f cc cf} { + set ct {[lsearch {browse view} $page] >= 0 && } + if {0 == $cc && 0 == [string compare -nocase inbox $cf]} { + append ct {0 == $c && 0 == [string compare -nocase inbox $f]} + } else { + append ct {$cc == $c && 0 == [string compare $cf $f]} + } + + set current [expr $ct] +} + +proc folder_link {current page c f u unread {ficon ""}} { + set url "browse/$c/[WPPercentQuote $f {/}]" + set clickurl $url + set urlid "" + set fclass "" + set fid "" + if {$current} { + set urlid "id=\"gFolder\"" + set urid "id=\"unreadCurrent\"" + set fid "id=\"fCurrent\"" + set onclick "onClick=return newMessageList({parms:{op:'unfocus',page:'new'}});" + } elseif {[string length $ficon]} { + set fq [cgi_quote_html $f] + set urid "id=\"unread${fq}\"" + set fid "id=\"f${fq}\"" + set onclick [onClick $clickurl] + } else { + set urid "" + set onclick "" + } + + if {$unread} { + set fclass "class=bld" + set urc " ($unread)" + } elseif {[string length $ficon] || $current} { + set urc "" + } + + if {[info exists urc]} { + set urt [cgi_span "class=wap unrd" $urid $urc] + } else { + set urt "" + } + + if {![string length $ficon]} { + set ficon [cgi_span "class=sp splc splc7" ""] + } + + if {[string length $f] > 20} { + set f "...[string range $f end-18 end]" + } + + return "[cgi_url "$ficon[cgi_span $fid $fclass [cgi_quote_html $f]]" $url class=wap $urlid $onclick]$urt" +} + +proc empty_link {current falias c} { + if {$current} { + set emptyfunc emptyCurrent + } else { + switch $falias { + Trash { set emptyfunc emptyTrash} + Junk { set emptyfunc emptyJunk } + } + } + if {[info exists emptyfunc]} { + return "\[[cgi_url "Empty" "#" "onClick=panelConfirm('Are you sure you want to permanently delete the contents of the $falias folder?<p>Deleted messages are gone forever.',{text:'Empty $falias',fn:$emptyfunc}); return false;" title="Permanently delete all messages in the $falias folder" class=wap]\]" + } + + return "" +} + +proc context_class {current focus} { + if {$current != 0 && $focus == 0} { + return "fld sel" + } + + return "fld" +} + +proc div_folder {page c f u cc cf unread focus {ficon ""}} { + set current [current_context $page $c $f $cc $cf] + cgi_division class="[context_class $current $focus]" { + cgi_put [folder_link $current $page $cc $cf $u $unread $ficon] + } +} + +proc wpStatusAndNewmailJavascript {} { + foreach sm [WPCmd PEInfo statmsgs] { + regsub -all {'} $sm {\'} sm + cgi_puts " addStatusMessage('$sm',15);" + } + + if {[catch {WPCmd PESession mailcheck 0} newmail]} { + regsub -all {'} $newmail {\'} newmail + cgi_puts " addStatusMessage('New Mail Error: $newmail',10);" + } else { + foreach nm $newmail { + set text [lindex $nm 2] + regsub -all {'} $text {\'} text + if {[string length $text]} { + cgi_puts " addStatusMessage('${text}',10);" + } + } + } + + cgi_puts " displayStatusMessages();" + catch {WPCmd PEMailbox newmailreset} +} + +proc wpSetMessageListNewMailCheck {} { + cgi_puts " setCheckMailFunction('gCheck', function(){ newMailCheck(0,'newMessageList()'); });" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout], 'newMessageList()');" +} + +set clicktest "" + +proc onClick {dest} { + global clicktest + + if {[string length $clicktest]} { + return "onClick=[$clicktest $dest]" + } + + return "" +} + +proc var_value {var} { + set varval [WPCmd PEConfig varget $var] + switch [lindex $varval 1] { + textarea { + return [join [lindex $varval 0] "\n"] + } + listbox { + return [lindex $varval 0] + } + default { + return [lindex [lindex $varval 0] 0] + } + } + + return "" +} + +# table representing common overall page layout +# +# NOTES: bodyform doesn't flow thru cgi.tcl,but it keeps menu bar's +# easier for caller to keep stright +# +proc wpCommonPageLayout {curpage c f u context searchform leavetest cmds menubar_top content menubar_bottom} { + global _wp clicktest + + set thispage [lindex $curpage 0] + + set clicktest $leavetest + + if {[catch {WPCmd PEMailbox focus} focused]} { + set focused 0 + } + + # various positioned elements + + # busy cue + cgi_division id="bePatient" { + cgi_put "Working..." + } + + cgi_table class="page" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + + cgi_table_row { + cgi_table_data class="spc" colspan="3" { + cgi_put [cgi_span "class=sp trans" "style=height:1px;width:2px;" [cgi_span " "]] + } + } + + # CONTEXT + cgi_table_row { + cgi_table_data class="wap topHdr" { + cgi_division id=hdrLogo { + cgi_puts [cgi_img "img/cbn/alpinelogo.gif" name="logo" class="logo" "title=Web Alpine [WPCmd PEInfo version]" class=wap] + cgi_puts [cgi_span "class=logo wap" "v [WPCmd PEInfo version].[WPCmd PEInfo revision]"] + } + } + + cgi_table_data class="topHdr" { + cgi_put [cgi_span "class=sp trans" "style=height:2px;width:5px;" " "] + } + + cgi_table_data class="wap topHdr" { + cgi_division class=hdrContent { + # RSS INFO STREAM + if {[catch {WPCmd PERss news} news]} { + cgi_put [cgi_nbspace] + cgi_html_comment "RSS FAILURE: $news" + } else { + if {[llength $news] > 0} { + set style "" + set n 0 + foreach item $news { + cgi_put [cgi_span class=RSS $style "[cgi_span "class=sp newsImg" "onClick=\"return rotateNews(this);\"" ""][cgi_url [lindex $item 0] [lindex $item 1] "onClick=this.blur();" id=newsItem$n target=_blank]"] + set style "style=display: none;" + } + } else { + cgi_put [cgi_nbspace] + } + } + + # STATUS LINE + cgi_division class=wbar id=statusMessage { + cgi_division class=status { + cgi_division "class=\"flt edge\"" { + cgi_put [cgi_span "class=sp spsm sm1" ""] + } + cgi_division "class=\"frt cap\"" {} + cgi_division "class=\"frt edge\"" { + cgi_put [cgi_url [cgi_span "class=sp spsm sm2" ""] "" class=wap "onClick=hideStatusMessage(); return false;"] + } + cgi_division class=center id=statusMessageText {} + } + } + + # WEATHER/USAGE/STATUS + cgi_division class=wbar id=weatherBar { + # RSS WEATHER + cgi_division class=weather id=rssWeather { + if {[catch {WPCmd PERss weather} weather]} { + cgi_html_comment "RSS FAILURE: $weather" + cgi_put [cgi_nbspace] + } else { + if {[llength $weather] > 0} { + set item [lindex $weather 0] + cgi_put [cgi_url [lindex $item 0] [lindex $item 1] "onClick=this.blur();" target=_blank] + } else { + cgi_put [cgi_nbspace] + } + } + } + if {[info exists _wp(usage)] + && 0 == [catch {exec -- $_wp(usage) [WPCmd set env(WPUSER)]} usage] + && [regexp {^([0-9]+)[ ]+([0-9]+)$} $usage dummy use_current use_total] + && $use_total > 0 + && $use_current <= $use_total} { + cgi_division class=usage { + cgi_table width="180px" cellpadding="0" cellspacing="0" { + cgi_table_row { + cgi_table_data class=wap width="1%" align=right { + cgi_put [cgi_nbspace] + } + cgi_table_data class=wap width="98%" { + + set useperc [expr {($use_current * 100) / $use_total}] + + cgi_table border=0 width="100%" height="12px" cellspacing=0 cellpadding=0 align=right { + set percentage [expr {($use_current * 100)/$use_total}] + cgi_table_row { + cgi_table_data class=wap align=right "style=\"border: 1px solid black; border-right: 0; background-color: #408040;\"" width="$useperc%" { + cgi_put [cgi_span "class=sp trans" "style=height:1px;width:1px;" [cgi_span " "]] + } + cgi_table_data class=wap align=right "style=\"border: 1px solid black; background-color: #ffffff;\"" width="[expr {100 - $useperc}]%" { + cgi_put [cgi_span "class=sp trans" "style=height:1px;width:1px;" [cgi_span " "]] + } + } + } + } + cgi_table_data class=wap width="1%" align=right { + set units MB + if {[info exists _wp(usage_link)]} { + set txt [cgi_url $use_total $_wp(usage_link) "onClick=this.blur();" title="Detailed usage report" target="_blank"] + } else { + set txt $use_total + } + + cgi_put [cgi_span "style=margin-left: .25em" $txt] + } + } + } + } + } + } + + cgi_division class=pageTitle id=pageTitle { + cgi_put $context + } + + cgi_division class=commands { + uplevel 1 $cmds + } + } + } + } + cgi_noscript { + cgi_table_row { + cgi_table_data class=noscript colspan="3" { + cgi_put "This version of Web Alpine requires Javascript. Please enable Javascript, or use the [cgi_url "HTML Version" "$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/wp.tcl"] of Web Alpine" + } + } + } + cgi_table_row { + cgi_table_data id=leftColumn class="wap checkMailandCompose" { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_put "<tbody>" + cgi_table_row { + cgi_table_data class="wap" { + set nUrl "browse/" + if {0 == [regexp {^[0-9]+$} $c]} { + append nUrl "/0'" + } else { + append nUrl "/$c'" + } + + if {0 == [string length $f]} { + append nUrl "/INBOX'" + } else { + append nUrl "/[WPPercentQuote $f]" + } + + set nUrl "browse/$c/$f" + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb15" "Check Mail"] $nUrl title="Check for New Mail" id=gCheck "onClick=this.blur(); return false;"] + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class="wap" { + set cUrl compose + if {[string compare compose $thispage]} { + switch $thispage { + browse { append cUrl "?pop=browse/$c/$f" } + view { append cUrl "?pop=view/$c/$f/$u" } + default { append cUrl "?pop=$thispage" } + } + } + + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb16" "Compose"] $cUrl id=composeLink title="Compose New Message" [onClick $cUrl]] + } + } + cgi_put "</tbody>" + } + + cgi_division class=searchFormDiv { + cgi_form [lindex $searchform 0] id=searchForm method=post enctype=multipart/form-data { + if {[string length [lindex $searchform 3]]} { + set sclick [lindex $searchform 3] + } else { + set sclick "showStatusMessage('Search is NOT implemented yet',3)" + } + + cgi_text "searchText=Search in [lindex $searchform 1]" class=wap id=searchField title="Click here to search" "onBlur=recallTextField(this, 'Search in [lindex $searchform 1]')" "onClick=\"clearTextField(this, 'Search in [lindex $searchform 1]')\"" "onKeyPress=\"return searchOnEnter(event,'searchButton');\"" maxlength="256" + cgi_put "<input alt=\"Search\" name=\"search\" class=\"sp searchBtn\" type=\"submit\" value=\"\" src=\"\" id=\"searchButton\" onClick=\"${sclick}; this.blur(); return false;\" />" + + set srclass "fld" + set searched 0 + if {[lsearch {browse view} $thispage] >= 0 && 0 == [catch {WPCmd PEMailbox searched} searched] && $searched} { + set style "" + if {$focused} { + append srclass " sel" + } + } else { + set style "display:none;" + } + + cgi_division id="searchRefine" style=\"$style\" { + cgi_select scope id=searchScope { + cgi_option "Search within Results" value=narrow + cgi_option "Add to Search Results" value=broad + cgi_option "New Search" value=new selected + } + } + } + } + + if {[lindex $searchform 2]} { + cgi_division id=searchAdvance { + cgi_puts [cgi_url "Advanced Search" "browse/$c/$f?search=1" class="wap" "onClick=return advanceSearch();"] + } + cgi_division id=searchClear style=$style { + cgi_puts "\[[cgi_url Clear # class="wap" "onClick=return newMessageList({parms:{op:'search',type:'none',page:'new'}});"]\]" + } + } + + cgi_division class=searchFormDiv {cgi_puts [cgi_nbspace]} + + cgi_division id=searchResult class="$srclass" style=\"$style\" { + cgi_puts [cgi_url "[cgi_span "class=sp splc splc9" ""][cgi_span class=bld id=searchResultText [cgi_quote_html "Search Result ($searched)"]]" browse/$c/$f?search=1 class=wap "onClick=return listSearchResults();"] + } + + if {0 == [string compare [lindex $curpage 0] settings]} { + uplevel 1 [lindex $curpage 1] + } else { + cgi_division class="folderPane" { + cgi_anchor_name folders + cgi_division class=folderList { + set defc [WPCmd PEFolder defaultcollection] + + cgi_javascript { + cgi_puts "function emptyCurrent(){" + cgi_puts " doEmpty(null,'all');" + cgi_puts "}" + cgi_puts "function emptyTrash(){" + cgi_puts " emptyFolder('$defc','[var_value trash-folder]','all',{status:true,fn:'fixupUnreadCount(\"Trash\",0)'});" + cgi_puts "}" + if {[info exists _wp(spamfolder)]} { + cgi_puts "function emptyJunk(){" + cgi_puts " emptyFolder('$defc','$_wp(spamfolder)','all',{status:true,fn:'fixupUnreadCount(\"Junk\",0)'});" + cgi_puts "}" + } + } + + set current [current_context $thispage $c $f 0 INBOX] + cgi_division class="[context_class $current $focused]" id=targetInbox { + cgi_put [folder_link $current $thispage 0 INBOX $u [WPCmd PEFolder unread 0 INBOX] [cgi_span "class=sp splc splc1" ""]] + if {0 == [string compare browse $thispage] && [string compare -nocase inbox $f]} { + lappend ddtargets [list targetInbox 0 INBOX] + } + } + + set draftf [var_value postponed-folder] + if {0 == [catch {WPCmd PEFolder exists $defc $draftf} result] && $result} { + div_folder $thispage $c $f $u $defc Drafts [WPCmd PEFolder unread $defc $draftf] $focused [cgi_span "class=sp splc splc2" ""] + } + + div_folder $thispage $c $f $u $defc Sent [WPCmd PEFolder unread $defc [var_value default-fcc]] $focused [cgi_span "class=sp splc splc3" ""] + + if {[info exists _wp(spamfolder)]} { + set current [current_context $thispage $c [wpSpecialFolder $c $f] $defc Junk] + cgi_division class="[context_class $current $focused]" { + cgi_put [cgi_span "xclass=left" [folder_link $current $thispage $defc Junk $u [WPCmd PEFolder unread $defc $_wp(spamfolder)] [cgi_span "class=sp splc splc4" ""]]] + cgi_put [cgi_span "class=right" [empty_link $current Junk $defc]] + } + } + + set current [current_context $thispage $c [wpSpecialFolder $c $f] $defc Trash] + cgi_division class="[context_class $current $focused]" id=targetTrash { + set trashf [var_value trash-folder] + cgi_put [cgi_span class=left [folder_link $current $thispage $defc Trash $u [WPCmd PEFolder unread $defc $trashf] [cgi_span "class=sp splc splc5" id=targetTrashIcon [cgi_span [cgi_nbspace]]]]] + cgi_put [cgi_span class=right [empty_link $current Trash $defc]] + if {0 == [string compare browse $thispage] && [string compare Trash $f]} { + lappend ddtargets [list targetTrash $defc $trashf] + } + } + cgi_division class="wap fld" { + cgi_put [cgi_nbspace] + } + + cgi_division class="[wpSelectedClass "0 == [string compare $thispage contacts]" 0 "fld"]" id=targetContacts { + set cUrl contacts + cgi_put [cgi_url "[cgi_span "class=sp splc splc6" ""][cgi_span Contacts]" $cUrl title="Contact List" class=wap [onClick $cUrl]] + if {0 == [string compare browse $thispage]} { + if {0 == [catch {WPCmd PEAddress books} booklist]} { + set tAFargs "\{books:\[" + set comma "" + foreach b $booklist { + regsub -all {'} [lindex $b 1] {\'} bname + append tAFargs "${comma}\{book:[lindex $b 0],name:'$bname'\}" + set comma "," + } + + append tAFargs "\]\}" + } else { + set tAFargs {{}} + } + + # pass address book list + cgi_puts "<script>setDragTarget('targetContacts',takeAddressFrom,$tAFargs);</script>" + } + } + cgi_division class="fld" { + cgi_put [cgi_nbspace] + } + cgi_division class="ftitle bld" { + cgi_put "Recent Folders" + } + + if {[catch {WPSessionState left_column_folders} fln]} { + set fln $_wp(fldr_cache_def) + } + + set nfl 0 + + foreach fce [getFolderCache] { + set fccol [lindex $fce 0] + set fcname [lindex $fce 1] + if {0 == [catch {WPCmd PEFolder exists $fccol $fcname} result] && $result} { + set current [current_context $thispage $c $f $fccol $fcname] + set folderID target$nfl + cgi_division class="[context_class $current $focused]" id=$folderID { + cgi_put [folder_link $current $thispage $fccol $fcname $u [WPCmd PEFolder unread $fccol $fcname] [cgi_span "class=sp splc splc7" id=${folderID}Icon [cgi_span [cgi_nbspace]]]] + if {0 == [string compare browse $thispage] && !($c == $fccol && 0 == [string compare $f $fcname])} { + lappend ddtargets [list $folderID $fccol $fcname] + } + } + } + + if {[incr nfl] >= $fln} { + break + } + } + + cgi_division class="wap fld" { + cgi_put [cgi_nbspace] + } + cgi_division class="[wpSelectedClass "0 == [string compare $thispage folders]" 0 "fld"]" { + set fUrl "folders" + cgi_put [cgi_url "[cgi_span "class=sp splc splc8" ""][cgi_span "View/Manage Folders..."]" $fUrl title="View, Create, Rename, and Delete Folders" class=wap [onClick $fUrl]] + } + } + } + } + } + + cgi_table_data class="spc" rowspan="2" { + cgi_put [cgi_span "class=sp trans" "style=height:2px;width:5px;" [cgi_span " "]] + } + + cgi_table_data width="100%" valign="top" { + cgi_table class="wap content" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data id=topToolbar class=wap { + cgi_anchor_name toolbar + uplevel 1 $menubar_top + } + } + + # display page content + cgi_table_row { + cgi_table_data height="100%" valign="top" { + cgi_division id=alpineContent { + uplevel 1 $content + } + } + } + + cgi_puts "</tbody>" + } + } + } + cgi_table_row { + cgi_table_data { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap txt" { + cgi_put "[cgi_span id=blankyblank "[cgi_nbspace]"]" + } + } + cgi_puts "</tbody>" + } + } + + cgi_table_data id=bottomToolbar class=wap valign="bottom" { + uplevel 1 $menubar_bottom + } + } + cgi_table_row { + cgi_table_data id=ftrContent colspan="3" class="wap footer" align="center" { + set ft "Powered by [cgi_url Alpine "http://www.washington.edu/alpine/" target="_blank"] - [cgi_copyright] 2007 University of Washington" + if {0 == [string compare browse $thispage]} { + append ft " - [cgi_url "HTML Version" "$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/wp.tcl"]" + } + + if {[info exists _wp(comments)] && [lsearch {browse view} $thispage] >= 0} { + append ft " - [cgi_url "Comments?" "mailto?to=$_wp(comments)&pop=browse/$c/[WPPercentQuote $f]"]" + } + + cgi_puts $ft + } + } + cgi_puts "</tbody>" + } + + if {[info exists ddtargets]} { + cgi_puts "<script>" + foreach t $ddtargets { + regsub -all {'} [lindex $t 2] {\'} fn + cgi_puts "setDragTarget('[lindex $t 0]',dragOntoFolder,{c:'[lindex $t 1]',f:'$fn'});" + } + cgi_puts "</script>" + } +} + +proc setCurrentFolder {_c _f _u} { + global _wp + + upvar 1 $_c c + upvar 1 $_f f + upvar 1 $_u u + + # verify current collection/folder + if {[catch {WPCmd PEFolder current} curfold]} { + set curc -1 + set curf "" + } else { + set curc [lindex $curfold 0] + set curf [lindex $curfold 1] + } + + # "current" folder's context + if {$c < 0} { + set c $curc + } + + # "current" folder + if {0 == [string length $f]} { + set f $curf + } + + if {[catch {WPCmd PEFolder defaultcollection} defc]} { + set defc 0 + } + + # open a different folder? + if {!($c == $curc && 0 == [string compare $f $curf])} { + # weed out special use folders + if {0 == $c && 0 == [string compare -nocase $f inbox]} { + set f INBOX + set truef INBOX + } else { + if {$c == $defc} { + switch -regexp -- $f { + {^Drafts$} { + set mode draft + catch {WPCmd set pre_draft_folder [WPCmd PEFolder current]} + set pf [var_value postponed-folder] + if {[string compare $curf $pf]} { + set truef $pf + if {[catch { + if {[WPCmd PEFolder exists $c $pf] <= 0} { + WPCmd PEFolder create $c $pf + } + } result]} { + WPCmd PEInfo statmsg $result + } + } + } + {^Trash$} { + set mode trash + set pf [var_value trash-folder] + if {[string compare $curf $pf]} { + set truef $pf + if {[catch { + if {[WPCmd PEFolder exists $c "$pf"] <= 0} { + WPCmd PEFolder create $c "$pf" + } + } result]} { + WPCmd PEInfo statmsg $result + } + } + } + {^Junk$} { + if {[info exists _wp(spamfolder)]} { + set mode junk + set pf $_wp(spamfolder) + if {[string compare $curf $pf]} { + set truef $pf + if {[catch { + if {[WPCmd PEFolder exists $c $pf] <= 0} { + WPCmd PEFolder create $c $pf + } + } result]} { + WPCmd PEInfo statmsg $result + } + } + } else { + set truef $f + } + } + {^Sent$} { + set mode sent + set pf [var_value default-fcc] + if {[string compare $curf $pf]} { + set truef $pf + if {[catch { + if {[WPCmd PEFolder exists $c $pf] <= 0} { + WPCmd PEFolder create $c $pf + } + } result]} { + WPCmd PEInfo statmsg $result + } + } + } + default { + set truef $f + } + } + } else { + set truef $f + } + } + + if {[info exists truef]} { + if {[catch {eval WPCmd PEMailbox open [list $c $truef]} reason]} { + error $reason + } else { + # do_broach handled this: WPCmd PEInfo statmsg "$f opened with [WPCmd PEMailbox messagecount] messages" + + if {![info exists mode]} { + addFolderCache $c $f + } + + if {[catch {WPCmd PEMailbox trashdeleted current} result]} { + WPCmd PEInfo statmsg "Detete FAILURE: $result" + } + } + } + } else { + # verify $c $f (and $u if present) exists + if {!($c == 0 && 0 == [string compare -nocase inbox $f])} { + if {[catch {WPCmd PEFolder exists $c $f} result]} { + WPCmd PEInfo statmsg "Cannot test $f for existance: $result" + } elseif {$result <= 0} { + WPCmd PEInfo statmsg "Folder $f in collection $c does not exist" + } + } + + if {$u > 0 && [catch {WPCmd PEMessage $u number} result]} { + WPCmd PEInfo statmsg "Message $u does not exist: $result" + } + } +} + +proc wpFolderMode {c f} { + if {$c == [WPCmd PEFolder defaultcollection]} { + switch -exact -- $f { + Drafts { return draft } + Sent { return sent } + Junk { return junk } + Trash { return trash } + } + } + + return "" +} + +proc wpInitPageFraming {_u _n _mc _ppg _pn _pt} { + upvar 1 $_u u + upvar 1 $_n n + upvar 1 $_mc mc + upvar 1 $_ppg ppg + upvar 1 $_pn pn + upvar 1 $_pt pt + + if {[catch {WPCmd PEMailbox trashdeleted current} result]} { + WPCmd PEInfo statmsg "Deleted move to Trash failed: $result" + } + + if {[catch {WPCmd PEMailbox focus} focused]} { + set focused 0 + } + + if {$n > 0} { + set pt [expr {$mc / $ppg}] + + if {$pt < 1} { + set pt 1 + } elseif {$mc % $ppg} { + incr pt + } + + if {$focused} { + set nth [WPCmd PEMailbox messagecount before $n] + incr nth + } else { + set nth $n + } + + if {$nth > $ppg} { + set pn [expr {$nth / $ppg}] + if {$nth % $ppg} { + incr pn + } + + set n [expr {(($pn - 1) * $ppg) + 1}] + if {$focused} { + set n [WPCmd PEMailbox next [WPCmd PEMailbox first] $n] + } + } else { + set pn 1 + set n [WPCmd PEMailbox first] + } + + set u [WPCmd PEMailbox uid $n] + } else { + set mc 0 + set pt 1 + set pn 1 + } +} + +proc wpHandleAuthException {err c {f ""}} { + global _wp + + if {[regexp {^CERTQUERY ([^+]+)\+\+(.*)$} $err dummy server reason]} { + return "code:'CERTQUERY',server:\"${server}\",reason:\"${reason}\"" + } elseif {[regexp {^CERTFAIL ([^+]+)\+\+(.*)$} $err dummy server reason]} { + return "code:'CERTFAIL',server:\"${server}\",reason:\"${reason}\"" + } elseif {[regexp {^NOPASSWD (.*)$} $err dummy server]} { + return "code:'NOPASSWD',c:[lindex $c 0],f:\"${f}\",server:\"{${server}/tls}\",reason:\"[lindex $c 1]\",sessid:\"$_wp(sessid)\"" + } elseif {[regexp {^BADPASSWD (.*)$} $err dummy server]} { + return "code:'BADPASSWD',c:[lindex $c 0],f:\"${f}\",server:\"{${server}/tls}\",reason:\"[lindex $c 1]\",sessid:\"$_wp(sessid)\"" + } + + return {} +} + +proc reportAuthException {exp} { + cgi_put "processAuthException(\{$exp\});" +} + +proc wpSaveMenuJavascript {p c f dc onDone {df ""}} { + set nn 0; + cgi_put "updateSaveCache(\"$p\",$c,\"$f\",$dc,$onDone,\[" + foreach {oname oval} [getSaveCache $df] { + if {[incr nn] > 1} { + cgi_put "," + } + + cgi_put "{fn:\"$oname\",fv:\"$oval\"}" + } + cgi_puts "\]);" +} + +proc wpLiteralFolder {c f} { + global _wp + + if {$c == [WPCmd PEFolder defaultcollection]} { + switch -exact -- $f { + Draft { + return [var_value postponed-folder] + } + Sent { + return [var_value default-fcc] + } + Junk { + if {[info exists _wp(spamfolder)]} { + return $_wp(spamfolder) + } + } + Trash { + return [var_value trash-folder] + } + } + } + + return $f +} + +proc wpSpecialFolder {c f} { + global _wp + + if {$c == [WPCmd PEFolder defaultcollection]} { + if {0 == [string compare $f [var_value postponed-folder]]} { + return Draft + } + + if {0 == [string compare $f [var_value default-fcc]]} { + return Sent + } + if {[info exists _wp(spamfolder)]} { + if {0 == [string compare $f $_wp(spamfolder)]} { + return Junk + } + } + if {0 == [string compare $f [var_value trash-folder]]} { + return Trash + } + } + + return $f +} diff --git a/web/cgi/alpine/2.0/compose b/web/cgi/alpine/2.0/compose new file mode 100755 index 00000000..bf6ce9ec --- /dev/null +++ b/web/cgi/alpine/2.0/compose @@ -0,0 +1,817 @@ +#!./tclsh +# $Id: compose 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# compose +# +# Purpose: CGI script template for Web Alpine 2.0 pages +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_viewed_msg> +# along with possible search parameters: +set compose_args { + {pop {} browse/0/INBOX} + {repqstr "" "_NONE_SET_"} + {contacts "" ""} +} + +# inherit global config +source ./alpine.tcl +source ./foldercache.tcl +source ./common.tcl + +set script_base "$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + +# TEST +proc cgi_suffix {args} { + return "" +} + +if {[info exists debugging]} { + # WHILE TESTING/DEBUGGING + set dmsgs "" + proc dm {s} { + global dmsgs + + lappend dmsgs $s + } +} + +# On input failure, redirect to home page "browse" +proc browse_redirect {} { + cgi_http_head { + cgi_redirect browse + } +} + +proc url {d} { + global _wp + + return [file join / $_wp(urlprefix) $_wp(appdir) $_wp(ui2dir) $d] +} + +proc leave_test {d} { + return "return cancelComposition('[url $d]');" +} + +proc fieldname {name} { + regsub -all -- {-} [string tolower $name] {_} fieldname + return $fieldname +} + +proc default_fcc {itemval} { + global fccdefault f_name f_colid + + if {[catch {WPCmd PEFolder collections} collections]} { + set collections "" + } + + # fcc's itemval should be a list of collection-id and folder-name + if {[llength $itemval] == 2} { + set fcccol [lindex $itemval 0] + set fccname [lindex $itemval 1] + } elseif {[info exists f_name] && [string length $f_name]} { + set fcccol $f_colid + set fccname $f_name + } elseif {[info exists fccdefault] || [catch {WPCmd PECompose fccdefault} fccdefault] == 0} { + set fcccol [lindex $fccdefault 0] + set fccname [lindex $fccdefault 1] + unset fccdefault + } else { + set fccname sent-mail + if {[llength $collections] > 1} { + set fcccol 1 + } else { + set fcccol 0 + } + } + + return [list $fccname $fcccol $collections] +} + +set firstheader 1 +proc rowfield {item itemval} { + global _wp addrheaders firstheader compose_mode + + if {0 == [string compare [string tolower $item] attach]} { + return + } + + set isaddr [lsearch -exact $addrheaders [string tolower $item]] + + cgi_table_row { + cgi_table_data class="spc" colspan="3" {} + } + cgi_table_row { + cgi_table_data class="wap lbl" { + cgi_anchor_name "to" + if {$isaddr >= 0} { + cgi_button "${item}..." title="Select email addresses from Contacts or Directory" "onClick=return pickContact('$item','field${item}');" + } elseif {0 == [string compare [string tolower $item] fcc]} { + cgi_button "Fcc..." title="Carbon Copy to Folder" "onClick=this.blur(); return pickFolder('folderList','Set Fcc','[WPCmd PEFolder defaultcollection]',pickFccDone);" + } else { + cgi_put "<label for=\"[string tolower $item]\">$item:</label>" + + } + } + cgi_table_data class="wap mid" { + if {$isaddr >= 0} { + cgi_textarea [string tolower $item]=$itemval class="mid" id="field$item" + cgi_division id="container$item" class="yui-skin-sam" {} + } else { + switch -- [string tolower $item] { + fcc { + set deffcc [default_fcc $itemval] + + set fccname [lindex $deffcc 0] + set fcccol [lindex $deffcc 1] + + cgi_text "[fieldname $item]=$fccname" id="field$item" class="mid" "onBlur=fccExists(false);" + cgi_text "colid=$fcccol" type=hidden "notab" id="fieldFccCollection" + } + default { + cgi_text "[fieldname $item]=$itemval" id="field$item" class="mid" + } + } + } + } + cgi_table_data class="wap rgt" { + if {$firstheader} { + set firstheader 0 + cgi_put "[cgi_span id="moreComposeHeaderText" [cgi_url "More Headers" "#" "onClick=showMoreComposeHeaders(); return false;" title="Show Bcc:, Fcc:, ..."]]" + cgi_put "[cgi_span id="lessComposeHeaderText" [cgi_url "Fewer Headers" "#" "onClick=showLessComposeHeaders(); return false;"]]" + } + if {0 && 0 == [string compare [string tolower $item] fcc]} { + cgi_puts [cgi_url "[cgi_nbspace]Select Folder" "#" "onClick=this.blur(); pickFolder('folderList','Set Fcc','[WPCmd PEFolder defaultcollection]',pickFccDone); return false;"] + } elseif {0 == [string compare [string tolower $item] subject]} { + if {[string compare -nocase rich $compose_mode]} { + set flipto Rich + } else { + set flipto Plain + } + cgi_put [cgi_url "$flipto Text" "" id=flipRich "onClick=return flipRichText();"] + } + } + } +} + +set c -1 +set f "" +set u 0 +set p "" +set body "" +set defaultheaders {to cc subject} +set addrheaders {to cc bcc} +set entryfocus fieldTo +set title Compose + +WPEval $compose_args { + + set compose_mode plain + + # figure out compose mode and collect necessary stuff + if {[regexp {/(reply|replyall|forward|resume|mailto)$} $env(SCRIPT_NAME) dummy mode]} { + if {0 == [string compare resume $mode]} { + if {[info exists env(PATH_INFO)]} { + if {[regexp {^/([0-9]+)$} $env(PATH_INFO) dummy u]} { + set title "Resume Draft" + set c [WPCmd PEFolder defaultcollection] + set f Drafts + if {[catch {WPCmd PEPostpone extract $u {html}} postponed]} { + WPCmd PEInfo statmsg "Cannot get Draft: $postponed" + } else { + foreach h [lindex $postponed 0] { + append hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + # return to message's edit mode + set compose_mode plain + + foreach opt [lindex $postponed 3] { + switch [lindex $opt 0] { + charset { + set charset [lindex $opt 1] + } + subtype { + if {0 == [string compare -nocase [lindex $opt 1] html]} { + set compose_mode rich + } + } + } + } + + set body [join [lindex $postponed 1] "\r\n"] + set attachments [lindex $postponed 2] + + unset postponed + + catch {WPCmd set help_context compose} + if {[catch {WPCmd set pre_draft_folder} curfold]} { + set pop "browse/0/INBOX" + } else { + set pop "browse/[lindex $curfold 0]/[wpSpecialFolder [lindex $curfold 0] [lindex $curfold 1]]" + } + } + } else { + WPCmd PEInfo statmsg "Invalid Draft UID: $env(PATH_INFO)" + browse_redirect + cgi_exit + } + } else { + WPCmd PEInfo statmsg "Missing Draft UID" + browse_redirect + cgi_exit + } + } elseif {0 == [string compare mailto $mode]} { + set title "Compose" + + if {[catch {cgi_import to}] == 0} { + set hdrvals(to) $to + } + + if {[catch {cgi_import cc}] == 0} { + set hdrvals(to) $cc + } + + if {[catch {cgi_import subject}] == 0} { + set hdrvals(subject) $subject + } + + catch {cgi_import body} + } else { + if {!([info exists env(PATH_INFO)] && [regexp {^/([0-9]+)/(.+)/([0-9]+)[/]?([\.0-9]*)*} $env(PATH_INFO) dummy c f u p])} { + WPCmd PEInfo statmsg "Invalid Invocation: $env(SCRIPT_NAME) (info = $env(PATH_INFO)" + browse_redirect + cgi_exit + } + + # process action specfied by compose_args + switch $mode { + reply - + replyall { + set title "Reply to Message [WPCmd PEMessage $u number]" + if {[string length $p]} { + append title ", part $p" + } + + foreach h [WPCmd PEMessage $u replyheaders $p] { + set hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + if {[string compare $mode replyall]} { + catch {unset hdrvals(cc)} + } + + if {[WPCmd PEInfo feature quell-format-flowed] == 0} { + set flowed 1 + } + + if {0 == [string compare $repqstr "_NONE_SET_"]} { + set repqstr [WPCmd PEMessage $u replyquote] + } + + set replytext [WPCmd PEMessage $u replytext $repqstr $p] + + if {[string compare $compose_mode plain]} { + set replytext [cgi_quote_html $replytext] + set body [join [lindex $replytext 0] "<br />"] + } else { + set body [join [lindex $replytext 0] "\n"] + } + + if {[WPCmd PEInfo feature include-attachments-in-reply]} { + set attachments [lindex $replytext 1] + } + + catch {WPCmd set help_context reply} + set cuid $u + set entryfocus composeText + } + forward { + set title "Forward [WPCmd PEMessage $u number]" + if {[string length $p]} { + append title ", part $p" + } + + foreach h [WPCmd PEMessage $u forwardheaders $p] { + set hdrvals([fieldname [lindex $h 0]]) [lindex $h 1] + } + + foreach line [WPCmd PEInfo signature] { + append body "$line\r\n" + } + + if {[WPCmd PEInfo feature quell-format-flowed] == 0} { + set flowed 1 + } + + set forwardtext [WPCmd PEMessage $u forwardtext $p] + + if {[string compare $compose_mode plain]} { + set forwardtext [cgi_quote_html $forwardtext] + append body [join [lindex $forwardtext 0] "<br />"] + } else { + append body [join [lindex $forwardtext 0] "\r\n"] + } + + set attachments [lindex $forwardtext 1] + catch {WPCmd set help_context forward} + set cuid $u + } + } + } + } else { + foreach line [WPCmd PEInfo signature] { + append body "$line\r\n" + } + + if {[string length $contacts] && [regexp {^[0-9\.,]+$} $contacts]} { + set hdrvals(to) "" + foreach c [split $contacts ","] { + if {[regexp {^([0-9]+)\.([0-9]+)$} $c dummy abook aindex]} { + # compose to address book entry + if {0 == [catch {WPCmd PEAddress entry $abook "" $aindex} entryval]} { + if {[string length $hdrvals(to)]} { + append hdrvals(to) ", " + } + + append hdrvals(to) [lindex $entryval 0] + set newfcc [lindex $entryval 1] + if {[string length $newfcc]} { + global fccdefault + if {[string compare $newfcc "\"\""] == 0} { + set newfcc "" + } + if {[catch {WPCmd PEFolder collections} collections]} { + set collections "" + } + set fccdefault [list [expr {[llength $collections] > 1 ? 1 : 0}] $newfcc] + } + } + } + } + } + + WPCmd PECompose noattach + } + + if {[catch {WPCmd PECompose userhdrs} headers]} { + error [list _action "Header Retrieval Failure" $headers] + } + + if {![info exists charset]} { + set charset UTF-8 + } + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=\"$charset\"" + } + + cgi_html { + cgi_head { + cgi_http_equiv Content-Type "text/html; charset=$charset" + cgi_title [wpPageTitle "$title"] + cgi_base "href=$script_base" + # yui css + cgi_stylesheet "$_wp(yui)/build/autocomplete/assets/skins/sam/autocomplete.css" + cgi_stylesheet "$_wp(yui)/build/tabview/assets/tabview-core.css" + cgi_stylesheet "$_wp(yui)/build/button/assets/skins/sam/button.css" + cgi_stylesheet "$_wp(yui)/build/container/assets/skins/sam/container.css" + cgi_stylesheet "$_wp(yui)/build/editor/assets/skins/sam/simpleeditor.css" + # local css + cgi_stylesheet css/cbn/screen.css + cgi_stylesheet css/menu.css + cgi_stylesheet css/cbn/folderdialog.css + cgi_stylesheet css/cbn/contactdialog.css + cgi_puts "<style type='text/css'>" + cgi_puts ".yui-skin-sam .yui-ac-content{ width:70%; }" + cgi_puts ".yui-navset .yui-nav li { margin-right:0.16em; padding-top:1px; zoom:1; }" + cgi_puts ".yui-navset .yui-nav .selected { margin-bottom:-1px; }" + cgi_puts ".yui-navset .yui-nav a { background:#dadbdb url($_wp(yui)/build/assets/skins/sam/sprite.png) repeat-x; border:solid #a3a3a3; border-width:0 1px; color:#000; text-decoration:none; }" + cgi_puts ".yui-navset .yui-nav li a em { border-top:solid 1px #a3a3a3; border-bottom:0; cursor:hand; padding:0.2em 0.5em; top:-1px; position:relative; }" + cgi_puts ".yui-navset .yui-nav .selected a, .yui-navset .yui-nav a:focus, .yui-navset .yui-nav a:hover { background:#214197 url($_wp(yui)/build/assets/skins/sam/sprite.png) repeat-x left -1400px; color:#fff; }" + cgi_puts ".yui-navset .yui-nav .selected a em { padding:0.3em 0.5em; }" + cgi_puts ".yui-navset .yui-nav .selected a, .yui-navset .yui-nav a:hover, .yui-navset .yui-nav a:focus { border-color:#243356; }" + cgi_puts ".yui-navset .yui-nav a:hover em, .yui-navset .yui-nav a:focus em, .yui-navset .yui-nav .selected a em { border-color:#233356 #406ed9; }" + cgi_puts ".yui-navset .yui-nav { border-bottom:1px solid #243356; position:relative; zoom:1; }" + cgi_puts ".yui-navset .yui-content { border-top:5px solid #214095; }" + cgi_puts "</style>" + # Yahoo UI Libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/get/get-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/autocomplete/autocomplete-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/tabview/tabview-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/editor/simpleeditor-min.js" {} + # local libraries + cgi_script language="JavaScript" src="lib/common.js" {} + cgi_script language="JavaScript" src="lib/compose.js" {} + # page/content specific + cgi_javascript { + cgi_puts "YAHOO.alpine.cgi_root = '$_wp(serverpath)';" + cgi_puts "YAHOO.alpine.cgi_base = '$script_base';" + if {0 == [catch {WPCmd PEFolder current} curfold]} { + cgi_puts "YAHOO.alpine.current.c = [lindex $curfold 0];" + cgi_puts "YAHOO.alpine.current.f = \"[lindex $curfold 1]\";" + } + cgi_puts "var gRichState = ('$compose_mode' == 'rich');" + cgi_puts "var gRichtextEditor, gRichtextRendered = false;" + cgi_puts "var gFieldHeight = 0;" + cgi_puts "var gDefCol = [WPCmd PEFolder defaultcollection];" + cgi_puts "var gDraftFolder = '[var_value postponed-folder]';" + + # set up contacts dialog + set markup [cgi_buffer { + cgi_division id="contactsDialogFramework" { + set dirs [catch {WPCmd PELdap directories} directories] + if {0 == $dirs} { + set class "class=yui-navset" + } else { + set class "" + } + + cgi_division id="contactDialog" $class { + if {0 == $dirs} { + cgi_bullet_list class="yui-nav" { + cgi_li class="selected" [cgi_url [cgi_emphasis Contacts] "#contactList" "onClick=this.blur();"] + cgi_li [cgi_url [cgi_emphasis Directory] "#directoryQuery" "onClick=this.blur();"] + } + cgi_division class=yui-content { + cgi_division id="contactList" class="contactContent" { + cgi_put "Loading..." + } + cgi_division id="directoryQuery" class=contactContent { + cgi_division class="clistContext" "style=\"text-align: center;\"" { + cgi_form $_wp(appdir)/$_wp(ui2dir)/conduit/query.tcl method=get target=formResponse { + if {[llength $directories] > 1} { + cgi_select dir class=wap { + for {set i 0} {$i < [llength $directories]} {incr i} { + set dname [lindex [lindex $directories $i] 0] + if {0 == [string length $dname]} { + set dname "Directory [expr {$i + 1}]" + } + cgi_option $dname value=$i + } + } + } else { + if {[string length [lindex [lindex $directories 0] 0]]} { + cgi_put [cgi_span [lindex [lindex $directories 0] 0]] + } + + cgi_text "dir=0" type=hidden "notab" + } + + cgi_text "query=" size="20" length="40" id="dirQuery" + cgi_submit_button go=Search + } + } + cgi_division id="dirResult" class="clistContacts" { + cgi_put [cgi_span "Search results appear here..."] + } + } + } + } else { + cgi_division id="contactList" class="contactContent" { + cgi_put "Loading..." + } + } + } + } + }] + + regsub -all {'} $markup {\'} markup + regsub -all {\n} $markup {} markup + cgi_puts "YAHOO.alpine.pickcontact.markup = '$markup';" + cgi_puts "function bodyOnLoad() {" + cgi_puts " initMenus();" + cgi_puts " if(gRichState){ initSimpleEditor([expr {0 == [string compare $entryfocus composeText]}]); if(gRichtextEditor){ gRichtextEditor.render(); gRichtextRendered = true; }}" + cgi_puts " autoSizeAddressField('fieldTo');" + cgi_puts " autoSizeAddressField('fieldCc');" + cgi_puts " autoSizeAddressField('fieldBcc');" + cgi_puts " setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + if {[info exists _wp(autodraft)]} { + cgi_puts " setAutoDraftInterval($_wp(autodraft));" + } + wpStatusAndNewmailJavascript + cgi_puts " setCursorPosition('$entryfocus',0);" + cgi_puts " fccExists(true);" + cgi_puts "}" + + cgi_puts "browserDetect();" + } + } + + cgi_body class="wap" "onLoad=bodyOnLoad()" { + cgi_division id="skip" { + cgi_put [cgi_url "Skip to Compose Body" "#to"] + cgi_put [cgi_url "Skip to Message List" "browse#messages"] + cgi_put [cgi_url "Skip to Folders" "#folders"] + } + + cgi_puts {<iframe name="formResponse" id="formResponse" src="img/cbn/spritelib.gif"></iframe>} + + wpCommonPageLayout compose "$c" "$f" "$u" \ + $title \ + [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/browse/${c}/${f}"] Composition 0] \ + leave_test\ + { + cgi_division class=hdrBtns { + cgi_javascript { + cgi_put "if(window.print) document.write('[cgi_buffer {cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"]}]');" + } + + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" "javascript:openHelpWindow('compose.html');" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "" "onClick=[leave_test "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"]"] + } + } { + cgi_anchor_name "toolbar" + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb9" "Send"] "post" "onClick=return sendComposition();"] + } + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb11" "Attach File"] "" "onClick=this.blur(); return addAttachField();"] + } + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb10" "Save Draft"] post/draft "onClick=return saveDraft();"] + } + cgi_table_data class="wap dv1" { + cgi_put [cgi_img "img/cbn/div.gif"] + } + cgi_table_data class="wap yui-skin-sam yuimenu" id="priorityButtonContainer" { + cgi_bullet_list class="wap menu" { + cgi_put "<li class=\"menuHdr\">[cgi_url "Priority [cgi_img "img/cbn/menu.gif" class="wap menuDn menuImg"]" "#" "onClick=return false;"]" + cgi_division { + cgi_bullet_list class=priority { + cgi_li [cgi_url "[cgi_span "class=sp spfcl blank" ""]Highest" "" id="pri5" "onClick=return setPriority(this,'highest')"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl blank" ""]High" "" id="pri4" "onClick=return setPriority(this,'high')"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl blank" ""]Normal" "" id="pri3" "onClick=return setPriority(this,'normal')"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl blank" ""]Low" "" id="pri2" "onClick=return setPriority(this,'low')"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl blank" ""]Lowest" "" id="pri1" "onClick=return setPriority(this,'lowest')"] + cgi_li "<hr />[cgi_url "[cgi_span "class=sp spfcl spfcl3" ""]No[cgi_nbspace]Priority" "" id="pri0" "onClick=return setPriority(this,'')"]" + } + } + cgi_put "</li>" + } + } + cgi_table_data class="wap dv1" { + cgi_put [cgi_img "img/cbn/div.gif"] + } + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb12" "Cancel"] "$pop" "onClick=return cancelComposition('[url $pop]');" title="Cancel Compose and lose unsaved changes"] + } + cgi_table_data class="wap" width="100%" { + cgi_put [cgi_nbspace] + } + cgi_table_data class="wap tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } { + cgi_form $_wp(appdir)/$_wp(ui2dir)/conduit/post.tcl "enctype=multipart/form-data" id=composeForm target=formResponse { + cgi_table width="100%" height="100%" cellpadding="0" cellspacing="0" id=compositionBody { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data { + cgi_table class="compose" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="spc" colspan="3" { + # various bits of what we need to pass on + cgi_text "cid=[WPCmd PEInfo key]" type=hidden "notab" + cgi_text "sessid=$sessid" type=hidden "notab" + cgi_text "postpost=$pop" type=hidden "notab" + cgi_text "subtype=plain" type=hidden id=contentSubtype notab + cgi_text "priority=0" type=hidden id=priority "notab" + + # TEST stuff we have to feed post.tcl to get it working + cgi_text "action=OK" type=hidden "notab" + cgi_text "send=1" type=hidden "notab" + cgi_text "sendop=send" type=hidden id=sendOp notab + cgi_text "autodraftuid=0" type=hidden id=autoDraftUid notab + + if {[string length $repqstr]} { + cgi_text "repqstr=$repqstr" type=hidden "notab" + } + + if {[info exists flowed]} { + cgi_text "form_flowed=yes" type=hidden "notab" + } + + foreach field [WPCmd PECompose syshdrs] { + set hdr [fieldname [lindex $field 0]] + if {[info exists hdrvals($hdr)]} { + cgi_text "${hdr}=$hdrvals($hdr)" type=hidden "notab" + } + } + } + } + + set extrahdrs {} + + foreach field $headers { + set item [lindex $field 0] + + if {[string length $item] == 0} { + continue + } + + set itemvaldef [lindex $field 1] + set litem [string tolower $item] + set fn [fieldname $item] + + if {[info exists hdrvals($fn)]} { + set itemval $hdrvals($fn) + } elseif {[info exists $litem] && [string length [subst $$litem]]} { + set itemval [subst $$litem] + } elseif {[string length $itemvaldef]} { + set itemval $itemvaldef + } else { + set itemval "" + } + + if {[catch {WPCmd PECompose composehdrs} h] == 0 && [llength $h] > 0} { + set display_headers [string tolower $h] + } else { + set display_headers $defaultheaders + } + + if {![info exists extrahdrs]} { + if {[info exists postoption(fcc-set-by-addrbook)]} { + if {[lsearch -exact $display_headers fcc] < 0} { + lappend display_headers fcc + } + } + } + + if {[lsearch -exact $display_headers [string tolower $item]] >= 0} { + rowfield $item $itemval + } elseif {[info exists extrahdrs]} { + lappend extrahdrs [list $item $itemval] + } else { + switch -- [string tolower $item] { + fcc { + set deffcc [default_fcc $itemval] + + set fccname [lindex $deffcc 0] + set fcccol [lindex $deffcc 1] + + cgi_text [fieldname $item]=$fccname type=hidden "notab" + cgi_text "colid=$fcccol" type=hidden "notab" + } + default { + cgi_text "[fieldname $item]=$itemval" type=hidden "notab" + } + } + } + } + + cgi_puts "</tbody>" + } + + if {[info exists extrahdrs]} { + cgi_division id="moreComposeHeaders" { + cgi_table class="wap compose" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + + foreach pb $extrahdrs { + rowfield [lindex $pb 0] [lindex $pb 1] + } + + cgi_puts "</tbody>" + } + } + } + + cgi_division id="composeAttachments" { + cgi_table class="wap compose" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap spc" colspan="2" {} + } + cgi_table_row { + cgi_table_data class="wap lbl" { + cgi_puts "<label>Attachments: </label>" + } + cgi_table_data class="wap attach" { + cgi_text "attachments=" type=hidden id=attachments notab + cgi_division id=attachList { + } + cgi_division id=fileUpload { + } + } + } + cgi_table_row { + cgi_table_data class="wap spc" colspan="2" { + + if {[info exists postoption(fcc-without-attachments)]} { + if {$postoption(fcc-without-attachments)} { + set checked "" + } else { + set checked checked + } + } elseif {[WPCmd PEInfo feature "fcc-without-attachments"]} { + set checked "" + } else { + set checked checked + } + + cgi_checkbox fccattach=1 $checked id="fcc_attachment" + cgi_puts "<label for='fcc_attachment'>Include attachments in copy of message saved to Fcc (i.e. sent-mail)</label>" + } + } + } + } + cgi_javascript { + if {[info exists attachments]} { + set comma "" + cgi_puts "drawAttachmentList({attachments:\[" + foreach a $attachments { + # {4137457288 bunny.gif 2514 Image/GIF} + cgi_puts "${comma}{id:'[lindex $a 0]',fn:'[lindex $a 1]',size:'[lindex $a 2]',type:'[lindex $a 3]'}" + set comma "," + } + cgi_puts "\]});" + } + } + } + } + cgi_table_row { + cgi_table_data height="100%" { + cgi_table class="composeBody" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="yui-skin-sam textBody" { + cgi_textarea body=$body id=composeText title="Message Body" rows="25" + } + } + cgi_puts "</tbody>" + } + } + } + cgi_puts "</tbody>" + } + } + } { + cgi_table class="wap toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data id=lastAutoDraft class="wap pageText" { + } + cgi_table_data class=wap width="100%" { + cgi_put [cgi_nbspace] + } + cgi_table_data class="wap tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } + + # autosize and autocompletion + cgi_javascript { + cgi_puts "var gACDataServer = '$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/conduit/complete.tcl';" + cgi_puts { + gACDataSource = new YAHOO.widget.DS_XHR(gACDataServer,['Result','Email','Nickname','Fcc']); + gACDataSource.responseType = YAHOO.widget.DS_XHR.TYPE_XML; + } + if {[info exists cuid] || [regexp {view/.*/([0-9]+)$} $pop dummy cuid]} { + cgi_puts " gACDataSource.scriptQueryAppend = 'uid=$cuid';" + } + cgi_puts { + var gAutoCompleteTo = new YAHOO.widget.AutoComplete('fieldTo','containerTo',gACDataSource); + autoCompleteDefaults(gAutoCompleteTo); + var gAutoCompleteCc = new YAHOO.widget.AutoComplete('fieldCc','containerCc',gACDataSource); + autoCompleteDefaults(gAutoCompleteCc); + var gAutoCompleteBcc = new YAHOO.widget.AutoComplete('fieldBcc','containerBcc',gACDataSource); + autoCompleteDefaults(gAutoCompleteBcc); + } + } + + if {[info exists debugging]} { + # any debugging info to insert? + + foreach dmsg $dmsgs { + cgi_html_comment "DEBUG: $dmsg" + cgi_puts "" + } + } + } + } +} diff --git a/web/cgi/alpine/2.0/conduit/apply.tcl b/web/cgi/alpine/2.0/conduit/apply.tcl new file mode 100755 index 00000000..d93ab0d7 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/apply.tcl @@ -0,0 +1,76 @@ +#!./tclsh +# $Id: apply.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# apply +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set apply_args { + {f {} ""} + {s {} ""} +} + +# inherit global config +source ../alpine.tcl + + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $apply_args { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + exit + } +} + +switch -- $f { + {new} - + {imp} - + {del} { + set flag $f + } + default { + } +} + +switch -- $s { + ton - + not { + set state $s + } + default { + } +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"" +cgi_puts "" +if {[catch { + if {[info exists flag] && [info exists state]} { + if {[catch {WPCmd PEMailbox apply flag $state $flag} result]} { + error "Apply $state ${flag}: $result" + } else { + set response "$result [WPCmd PEMailbox selected] [WPCmd PEMailbox messagecount]" + cgi_puts $response + } + } else { + WPCmd PEInfo statmsg "Unknown flag ($f) or state ($s)" + } +} result]} { + cgi_puts "failed: $result" +} diff --git a/web/cgi/alpine/2.0/conduit/attach.tcl b/web/cgi/alpine/2.0/conduit/attach.tcl new file mode 100755 index 00000000..924fd148 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/attach.tcl @@ -0,0 +1,101 @@ +#!./tclsh +# $Id: attach.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# attach.tcl +# +# Purpose: CGI script to handle attaching attachment +# to composition via queryattach generated form +# +# Input: +set attach_vars { + {file "" ""} + {description "" ""} + {op "" ""} + {id "" 0} +} + +# Output: + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $attach_vars { + if {[catch {eval WPImport $item} errstr]} { + lappend errs $errstr + } +} + +if {[string length $file] && [string length [lindex $file 1]]} { + + # "file" is a list: local_file remote_file content-type/content-subtype + # trim path from file name on remote system + # since we can't be certain what the delimiter is, + # try the usual suspects + set delims [list "\\" "/" ":"] + set native [lindex $file 1] + if {[string length $native]} { + foreach delim $delims { + if {[set crop [string last $delim $native]] >= 0} { + set native [string range $native [expr {$crop + 1}] [string length $native]] + break; + } + } + + regsub -all "'" $native "\\'" jsnative + + if {0 == [string length [lindex $file 2]]} { + set conttype [list text plain] + } else { + set conttype [split [lindex $file 2] "/"] + } + + set id [WPCmd PECompose attach [lindex $file 0] [lindex $conttype 0] [lindex $conttype 1] $native $description] + } else { + lappend errs "Requested attachment does not exist" + } +} elseif {![string compare delete $op]} { + if {[catch {WPCmd PECompose unattach $id} result]} { + lappend errs $result + } +} + + + +# return attachment list +puts stdout "Content-type: text/html;\n\n<html><head><script>window.parent.drawAttachmentList(\{" +if {0 == [catch {WPCmd PECompose attachments} attachments]} { + puts stdout "attachments:\[" + set comma "" + foreach a $attachments { + # {4137457288 bunny.gif 2514 Image/GIF} + puts stdout "${comma}\{id:\"[lindex $a 0]\",fn:\"[lindex $a 1]\",size:\"[lindex $a 2]\",type:\"[lindex $a 3]\"\}" + set comma "," + } + puts stdout "\]" + set comma "," +} else { + set comma "" + lappend errs $attachments +} + +if {[info exists errs]} { + puts stdout "${comma}error:\"[join $errs {, }]\"" +} + +puts stdout "\});</script></head><body></body></html>" diff --git a/web/cgi/alpine/2.0/conduit/cert.tcl b/web/cgi/alpine/2.0/conduit/cert.tcl new file mode 100755 index 00000000..a3a4a28c --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/cert.tcl @@ -0,0 +1,48 @@ +#!./tclsh +# $Id: cert.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# cert.tcl +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set cert_args { + {server {} ""} + {accept {} "no"} +} + +# inherit global config +source ../alpine.tcl + + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $cert_args { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + return + } +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" +set answer "Server certificate declined" +if {[string compare $accept yes] || [catch {WPCmd PESession acceptcert $server} answer]} { + cgi_puts "PROBLEM: $answer" +} else { + cgi_puts "$answer" +} diff --git a/web/cgi/alpine/2.0/conduit/complete.tcl b/web/cgi/alpine/2.0/conduit/complete.tcl new file mode 100755 index 00000000..1fd009a0 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/complete.tcl @@ -0,0 +1,54 @@ +#!./tclsh +# $Id: complete.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# complete +# +# Purpose: CGI script to supply data to YUI AutoComplete +# +# Input: +# along with possible search parameters: +set complete_args { + {param {} ""} + {query {} ""} + {uid {} 0} +} + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $complete_args { + if {[catch {eval WPImport $item} errstr]} { + error $errstr + } +} + +if {[catch {WPCmd PEAddress complete $query $uid} result]} { + error "complete: $result" +} + +puts stdout "Content-type: text/xml; charset=\"UTF-8\"" +puts stdout "" +puts stdout {<?xml version="1.0" encoding="UTF-8"?>} +puts stdout "<ResultSet totalResultsAvailable=\"[llength $result]\">" +if {[string length $query]} { + foreach abe $result { + puts stdout "<Result><Nickname>[cgi_quote_html [lindex $abe 0]]</Nickname><Email>[cgi_quote_html [lindex $abe 1]]</Email><Fcc>[cgi_quote_html [lindex $abe 2]]</Fcc></Result>" + } +} +puts stdout {</ResultSet>} diff --git a/web/cgi/alpine/2.0/conduit/contactlist.tcl b/web/cgi/alpine/2.0/conduit/contactlist.tcl new file mode 100755 index 00000000..efac458b --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/contactlist.tcl @@ -0,0 +1,306 @@ +#!./tclsh +# $Id: contactlist.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# contactlist.tcl +# +# Purpose: CGI script that generates a page displaying a +# list of contacts in the requested address book +# +# Input: PATH_INFO: /booknumber +# along with possible search parameters: +set contactlist_args { + {op {} "noop"} + {book "" 0} + {ai "" -1} + {entryList "" ""} + {contactNick "" ""} + {origNick "" ""} + {contactName "" ""} + {contactEmail "" ""} + {contactFcc "" ""} + {contactNotes "" ""} + {hdr {} "off"} + {sendto {} "off"} + {canedit {} "off"} +} + +# inherit global config +source ../alpine.tcl +source ../common.tcl + +# TEST +proc cgi_suffix {args} { + return "" +} + +proc deleteByBook {_delbooks} { + upvar 1 $_delbooks delbooks + foreach dbn [array names delbooks] { + foreach dbi [lsort -integer -decreasing $delbooks($dbn)] { + if {[catch {WPCmd PEAddress delete $dbn "" $dbi} result]} { + error "Address Delete Failure: $result" + } + } + } +} + +proc newContactJSObject {} { + uplevel 1 { + set json {} + + foreach k {hdr sendto canedit} { + set v [subst $$k] + + if {[string length $json]} { + append json "," + } + + if {[string length $v]} { + append json "${k}:'${v}'" + } + } + + return "\{${json}\}" + } +} + +if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {[regexp {^/([0-9]+|-1)$} $env(PATH_INFO) dummy abook]} { + # Import data validate it and get session id + if {[catch {WPGetInputAndID sessid}]} { + set harderr "No Session ID: $sessid" + } else { + # grok parameters + foreach item $contactlist_args { + if {[catch {eval WPImport $item} importerr]} { + set harderr "Cannot init session: $importerr" + break + } + } + } + } else { + set harderr "Bad Address Book Request: $env(PATH_INFO)" + } +} else { + set harderr "No Address Book Specified" +} + +puts stdout "Content-type: text/html; charset=\"UTF-8\"\n" + +if {[info exists harderr]} { + puts stdout "<b>ERROR: $harderr</b>" + exit +} + +switch -- $op { + delete { + set result "" + # grok delete format: \[(book)index\], + if {[regexp {^[0-9\.,]+$} $entryList]} { + # collect by book + set entryList [split $entryList ","] + foreach e $entryList { + if {[regexp {^([0-9]+)\.([0-9]+)} $e dummy eb ei]} { + lappend delbooks($eb) $ei + } + } + + # delete by book in DECREASING index order + if {[catch {deleteByBook delbooks} result] || [string length $result]} { + WPCmd PEInfo statmsg "$result" + } else { + if {[llength $entryList] > 1} { + WPCmd PEInfo statmsg "Contacts Deleted" + } else { + WPCmd PEInfo statmsg "Contact Deleted" + } + } + } else { + WPCmd PEInfo statmsg "Invalid entry list format: >>>>$entryList<<<<" + } + } + add { + if {[catch {WPCmd PEAddress edit $book $contactNick $ai $contactName $contactEmail $contactFcc $contactNotes 1} result]} { + WPCmd PEInfo statmsg "Add failed: $result" + } + } + change { + if {[catch {WPCmd PEAddress edit $book $contactNick $ai $contactName $contactEmail $contactFcc $contactNotes 0 $origNick} result]} { + WPCmd PEInfo statmsg "Change failed: $result" + } + } + noop { + } + default { + WPCmd PEInfo statmsg "Unrecognized option: $op" + } +} + +# remainder is director to list +if {[catch {WPCmd PEAddress books} booklist]} { + WPCmd PEInfo statmsg "Cannot get list of Addressbooks" +} else { + set books [llength $booklist] + if {$abook < 0} { + cgi_division class="clistContext" { + cgi_put "[cgi_span "class=sp spfcl spfcl1" [cgi_span "style=display:none;" "Contacts: "]][cgi_span "Contact Lists"]" + } + cgi_division class=clistContacts id=clistContacts { + cgi_table cellspacing="0" cellpadding="0" class="clt" { + for {set i 0} {$i < $books} {incr i} { + set thisbook [lindex $booklist $i] + cgi_table_row { + cgi_table_data class="cli" { + cgi_puts [cgi_url [cgi_span "class=sp spfcl spfcl1" "style=border-bottom: 1px solid #003399;" [cgi_span "style=display:none;" [cgi_gt]]] "contacts/${i}/" title="View Contacts in [lindex $thisbook 1]" "onClick=newContactList(YAHOO.alpine.containers.contactlist,null,[lindex $thisbook 0],[newContactJSObject]); return false;"] + } + cgi_table_data class="cln" { + cgi_put [lindex $thisbook 1] + } + } + } + } + } + } else { + for {set i 0} {$i < $books} {incr i} { + if {$i == $abook} { + set thisbook [lindex $booklist $i] + if {[catch {WPCmd PEAddress format [lindex $thisbook 0]} format]} { + WPCmd PEInfo statmsg "Cannot get Contacts format: $format" + } + + if {[catch {WPCmd PEAddress list [lindex $thisbook 0]} clist]} { + WPCmd PEInfo statmsg "Cannot get Contacts list: $clist" + } + + break + } + } + + if {[info exists thisbook]} { + cgi_division class="clistContext" { + if {$books == 1} { + cgi_put "[cgi_span "class=sp spfcl spfcl1" [cgi_span "style=display:none;" "Contacts: "]][cgi_span "Contact List"]" + } else { + cgi_put "[cgi_span "class=sp spfcl spfcl1" "style=border-bottom: 1px solid #003399;" "title=\"Show All Contact Lists\"" "onClick=\"newContactList(YAHOO.alpine.containers.contactlist,null,-1,[newContactJSObject]);\"" [cgi_span "style=display:none;" "Contacts: "]]" + cgi_put [cgi_span id=clistName [lindex $thisbook 1]] + } + } + + cgi_division class=clistContacts id=clistContacts { + cgi_table cellspacing="0" cellpadding="0" "class=\"listTbl divider\"" { + cgi_puts "<tbody>" + if {![string compare $hdr on]} { + cgi_table_row "class=\"contactHeader\"" { + cgi_table_head "class=\"wap colHdr\"" {} + foreach field $format { + cgi_table_head "class=\"wap colHdr lt\"" { + switch -- [lindex $field 0] { + nick { + cgi_puts "Nickname" + } + full { + cgi_puts "Display Name" + if {0 == [string compare $canedit on]} { + cgi_puts " (click to edit)" + } + } + addr { + cgi_put "Email" + if {0 == [string compare $sendto on]} { + cgi_puts " (click email to send)" + } + } + default { + cgi_puts [index $field 0] + } + } + } + } + } + } + + set aindex 0 + foreach contact $clist { + cgi_table_row "class=\"clr\"" { + set nfields [llength $format] + + cgi_table_data class=wap { + set label "ab${abook}.${aindex}" + cgi_checkbox "nickList=$abook.$aindex.[lindex [lindex $contact 0] 0]" id=$label "onclick=\"return boxChecked(this);\"" + } + + for {set i 0} {$i < $nfields} {incr i} { + set field [lindex $format $i] + set data [lindex $contact [expr $i + 1]] + + cgi_table_data "class=\"wap clcd\"" { + switch -- [lindex $field 0] { + addr { + switch -- [lindex [lindex $contact 0] 1] { + single { + set addr [cgi_quote_html $data] + if {0 == [string compare $sendto on]} { + cgi_puts [cgi_url $addr compose?contacts=${abook}.${aindex} class=wap] + } else { + cgi_puts "<label for=$label>$addr</label>" + } + } + list { + foreach addr $data { + set addr [cgi_quote_html $addr] + if {0 == [string compare $sendto on]} { + cgi_puts "[cgi_url $addr compose?contacts=${abook}.${aindex} class=wap][cgi_nl]" + } + } + } + default { + cgi_puts "Unknown contact type" + } + } + } + full { + if {[string length $data]} { + if {0 == [string compare $canedit on]} { + cgi_puts [cgi_url [cgi_quote_html $data] \# "onClick=return editContact({book:${abook},index:${aindex}});" class=wap] + } else { + cgi_puts "<label for=$label>[cgi_quote_html $data]</label>" + } + } else { + cgi_puts [cgi_nbspace] + } + } + default { + if {[string length $data]} { + cgi_puts "<label for=$label>[cgi_quote_html $data]</label>" + } else { + cgi_puts [cgi_nbspace] + } + } + } + } + } + } + incr aindex + } + cgi_puts "</tbody>" + } + } + } else { + WPCmd PEInfo statmsg "Unknown Address Book" + } + } +} +cgi_puts "<script>" +wpStatusAndNewmailJavascript +cgi_puts "if(window.updateContactCount) updateContactCount('$books','[llength $clist]');" +cgi_puts "</script>" diff --git a/web/cgi/alpine/2.0/conduit/empty.tcl b/web/cgi/alpine/2.0/conduit/empty.tcl new file mode 100755 index 00000000..f30864fe --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/empty.tcl @@ -0,0 +1,73 @@ +#!./tclsh +# $Id: empty.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# empty.tcl +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set empty_args { + {c "Unspecified Collection"} + {f "Unspecified Folder"} + {u "" 0} +} + +# inherit global config +source ../alpine.tcl +source ../common.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $empty_args { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + exit + } +} + + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"" +cgi_puts "" + +# ONLY ever empty Junk, Trash or Drafts +set defc [WPCmd PEFolder defaultcollection] + +set tf [lindex [WPCmd PEConfig varget trash-folder] 0] +set df [lindex [WPCmd PEConfig varget postponed-folder] 0] +set f [wpLiteralFolder $c $f] +if {$c == $defc + && (([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || ([string length $tf] && 0 == [string compare $f $tf]) + || ([string length $tf] && 0 == [string compare $f $df]))} { + if {[catch { + switch -regexp $u { + ^([0-9]+)$ - + ^selected$ - + ^all$ { + cgi_puts [WPCmd PEFolder empty $c $f $u] + } + default { + error "Unknown option" + } + } + } result]} { + cgi_puts "$result" + } +} else { + cgi_puts "Empty $f NOT permitted" +} diff --git a/web/cgi/alpine/2.0/conduit/exists.tcl b/web/cgi/alpine/2.0/conduit/exists.tcl new file mode 100755 index 00000000..9f5c2168 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/exists.tcl @@ -0,0 +1,65 @@ +#!./tclsh +# $Id: exists.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# exists +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set exists_args { + {c {} ""} + {f {} ""} + {create {} "no"} +} + +# inherit global config +source ../alpine.tcl + +puts stdout "Content-type: application/json\n" + +if {[catch {WPGetInputAndID sessid}]} { + set harderr "No Session ID: $sessid" +} else { + # grok parameters + foreach item $exists_args { + if {[catch {eval WPImport $item} importerr]} { + set harderr "Cannot init session: $importerr" + break + } + } +} + +if {[info exists harderr]} { + puts -nonewline stdout "{error: '$harderr'}" +} elseif {![regexp {^([0-9]+)$} $c]} { + puts -nonewline stdout "{error: 'Missing collection ID: $c'}" +} elseif {[string length $f] <= 0} { + puts -nonewline stdout "{error: 'Missing folder name'}" +} elseif {0 == [catch {WPCmd PEFolder exists $c $f} result]} { + if {1 == $result} { + puts -nonewline stdout "{exists:1}" + } else { + if {0 == [string compare $create yes]} { + if {0 == [catch {WPCmd PEFolder create $c $f} result]} { + puts -nonewline stdout "{exists:1}" + } else { + puts -nonewline stdout "{error: '$result'}" + } + } else { + puts -nonewline stdout "{exists:0}" + } + } +} else { + puts -nonewline stdout "{error: '$result'}" +} diff --git a/web/cgi/alpine/2.0/conduit/expand.tcl b/web/cgi/alpine/2.0/conduit/expand.tcl new file mode 100755 index 00000000..4599a984 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/expand.tcl @@ -0,0 +1,84 @@ +#!./tclsh +# $Id: expand.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# expand.tcl +# +# Purpose: CGI script to supply data to composer +# +# Input: +# along with possible search parameters: +set expand_args { + {book {} -1} + {index {} -1} + {addrs {} ""} +} + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid} result]} { + error "expand.tcl: $result" +} + +# grok parameters +foreach item $expand_args { + if {[catch {eval WPImport $item} result]} { + error "expand.tcl: $result" + } +} + +catch (unset errstr} +set errlist {} +set expaddr {} + +if {[regexp {^[0-9]*$} $book] && [regexp {^[0-9,]*$} $index]} { + foreach i [split $index ","] { + if {[catch {WPCmd PEAddress entry $book "" $i} entry]} { + lappend errlist $entry + } else { + regsub -all "'" [lindex $entry 0] "\\'" resaddr + lappend expaddr $resaddr + set fcc "" + } + } +} elseif {[string length $addrs]} { + if {[catch {WPCmd PEAddress expand $addrs [lindex [WPCmd PECompose fccdefault] 1]} result]} { + set errstr $result + } else { + set expaddr [list [lindex $result 0]] + set fcc [lindex $result 2] + } +} else { + set errstr "Unknown expand options" +} + +puts stdout "Content-type: text/xml; charset=\"UTF-8\"\n" +puts stdout {<?xml version="1.0" encoding="UTF-8"?>} + +if {[info exists errstr] && [string length $errstr]} { + puts stdout "<ResultSet totalResultsAvailable=\"1\"><Result>" + puts stdout "<Error>$errstr</Error>" + puts stdout "</Result></ResultSet>" +} else { + puts stdout "<ResultSet totalResultsAvailable=\"[expr {[llength $expaddr] + [llength $errlist]}]\">" + foreach e $errlist { + puts stdout "<Result><Error>[cgi_quote_html $e]</Error></Result>" + } + + foreach a $expaddr { + puts stdout "<Result><Address>[cgi_quote_html $a]</Address><Fcc>[cgi_quote_html $fcc]</Fcc></Result>" + } + + puts stdout "</ResultSet>" +} diff --git a/web/cgi/alpine/2.0/conduit/export b/web/cgi/alpine/2.0/conduit/export new file mode 100755 index 00000000..42a9f82b --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/export @@ -0,0 +1,168 @@ +#!./tclsh +# $Id: export 391 2007-01-25 03:53:59Z mikes@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# export +# +# Purpose: CGI script to download exported folder +# +# Input: +set export_vars { +} + +#set export_via_ip_address 1 +#set export_via_local_hostname 1 + +# inherit global config +source ../alpine.tcl + +set mailextension ".mbx" + +proc WPServerIP {} { + global _wp + + catch { + set ip 127.0.0.1 + set sid [socket -async [info hostname] [expr {([string length $_wp(serverport)]) ? $_wp(serverport) : 80}]] + set ip [lindex [ fconfigure $sid -sockname ] 0] + close $sid + } + + return $ip +} + + +WPEval $export_vars { + # grok PATH_INFO for collection 'c' and folder 'f' uid 'u' and part 'p' + if {!([info exists env(PATH_INFO)] && [string length $env(PATH_INFO)] + && [regexp {^/([0-9]+)/(.*)$} $env(PATH_INFO) dummy c f])} { + WPCmd PEInfo statmsg "Invalid Detach: $env(SCRIPT_NAME)" + cgi_exit + } + + # generate filenames to hold exported folder and control file + for {set n 0} {1} {incr n} { + + set rhandle [WPCmd PESession random 64] + set cfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-control] + set dfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-data] + + if {[file exists $cfile] == 0 && [file exists $dfile] == 0} { + if {[catch {open $cfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} cfd] + || [catch {open $dfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} dfd]} { + if {[info exists dfd]} { + catch {close $cfd} + catch {file delete -force $cfile} + set errstr $dfd + } else { + set errstr $cfd + } + + error [list _action Export "Cannot create command/control files: [cgi_quote_html $errstr]" "Please close this window"] + } else { + close $dfd + break + } + } elseif {$n > 4} { + error [list _action Export "Command file creation limit" "Please close this window"] + } + } + + catch {file delete $dfile} + + if {[catch {WPCmd PEFolder export $c $f $dfile} result]} { + WPCmd PEInfo statmsg $result + } else { + if {[set dfilesize [file size $dfile]] > 0 + && ([info exists _wp(uplim_bytes)] && $_wp(uplim_bytes) > 0) + && $dfilesize > $_wp(uplim_bytes)} { + if {$_wp(uplim_bytes) > (1000000)} { + set dfs [format {%s.%.2s MB} [WPcomma [expr {$dfilesize / 1000000}]] [expr {$dfilesize % 1000000}]] + set esl [format {%s.%.2s MB} [WPcomma [expr {$_wp(uplim_bytes) / 1000000}]] [expr {$_wp(uplim_bytes) % 1000000}]] + } else { + set dfs "[WPcomma $dfs] KB" + set esl "[WPcomma $_wp(uplim_bytes)] KB" + } + + WPCmd PEInfo statmsg "Exported folder size ($dfs) exceeds the maximum ($esl) size that can be imported.<br>If you wish to import this folder back into Web Alpine at a later time,<br>you should break it up into smaller folders" + } + + if {[info exists export_via_ip_address]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[WPServerIP]\]\\2" redirect] != 1} { + WPCmd PEInfo statmsg "Cannot determine server address" + catch {unset redirect} + } + } elseif {[info exists export_via_local_hostname]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[info hostname]\]\\2" redirect] != 1} { + WPCmd PEInfo statmsg "Cannot determine server address" + catch {unset redirect} + } + } else { + set redirect "[cgi_root]/pub/getach.tcl" + } + + set givenname "[file tail $f]${mailextension}" + set safegivenname $givenname + regsub -all {[/]} $safegivenname {-} safegivenname + regsub -all {[ ]} $safegivenname {_} safegivenname + regsub -all {[\?]} $safegivenname {X} safegivenname + regsub -all {[&]} $safegivenname {X} safegivenname + regsub -all {[#]} $safegivenname {X} safegivenname + regsub -all {[=]} $safegivenname {X} safegivenname + set safegivenname "/$safegivenname" + + puts $cfd "Content-type: Application/X-Mail-Folder" + puts $cfd "Content-Disposition: attachment; filename=\"$givenname\"" + + # side-step the cgi_xxx stuff in this special case because + # we don't want to buffer up the downloading attachment... + + puts $cfd "Content-Length: $dfilesize" + puts $cfd "Expires: [clock format [expr {[clock seconds] + 3600}] -f {%a, %d %b %Y %H:%M:%S GMT} -gmt true]" + puts $cfd "Cache-Control: max-age=3600" + puts $cfd "" + + puts $cfd $dfile + + # exec chmod [cgi_tmpfile_permissions] $dfile + + close $cfd + + exec /bin/chmod [cgi_tmpfile_permissions] $cfile + exec /bin/chmod [cgi_tmpfile_permissions] $dfile + } + + # prepare to clean up if the brower never redirects + if {[info exists redirect]} { + set redirect "${redirect}${safegivenname}?h=${rhandle}" + } else { + set redirect "[cgi_root]/$_wp(appdir)/$_wp(ui2dir)/folders/" + } + + cgi_http_head { + # redirect to the place we stuffed the export info. use the ip address + # to foil spilling any session cookies or the like + + if {[info exists env(SERVER_PROTOCOL)] && [regexp {[Hh][Tt][Tt][PP]/([0-9]+)\.([0-9]+)} $env(SERVER_PROTOCOL) m vmaj vmin] && $vmaj >= 1 && $vmin >= 1} { + cgi_puts "Status: 303 Temporary Redirect" + } else { + cgi_puts "Status: 302 Redirected" + } + + cgi_puts "URI: $redirect" + cgi_puts "Location: $redirect" + } + + cgi_body {} + + exec echo $rhandle | [file join $_wp(cgipath) [WPCmd PEInfo set wp_ver_dir] whackatch.tcl] >& /dev/null & +} diff --git a/web/cgi/alpine/2.0/conduit/flag.tcl b/web/cgi/alpine/2.0/conduit/flag.tcl new file mode 100755 index 00000000..63018125 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/flag.tcl @@ -0,0 +1,77 @@ +#!./tclsh +# $Id: flag.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# flag +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set flag_args { + {u {} ""} + {f {} ""} + {s {} ""} +} + +# inherit global config +source ../alpine.tcl + +WPEval $flag_args { + cgi_body { + switch -- $f { + {new} - + {imp} { + set flag $f + } + default { + } + } + + switch -- $s { + ton - + not { + set state $s + } + default { + } + } + + if {[info exists flag] && [info exists state]} { + regsub -all {,} $u { } u + if {[regexp {^[ 0123456789]*$} $u]} { + switch $state { + ton { set state 1 } + not { set state 0 } + } + switch $flag { + imp { set flag important } + } + + foreach eu $u { + if {[catch {WPCmd PEMessage $eu flag $flag $state} result]} { + set result "FALURE: setting $eu to $setting : $result" + break + } + } + } elseif {0 == [string compare $u all]} { + if {[catch {WPCmd PEMailbox flag $state $flag} result]} { + set result "FAILURE: flag $state $flag : $result" + } + } + } else { + set result "FAILURE: unkown flag ($f) or state ($s)" + } + + cgi_puts $result + } +} diff --git a/web/cgi/alpine/2.0/conduit/folderlist.tcl b/web/cgi/alpine/2.0/conduit/folderlist.tcl new file mode 100755 index 00000000..c8e73d2d --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/folderlist.tcl @@ -0,0 +1,255 @@ +#!./tclsh +# $Id: folderlist.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# folderlist.tcl +# +# Purpose: CGI script that generates a page snippet that displays +# the XHR requested folder list +# +# Input: PATH_INFO: [/<col_number>]/<directory_path> +# along with possible search parameters: +set folderlist_args { + {op {} "noop"} +} + +# inherit global config +source ../alpine.tcl +source ../foldercache.tcl +source ../common.tcl + + +# default folderlist.tcl state +set c 0 + +# TEST +proc cgi_suffix {args} { + return "" +} + +if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {0 == [string compare $env(PATH_INFO) "/"] || 0 == [string compare $env(PATH_INFO) "//"]} { + set c -1 + set dir "" + } + + if {$c < 0 || [regexp {^/([0-9]+)/(([^/]*/)*)$} $env(PATH_INFO) dummy c dir]} { + # Import data validate it and get session id + if {[catch {WPGetInputAndID sessid} result]} { + set harderr "Cannot init session: $result" + } else { + # grok parameters + foreach item $folderlist_args { + if {[catch {eval WPImport $item} result]} { + set harderr "Cannot read input: $result" + break + } + } + } + } else { + set harderr "BOTCH: Invalid Request: $env(PATH_INFO)" + } +} else { + set harderr "BOTCH: No Folder Specified" +} +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" + +if {[info exists harderr]} { + cgi_puts "<b>ERROR: $harderr</b>" + exit +} + +set cs [WPCmd PEFolder collections] + +if {$c < 0} { + cgi_division class="flistContext" { + cgi_put "[cgi_span "class=sp spfcl spfcl2" [cgi_span "style=display:none;" "Folders: "]][cgi_span "Folder Collections"]" + set folderpath "" + } + + cgi_division class=flistFolders { + cgi_table cellspacing="0" cellpadding="0" class="flt" { + foreach col $cs { + set ci [lindex $col 0] + set onclick "onClick=return newFolderList(this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode,null,$ci);" + cgi_table_row { + cgi_table_data class="fli" { + cgi_puts [cgi_url [cgi_span "class=sp spfl spfl1" [cgi_span "style=display:none;" [cgi_gt]]] "list/${ci}/" title="View folders in collection." $onclick] + } + cgi_table_data class="fln" { + cgi_puts "[lindex $col 1]" + } + } + cgi_table_row { + cgi_table_data colspan=2 class="flcd" { + cgi_puts "[cgi_span class=flcd [lindex $col 2]]" + } + } + } + } + } + cgi_puts "<script>" + cgi_puts "updateElementValue('pickFolderCollection', '-1');" + cgi_puts "updateElementValue('pickFolderPath', '/');" + wpStatusAndNewmailJavascript + cgi_puts "setPanelBodyWidth('flistFolders');" + cgi_puts "</script>" +} else { + set delim [WPCmd PEFolder delimiter $c] + + switch -- $op { + delete { + if {0 == [catch {cgi_import_as f delf}]} { + if {0 == [string length $dir] && 0 == [string compare -nocase inbox $delf]} { + WPCmd PEInfo statmsg "Cannot delete INBOX" + } else { + regsub -all "${delim}" $dir { } deld + if {[catch [concat WPCmd PEFolder delete $c $deld \"$delf\"] result]} { + WPCmd PEInfo statmsg "Cannot delete $result" + } else { + WPCmd PEInfo statmsg "Folder \"$delf\" permanently deleted" + removeFolderCache $c [join [list $dir $delf] $delim] + } + } + } else { + WPCmd PEInfo statmsg "Delete which folder???" + } + } + add { + if {0 == [catch {cgi_import_as f addf}]} { + if {0 == [string length $dir] && 0 == [string compare -nocase inbox $delf]} { + WPCmd PEInfo statmsg "Cannot add INBOX" + } else { + regsub -all "${delim}" $dir { } addd + if {[catch [concat WPCmd PEFolder create $c $addd \"$addf\"] result]} { + WPCmd PEInfo statmsg "Folder Cannot add: $result" + } else { + WPCmd PEInfo statmsg "Folder \"$addf\" added" + } + } + } else { + WPCmd PEInfo statmsg "No foldername provided" + } + } + rename { + if {0 == [catch {cgi_import sf}] && 0 == [catch {cgi_import df}]} { + if {[string compare -nocase inbox $sf] && [string compare -nocase inbox $df]} { + if {[catch {WPCmd PEFolder rename $c [join [list $dir $sf] $delim] [join [list $dir $df] $delim]} result]} { + WPCmd PEInfo statmsg "Cannot rename: $result" + } else { + WPCmd PEInfo statmsg "Renamed \"$sf\" to \"$df\"" + } + } else { + WPCmd PEInfo statmsg "Cannot rename INBOX" + } + } else { + WPCmd PEInfo statmsg "Foldernames not provided" + } + } + noop { + } + default { + WPCmd PEInfo statmsg "Unrecognized option: $op" + } + } + + if {0 == [string length $dir] || 0 == [string compare $dir {/}]} { + if {[catch {WPCmd PEFolder list $c} flist]} { + set authlist [wpHandleAuthException $flist [list [lindex [lindex $cs $c] 0] "list folders in collection [lindex [lindex $cs $c] 1]"] INBOX] + if {0 == [llength $authlist]} { + WPCmd PEInfo statmsg $flist + } + } + } else { + if {[catch {WPCmd PEFolder list $c $dir} flist]} { + set col [lindex [lindex $cs $c] 1] + + set authlist [wpHandleAuthException $flist [list [lindex [lindex $cs $c] 0] "list folders in collection [lindex [lindex $cs $c] 1]"] INBOX] + if {0 == [llength $authlist]} { + WPCmd PEInfo statmsg $flist + } + } + } + + cgi_division class="flistContext" { + + if {[llength $cs] > 1} { + cgi_put "[cgi_span "class=sp spfcl spfcl2" "style=border-bottom: 1px solid #003399;" "title=\"Show Folder Collections\"" "onClick=\"newFolderList(this.parentNode.parentNode,null,'');\"" [cgi_span "style=display:none;" "Folders: "]]" + } else { + cgi_put [cgi_span "class=sp spfcl spfcl2" [cgi_span "style=display:none;" "Folders: "]] + } + + set dp "" + set col [lindex [lindex $cs $c] 1] + + if {[regexp {^(.*)/$} $dir dummy folderpath]} { + cgi_puts [cgi_url $col "list/$c/" title="List folders in this directory" "onClick=return newFolderList(this.parentNode.parentNode,null,$c);"] + set ds [split $folderpath {/}] + for {set i 0} {$i < [llength $ds]} {incr i} { + set d [lindex $ds $i] + if {[string length $d]} { + lappend dp $d + set path [join $dp {/}] + if {$i < ([llength $ds] - 1)} { + set d [cgi_url "${d}" "list/$c/$path/" title="List subfolders" "onClick=return newFolderList(this.parentNode.parentNode,null,$c,'$path');"] + } else { + set d [span class=flistFolder $d] + } + + cgi_puts "[cgi_span "»"]$d" + } + } + } else { + set folderpath "" + cgi_puts [cgi_span $col] + } + } + + cgi_division class=flistFolders id=flistFolders { + cgi_table cellspacing="0" cellpadding="0" class="flt" { + foreach f $flist { + set t [lindex $f 0] + set fn [lindex $f 1] + set onclick "onClick=return newFolderList(this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode,null,${c},'[file join ${folderpath} ${fn}]');" + cgi_table_row class="flr" { + cgi_table_data class="fli" { + if {[string first D $t] >= 0} { + cgi_puts [cgi_url [cgi_span "class=sp spfl spfl1" [cgi_span "style=display:none;" [cgi_gt]]] "folders/${c}/[WPPercentQuote "${dir}${fn}" {/}]/" title="List subfolders" $onclick] + } else { + cgi_puts [cgi_nbspace] + } + } + cgi_table_data class="fln" { + set hfn [cgi_quote_html $fn] + if {[string first F $t] >= 0} { + cgi_puts [cgi_url "$hfn" "browse/${c}/[WPPercentQuote "${dir}${fn}" {/}]" class="fln" title="Click to select. Double-click to view messages." "onClick=return flistPick(this,'[WPPercentQuote $fn]');" "onDblClick=return flistPickPick(this);"] + } else { + cgi_puts "$hfn" + } + } + } + } + } + } + cgi_puts "<script>" + if {$c >= 0} { + cgi_puts "YAHOO.alpine.current.incoming = [WPCmd PEFolder isincoming $c];" + } + cgi_puts "updateElementValue('pickFolderCollection', '$c');" + cgi_puts "updateElementValue('pickFolderPath', '$folderpath');" + wpStatusAndNewmailJavascript + cgi_puts "setPanelBodyWidth('flistFolders');" + if {[info exists authlist]} { + reportAuthException $authlist + } + cgi_puts "</script>" +} diff --git a/web/cgi/alpine/2.0/conduit/getcontact.tcl b/web/cgi/alpine/2.0/conduit/getcontact.tcl new file mode 100755 index 00000000..f859a21d --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/getcontact.tcl @@ -0,0 +1,53 @@ +#!./tclsh +# $Id: getcontact.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# getcontact.tcl +# +# Purpose: CGI script to handle saving new/edited contacts +# +# Input: +set contact_vars { + {book "" 0} + {index "" -1} +} + +# Output: + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid} result]} { + error "getcontact.tcl $result" +} + +# grok parameters +foreach item $contact_vars { + if {[catch {eval WPImport $item} result]} { + error "getcontact.tcl $result" + } +} + +if {[catch {WPCmd PEAddress fullentry $book "" $index} addrinfo]} { + error "getcontact.tcl $addrinfo" +} + +puts stdout "Content-type: text/xml; charset=\"UTF-8\"\n" +puts stdout {<?xml version="1.0" encoding="UTF-8"?>} +puts stdout "<ResultSet totalResultsAvailable=\"1\"><Result>" +puts stdout "<Nickname>[cgi_quote_html [lindex $addrinfo 0]]</Nickname>" +puts stdout "<Personal>[cgi_quote_html [lindex $addrinfo 1]]</Personal>" +puts stdout "<Mailbox>[cgi_quote_html [join [lindex $addrinfo 2] ", "]]</Mailbox>" +puts stdout "<Fcc>[cgi_quote_html [lindex $addrinfo 3]]</Fcc>" +puts stdout "<Note>[cgi_quote_html [lindex $addrinfo 4]]</Note>" +puts stdout "</Result></ResultSet>" diff --git a/web/cgi/alpine/2.0/conduit/import b/web/cgi/alpine/2.0/conduit/import new file mode 100755 index 00000000..04326b14 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/import @@ -0,0 +1,73 @@ +#!./tclsh +# $Id: import 391 2007-01-25 03:53:59Z mikes@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# import +# +# Purpose: CGI script that generates a page displaying a message +# list of the indicated folder. +# +# Input: PATH_INFO: [/<col_number>]/<directory_path> +# along with possible search parameters: +set import_args { +} + +# inherit global config +source ../alpine.tcl + +# TEST +proc cgi_suffix {args} { + return "" +} + +WPEval $import_args { + + # grok PATH_INFO for collection 'c' and folder path 'p' + if {!([info exists env(PATH_INFO)] && [string length $env(PATH_INFO)] + && [regexp {^/([0-9]+)/(.*)$} $env(PATH_INFO) dummy c p])} { + WPCmd PEInfo statmsg "Invalid Detach: $env(SCRIPT_NAME)" + cgi_exit + } + + if {[catch {WPImport file "Missing File Upload"} result] == 0} { + set local_file [lindex $file 0] + if {[catch {WPImport newFolder "import name"} result] == 0} { + set iname [string trim $newFolder] + if {[string length $iname]} { + set fldr [eval "file join $p $iname"] + if {[catch {WPCmd PEFolder import $local_file $c $fldr} result] == 0} { + WPCmd PEInfo statmsg "Imported folder $iname" + } else { + WPCmd PEInfo statmsg "Can't Import File: $result" + } + } else { + WPCmd PEInfo statmsg "Must provide uploaded folder name" + } + } else { + WPCmd PEInfo statmsg "No Import Folder Name: $result" + } + + catch {file delete -force $local_file} + } else { + WPCmd PEInfo statmsg "Cannot Import: $result" + } + + cgi_html { + cgi_head { + cgi_javascript { + cgi_puts "window.parent.hideLoading();" + cgi_puts "window.parent.redrawFolderList();" + } + } + cgi_body {} + } +} diff --git a/web/cgi/alpine/2.0/conduit/mark.tcl b/web/cgi/alpine/2.0/conduit/mark.tcl new file mode 100755 index 00000000..2ac5a2d7 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/mark.tcl @@ -0,0 +1,77 @@ +#!./tclsh +# $Id: mark.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# mark.tcl +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set mark_args { + {u {} ""} + {mark {} ""} +} + +# inherit global config +source ../alpine.tcl + +WPEval $mark_args { + cgi_body { + switch -- $mark { + false { + set setting 0 + } + true { + set setting 1 + } + default { + } + } + + if {[info exists setting]} { + regsub -all {,} $u { } u + if {[regexp {^[ 0123456789]*$} $u]} { + foreach eu $u { + if {[catch {WPCmd PEMessage $eu select $setting} result]} { + set result "FAILURE: setting $eu to $setting : $result" + break + } + } + } elseif {0 == [string compare $u all]} { + if {$setting} { + set setting all + } else { + set setting none + } + + if {[catch {WPCmd PEMailbox select $setting} result]} { + set result "FAILURE: $result" + } + } elseif {0 == [string compare $u searched]} { + if {$setting} { + set setting searched + } else { + set setting unsearched + } + + if {[catch {WPCmd PEMailbox select $setting} result]} { + set result "FAILURE: $result" + } + } + } else { + set reult "FAILURE: Unknown mark value: $mark" + } + + cgi_puts $result + } +} diff --git a/web/cgi/alpine/2.0/conduit/newmail.tcl b/web/cgi/alpine/2.0/conduit/newmail.tcl new file mode 100755 index 00000000..cecd3466 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/newmail.tcl @@ -0,0 +1,56 @@ +#!./tclsh +# $Id: newmail.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# newmail.tcl +# +# Purpose: CGI script generating response to xmlHttpRequest +# +# Input: +# +set newmail_args { + {reload {} 0} +} + +# inherit global config +source ../alpine.tcl + + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $newmail_args { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + return + } +} + +puts stdout "Content-type: application/json\n" + +if {[catch {WPCmd PESession mailcheck $reload} newmail]} { + puts -nonewline stdout "{error: '$newmail'}" +} else { + puts -nonewline "\[" + set comma "" + foreach nm $newmail { + set text [lindex $nm 2] + regsub -all {'} $text {\'} text + puts -nonewline "${comma}\{newcount:[lindex $nm 0],uid:[lindex $nm 1],verbiage:'${text}'\}" + set comma "," + } + + puts -nonewline "\]" +} diff --git a/web/cgi/alpine/2.0/conduit/post.tcl b/web/cgi/alpine/2.0/conduit/post.tcl new file mode 100755 index 00000000..9757baca --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/post.tcl @@ -0,0 +1,333 @@ +#!./tclsh +# $Id: post.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# post.tcl +# +# Purpose: CGI script to do the job of posting message supplied by compose form +# + +# Input: +set post_vars { + {cid "Missing Command ID"} + {check {} 0} + {sendop {} ""} + {extrahdrs {} ""} + {fccattach {} 0} + {form_flowed {} ""} + {subtype {} "plain"} + {priority {} ""} + {autodraftuid {} 0} +} + +# inherit global config +source ../alpine.tcl +source ../common.tcl + +# Output: HTML containing javascript calls to functions of parent window +# + + +proc fieldname {name} { + regsub -all -- {-} [string tolower $name] {_} fieldname + return $fieldname +} + +proc removeAutoDraftMsg {uid} { + if {$uid != 0} { + if {[regexp {^[0-9]+$} $uid]} { + if {[catch {WPCmd PEPostpone delete $uid} result]} { + catch {WPCmd PEInfo statmsg "Stale autodraft UID: $result"} + } + } else { + catch {WPCmd PEInfo statmsg "Invalid autodraft uid: $uid"} + } + } +} + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $post_vars { + if {[catch {eval WPImport $item} errstr]} { + lappend errs $errstr + } +} + + +# collect message data + +# For now the input headers have to match the postheaders +# list. Any outside the list are ignored (and probably should +# be to avoid hostile input). Note, postheaders is a +# super-set of composeheaders as not all headers are meant +# to be shown the user for composition +if {[catch {WPCmd PECompose userhdrs} headers]} { + error [list _action "User Headers" $headers "Click browser's Back button to try again."] +} + +if {[catch {WPCmd PECompose syshdrs} otherhdrs]} { + error [list _action "System Headers" $otherhdrs "Click browser's Back button to try again."] +} else { + eval "lappend headers $otherhdrs" +} + +foreach field $headers { + set hdr [string tolower [lindex $field 0]] + regsub -all -- {-} $hdr {_} hdr + WPLoadCGIVarAs $hdr val + switch -- $hdr { + attach { + # disregard: u/i convenience (attachments marshalled below) + } + fcc { + if {[string length $val]} { + WPLoadCGIVar colid + set has_fcc [list $colid $val] + lappend msgdata [list Fcc $has_fcc] + } + } + default { + if {[string length $val] || [lsearch -exact {subject} $hdr] >= 0} { + # join lines + regsub -all {\n} $val { } val + if {[lsearch -exact {to cc bcc} $hdr] >= 0} { + # strip trailing whitespace and commas + regsub {[ ,]*$} $val {} val + set has_$hdr 1 + } + lappend msgdata [list [lindex $field 0] $val] + } + } + } +} + +if {[info exists env(REMOTE_ADDR)]} { + lappend msgdata [list x-auth-received "from \[$env(REMOTE_ADDR)\] by [info hostname] via HTTP; [clock format [clock seconds] -format "%a, %d %b %Y %H:%M:%S %Z"]"] +} + +if {[catch {cgi_import attachments}] == 0} { + foreach id [split $attachments ","] { + lappend msgdata [list attach $id] + } +} + +cgi_import body + +# pass body text options, dress as necessary +if {0 == [string compare -nocase $subtype html]} { + lappend msgdata [list postoption [list subtype html]] + set body "<html><head><title></title></head>\n<body>\n${body}\n</body></html>" + set compose_mode rich +} else { + set compose_mode plain + if {[string length $form_flowed]} { + lappend msgdata [list postoption [list flowed yes]] + } +} + +if {[regexp {^(lowest|low|normal|high|highest)$} $priority]} { + lappend msgdata [list postoption [list priority $priority]] +} + +lappend msgdata [list body [split $body "\n"]] + +switch -exact -- $fccattach { + 0 - + 1 { + lappend msgdata [list postoption [list fcc-without-attachments [expr {!$fccattach}]]] + } +} + +lappend msgdata [list postoption [list charset "utf-8"]] + +# figure out what to do with data +if {[string compare $sendop send] == 0} { + if {[info exists has_to] || [info exists has_cc] || [info exists has_bcc] || [info exists has_fcc]} { + # expand any nicknames + if {[catch { + set fccdef [WPCmd PECompose fccdefault] + for {set i 0} {$i < [llength $msgdata]} {incr i} { + if {[string length [lindex [lindex $msgdata $i] 1]]} { + set fld [lindex $msgdata $i] + set fn [string tolower [lindex $fld 0]] + switch -- $fn { + [Ff]cc { + if {[string length [lindex [lindex $fld 1] 1]]} { + # setup for send confirmation + set colidval [lindex [lindex $fld 1] 0] + set fccval [lindex [lindex $fld 1] 1] + } + } + to - + cc - + bcc - + reply-to { + set expaddr [WPCmd PEAddress expand [lindex $fld 1] {}] + if {[string compare [lindex $expaddr 0] [lindex $fld 1]]} { + set msgdata [lreplace $msgdata $i $i [list [lindex $fld 0] [lindex $expaddr 0]]] + + # if expanded, update fcc? + if {[string compare to $fn] == 0 && [string length $fn]} { + set expanded_fcc [lindex $expaddr 2] + } + } + } + body { + if {[string length $form_flowed]} { + set ws "\[ \t]" + set nws "\[^ \t]" + + set nextline [lindex [lindex $fld 1] 0] + for {set j 1} {$j <= [llength [lindex $fld 1]]} {incr j} { + set line $nextline + # space stuff? + if {[regexp "^${ws}+" $line]} { + set line " $line" + } + + set nextline [lindex [lindex $fld 1] $j] + if {[regexp {^-- $} $line] == 0} { + catch {unset linetext} + # trim trailing WS from lines preceding those with LWS (space-stuff as needed) + if {[string length $nextline] == 0 || [regexp "^${ws}+(${nws}?.*)\$" $nextline dummy linetext]} { + set line [string trimright $line] + if {[info exists linetext] == 0 || [string length $linetext] == 0} { + set nextline "" + } + } + + # break overly long lines in a flowed way + if {[regexp {^[^>]} $line] && [string length $line] > 1000} { + while {[regexp "^(${ws}*${nws}+${ws}+)$nws" [string range $line 900 end] dummy linex]} { + set cliplen [expr {900 + [string length $linex]}] + lappend newbody [string range $line 0 [expr {$cliplen - 1}]] + set line [string range $line $cliplen end] + } + } + } + + lappend newbody $line + } + + set msgdata [lreplace $msgdata $i $i [list body $newbody]] + } + } + default { + } + } + } + } + } result]} { + set reportfunc sendFailure + set postresult "Address problem: $result" + } else { + # update fcc? + if {[info exists expanded_fcc] + && (![info exists has_fcc] || 0 == [string compare [lindex $fccdef 1] [lindex $has_fcc 1]])} { + for {set j 0} {$j < [llength $msgdata]} {incr j} { + if {[string compare fcc [fieldname [lindex [lindex $msgdata $j] 0]]] == 0} { + set fcc_index $j + break + } + } + + set colid [lindex $fccdef 0] + if {[info exists fcc_index]} { + set msgdata [lreplace $msgdata $fcc_index $fcc_index [list Fcc [list $colid $expanded_fcc]]] + } else { + lappend msgdata [list Fcc [list $colid $expanded_fcc]] + } + } + + removeAutoDraftMsg $autodraftuid + + # do the sending... + set verb Send + set verbpast Sent + set postcmd PECompose + set postcmdopt post + if {[info exists compose_mode]} { + catch {WPSessionState compose_mode $compose_mode} + } + } + } else { + set reportfunc sendFailure + set postresult "Send MUST include Recipients (To, Cc, Bcc, or Fcc)" + } +} elseif {[string compare $sendop postpone] == 0} { + removeAutoDraftMsg $autodraftuid + set verb "Save to Drafts" + set verbpast "Saved to Drafts" + set postcmd PEPostpone + set postcmdopt append +} elseif {[string compare $sendop autodraft] == 0} { + removeAutoDraftMsg $autodraftuid + + set verb "Save to Drafts" + set verbpast "Saved to Drafts" + set postcmd PEPostpone + set postcmdopt draft + set reportfunc reportAutoDraft +} else { + set reportfunc sendFailure + set postresult "Unrecognized Action" +} + +#do what was asked +if {[info exists postcmd]} { + if {[info exists msgdata]} { + if {[catch {WPCmd $postcmd $postcmdopt $msgdata} postresult]} { + set auth [wpHandleAuthException $postresult [list 0 "send"]] + if {[string length $auth]} { + set reportcall "processPostAuthException(\{${auth}\});" + } else { + set reportfunc sendFailure + } + } elseif {0 == [string compare $postcmd PECompose]} { + WPCmd PEInfo statmsg "Message $verbpast" + } + } else { + WPCmd PEInfo statmsg "No Message $verbpast!" + } + + if {[info exists delete_me]} { + foreach i $delete_me { + catch {file delete $i} + } + } +} + +puts stdout "Content-type: text/html;\n\n<html><head><script>" + +if {[info exists reportfunc]} { + puts stdout "window.parent.${reportfunc}(\"${postresult}\");" + foreach sm [WPCmd PEInfo statmsgs] { + regsub -all {'} $sm {\'} sm + puts stdout "window.parent.sendFailure(\"${sm}\");" + } +} elseif {[info exists reportcall]} { + puts stdout "window.parent.${reportcall};" + foreach sm [WPCmd PEInfo statmsgs] { + regsub -all {'} $sm {\'} sm + if {0 == [regexp {Authentication cancelled} $sm]} { + puts stdout "window.parent.sendFailure(\"${sm}\");" + } + } +} else { + puts stdout "window.parent.sendSuccess(\"${postresult}\");" +} + +puts stdout "</script></head><body></body></html>" diff --git a/web/cgi/alpine/2.0/conduit/query.tcl b/web/cgi/alpine/2.0/conduit/query.tcl new file mode 100755 index 00000000..eba4ee77 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/query.tcl @@ -0,0 +1,83 @@ +#!./tclsh +# $Id: query.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# query.tcl +# +# Purpose: CGI script to handle querying LDAP directory +# +# Input: +set query_vars { + {dir "" "0"} + {query "" ""} +} + +# Output: + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $query_vars { + if {[catch {eval WPImport $item} errstr]} { + lappend errs $errstr + } +} + +set qresult "" + +# return attachment list +puts stdout "Content-type: text/html;\n\n<html><head><script>window.parent.drawLDAPResult({" +if {[string length $query]} { + if {[catch {WPCmd PELdap query $dir $query ""} qn]} { + regsub -all {'} $qn {\'} qn + puts stdout "error:'Search failed: $qn'" + } else { + switch $qn { + 0 { puts stdout "error:'Search found no matching entries'" } + default { + if {[catch {WPCmd PELdap results $qn} results]} { + regsub -all {'} $results {\'} results + puts stdout "error:'Problem with results: $results'" + } else { + puts stdout "results:\[" + foreach result $results { + set res [lindex $result 1] + set comma "" + foreach r $res { + regsub -all {'} $r {\'} r + puts -nonewline stdout "${comma}{personal:'[lindex $r 0]',email:\[" + set comma2 "" + foreach a [lindex $r 4] { + puts -nonewline stdout "$comma2'$a'" + set comma2 "," + } + puts -nonewline stdout "\]}" + set comma "," + } + } + + puts stdout "\]" + } + } + } + } +} else { + puts stdout "error:'Empty search request'" +} + +puts stdout "});</script></head><body></body></html>" diff --git a/web/cgi/alpine/2.0/conduit/settings.tcl b/web/cgi/alpine/2.0/conduit/settings.tcl new file mode 100755 index 00000000..f4f30922 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/settings.tcl @@ -0,0 +1,184 @@ +#!./tclsh +# $Id: settings.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# settings.tcl +# +# Purpose: CGI script to do the job of updating submitted settings +# + +# Input: +set settings_vars { + {restore "" false} +} + +# inherit global config +source ../alpine.tcl +source ../common.tcl + +# Output: HTML containing javascript calls to functions of parent window +# + + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +foreach item $settings_vars { + if {[catch {eval WPImport $item} result]} { + regsub -all {"} $result {\"} errstr + break + } +} + +set response "Settings Updated" + +# feature settings +if {0 == [string compare restore $restore]} { + WPCmd PEConfig reset pinerc + set response "Default Settings Restored" +} elseif {[catch { + WPCmd PEConfig newconf + + # collect feature settings + set setfeatures [WPCmd PEConfig featuresettings] + foreach feature { + include-header-in-reply + include-attachments-in-reply + signature-at-bottom + strip-from-sigdashes-on-reply + fcc-without-attachments + auto-move-read-msgs + enable-msg-view-urls + feature enable-msg-view-web-hostnames + enable-msg-view-addresses + render-html-internally + quell-server-after-link-in-html + quell-flowed-text + } { + if {[catch {cgi_import_as $feature setting}]} { + if {[lsearch $setfeatures $feature] >= 0} { + WPCmd PEConfig feature $feature 0 + } + } else { + if {[lsearch $setfeatures $feature] < 0} { + WPCmd PEConfig feature $feature 1 + } + } + } + + # collect single-line text variable settings + foreach variable { + wp-indexlines + default-fcc + personal-name + user-domain + sort-key + incoming-startup-rule + posting-character-set + reply-leadin + reply-indent-string + postponed-folder + trash-folder + inbox-path + rss-news + rss-weather + read-message-folder + } { + set varvals [WPCmd PEConfig varget $variable] + set varvalue [lindex $varvals 0] + cgi_import_as $variable value + set value [split $value "\n"] + if {[string compare $varvalue $value]} { + WPCmd PEConfig varset $variable $value + } + } + + # collect list-style variable settings + foreach {variable handle} { + alt-addresses altAddr + viewer-hdrs viewerHdr + default-composer-hdrs composeHdr + smtp-server smtpServer + ldap-servers ldapServer + } { + if {0 == [catch {cgi_import_as ${handle}s lcount}]} { + set l {} + for {set i 1} {$i <= $lcount} {incr i} { + if {0 == [catch {cgi_import_as ${handle}${i} value}] && [string length $value]} { + lappend l $value + } + } + + WPCmd PEConfig varset $variable $l + } + } + + # special-case variable settings + if {0 == [catch {cgi_import customHdrFields}]} { + set hdrs {} + for {set i 1} {$i <= $customHdrFields} {incr i} { + if {0 == [catch {cgi_import_as customHdrField${i} field}]} { + set hdr "${field}:" + if {0 == [catch {cgi_import_as customHdrData${i} value}]} { + append hdr " $value" + } + + lappend hdrs $hdr + } + } + + if {[llength $hdrs]} { + WPCmd PEConfig varset customized-hdrs $hdrs + } + } + + cgi_import wrapColumn + WPCmd PEConfig columns $wrapColumn + + cgi_import folderCache + WPSessionState left_column_folders $folderCache + + cgi_import forwardAs + if {0 == [string compare attached $forwardAs]} { + if {[lsearch $setfeatures $feature] < 0} { + WPCmd PEConfig feature forward-as-attachment 1 + } + } else { + if {[lsearch $setfeatures $feature] >= 0} { + WPCmd PEConfig feature forward-as-attachment 0 + } + } + + cgi_import signature + set cursig [string trimright [join [WPCmd PEConfig rawsig] "\n"]] + set signature [string trimright $signature] + if {[string compare $cursig $signature]} { + WPCmd PEConfig rawsig [split $signature "\n"] + } + + WPCmd PEConfig saveconf +} result]} { + regsub -all {"} $result {\"} errstr +} + +puts stdout "Content-type: text/html;\n\n<html><head><script>" + +if {[info exists errstr]} { + puts stdout "window.parent.settingsFailure(\"${errstr}\");" +} else { + WPCmd PEInfo statmsg $response + puts stdout "window.parent.settingsSuccess();" +} + +puts stdout "</script></head><body></body></html>" diff --git a/web/cgi/alpine/2.0/conduit/storecontact.tcl b/web/cgi/alpine/2.0/conduit/storecontact.tcl new file mode 100755 index 00000000..36836f54 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/storecontact.tcl @@ -0,0 +1,67 @@ +#!./tclsh +# $Id: storecontact.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# storecontact.tcl +# +# Purpose: CGI script to handle saving new/edited contacts +# +# Input: +set store_vars { + {book "" 0} + {ai "" -1} + {contactNick "" ""} + {contactName "" ""} + {contactEmail "" ""} + {contactFcc "" ""} + {contactNotes "" ""} +} + +# Output: + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $store_vars { + if {[catch {eval WPImport $item} errstr]} { + lappend errs $errstr + } +} + +if {[string length $contactNick] || [string length $contactName] || [string length $contactEmail]} { + set result "" + if {[catch {WPCmd PEAddress edit $book $contactNick $ai $contactName $contactEmail $contactFcc $contactNotes 1} result]} { + lappend status "Address Set Failure: $result" + } elseif {[string length $result]} { + lappend status "$result" + } else { + lappend status "Contact Added" + } +} else { + lappend status "No Contact Added: Must contain Display Name, Address or Nickname" +} + +# return response text +puts stdout "Content-type: text/xml; charset=\"UTF-8\"\n" +puts stdout {<?xml version="1.0" encoding="UTF-8"?>} +puts stdout "<ResultSet totalResultsAvailable=\"[llength $status]\">" +foreach sm $status { + regsub {'} $sm {\'} sm + puts stdout "<Result><StatusText>$sm</StatusText></Result>" +} +puts stdout "</ResultSet>" diff --git a/web/cgi/alpine/2.0/conduit/take.tcl b/web/cgi/alpine/2.0/conduit/take.tcl new file mode 100755 index 00000000..4f5f1342 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/take.tcl @@ -0,0 +1,84 @@ +#!./tclsh +# $Id: take.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# take.tcl +# +# Purpose: CGI script to supply data to YUI AutoTake +# +# Input: +# along with possible search parameters: +set take_args { + {op {} "noop"} + {u {} 0} +} + +# inherit global config +source ../alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + error "take.tcl $result" +} + +# grok parameters +foreach item $take_args { + if {[catch {eval WPImport $item} result]} { + set errstr $result + break; + } +} + +switch -- $op { + from { + if {[catch {WPCmd PEMessage $u takefrom} result]} { + set errstr $result + } + } + all { + if {[catch {WPCmd PEMessage $u takeaddr} result]} { + set errstr $result + } + } + default { + set errstr "Unrecognized Take option: $op" + } +} + +puts stdout "Content-type: text/xml; charset=\"UTF-8\"\n" +puts stdout {<?xml version="1.0" encoding="UTF-8"?>} +puts stdout "<ResultSet totalResultsAvailable=\"[llength $result]\">" +if {[info exists errstr]} { + puts -nonewline stdout "<Result><Error>$errstr</Error></Result>" +} else { + foreach r $result { + set ar [lindex $r 1] + set sr [lindex $r 2] + if {[string length [lindex $sr 0]] > 0 + || [string length [lindex $sr 2]] > 0 + || [string length [lindex $sr 3]] > 0} { + set type "edit" + } else { + set type "add" + } + # there is also an addrbook Fullname in sr 1 + puts -nonewline stdout "<Result>" + puts -nonewline stdout "<Type>[cgi_quote_html $type]</Type>" + puts -nonewline stdout "<Nickname>[cgi_quote_html [lindex $sr 0]]</Nickname>" + puts -nonewline stdout "<Personal>[cgi_quote_html [lindex $ar 0]]</Personal>" + puts -nonewline stdout "<Email>[cgi_quote_html "[lindex $ar 1]@[lindex $ar 2]"]</Email>" + puts -nonewline stdout "<Fcc>[cgi_quote_html [lindex $sr 2]]</Fcc>" + puts -nonewline stdout "<Note>[cgi_quote_html [lindex $sr 3]]</Note>" + puts stdout "</Result>" + } +} +puts stdout {</ResultSet>} diff --git a/web/cgi/alpine/2.0/conduit/tclsh b/web/cgi/alpine/2.0/conduit/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/alpine/2.0/conduit/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/contacts b/web/cgi/alpine/2.0/contacts new file mode 100755 index 00000000..1cbec957 --- /dev/null +++ b/web/cgi/alpine/2.0/contacts @@ -0,0 +1,201 @@ +#!./tclsh +# $Id: contacts 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# view.tcl +# +# Purpose: CGI script contacts for Web Alpine 2.0 pages +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_viewed_msg> +# along with possible search parameters: +set contacts_args { +} + +# inherit global config +source ./alpine.tcl +source ./foldercache.tcl +source ./common.tcl + +# TEST +proc cgi_suffix {args} { + return "" +} + +# WHILE TESTING/DEBUGGING +proc noimp {s} { + return "onClick=return noImp('${s}');" +} + +set dmsgs "" +proc dm {s} { + global dmsgs + + lappend dmsgs $s +} + + +WPEval $contacts_args { + # verify current collection/folder + if {[catch {WPCmd PEFolder current} curfold]} { + error [list _action browse "cannot determine default folder: $curfold"] + } else { + set c [lindex $curfold 0] + set f [lindex $curfold 1] + } + + set charset "UTF-8" + set u 0 + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + cgi_html { + cgi_head { + cgi_content_type "text/html; charset=$charset" + # WPStdHttpHdrs "text/html; charset=$charset" + cgi_title [wpPageTitle "Contacts"] + cgi_base "href=$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + + cgi_stylesheet css/menu.css + cgi_stylesheet css/cbn/screen.css + cgi_stylesheet css/cbn/contacts.css + # Yahoo Styles + cgi_stylesheet $_wp(yui)/build/container/assets/container-core.css + cgi_stylesheet $_wp(yui)/build/menu/assets/skins/sam/menu.css + cgi_stylesheet $_wp(yui)/build/button/assets/skins/sam/button.css + # YahooUI libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/menu/menu-min.js" {} + # local libraries + cgi_script language="JavaScript" src="lib/common.js" {} + cgi_script language="JavaScript" src="lib/contacts.js" {} + + cgi_javascript { + cgi_puts "var gCurrentAbook = 0;" + cgi_puts "YAHOO.alpine.current.c = '$c';" + cgi_puts "YAHOO.alpine.current.f = '$f';" + cgi_puts "YAHOO.alpine.current.u = $u;" + cgi_puts "function updateContactCount(nBooks,nContacts){" + cgi_puts " var el = document.getElementById('contactCount');" + cgi_puts " if(el) el.innerHTML = nContacts + ' Contacts';" + cgi_puts "}" + cgi_puts "function bodyOnLoad() {" + cgi_puts " initMenus();" + cgi_puts " if(YAHOO.env.ua.gecko > 0){ sizeVPHeight(); window.onresize = resizeVPHeight; }" + cgi_puts " setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + cgi_puts " drawContactList('alpineContent',gCurrentAbook,{hdr:'on',sendto:'on',canedit:'on'});" + cgi_puts "}" + + # WHILE TESTING/DEBUGGING + cgi_puts "var impi = new Array(); function noImp(m){ var sm; if(impi\[m\]) {impi\[m\]++; if(impi\[m\] > 4) sm = '<b>Seriously,</b> ' + m + ' will <b>never</b> get implemented if you keep bothering me!'; else sm = m + ' is <b>still</b> not implemented!'; } else { sm = m + ' is not implemented yet!' ; impi\[m\] = 1 ;} showStatusMessage(sm,3); return false; }" + + cgi_puts "browserDetect();" + } + } + + cgi_body class=wap "onLoad=bodyOnLoad()" { + + wpCommonPageLayout contacts "$c" "$f" "$u" "Contacts" [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/contacts"] Contacts 0 searchContent('contacts','clistContacts')] "" { + # CONTEXT COMMANDS + cgi_division class=hdrBtns { + cgi_javascript { + cgi_put "if(window.print) document.write('[cgi_buffer {cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"]}]');" + } + + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi2" ""][cgi_span "class=hdrBtnText" Settings]" "settings"] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" "javascript:openHelpWindow('contacts.html');" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"] + } + } { + # TO MENUBAR + cgi_anchor_name "toolbar" + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb13" "New Contact"] "contacts/new" title="Create new contact" "onClick=return contactEditor({which:'add'},storeNewContact);"] + + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb14" "New Group"] "contacts/new/group" title="Create new group contact" "onClick=return contactEditor({which:'add',group:true},storeNewContact);"] + } + cgi_table_data class="dv1" { + cgi_puts [cgi_img "img/cbn/div.gif"] + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb9" "Send Email"] "send" title="Send email to selected contact" "onClick=return sendToContact();"] + } + cgi_table_data class=wap { + cgi_puts [cgi_url "[cgi_img "img/cbn/edit.gif" class=wap] Edit" "#" title="Edit selected contact" "onClick=return editCheckedContact();"] + } + cgi_table_data class=wap { + cgi_puts [cgi_url "[cgi_img "img/cbn/delete.gif" class=wap] Delete" "#" title="Delete selected contact" "onClick=return contactDelete();"] + } + cgi_table_data class="dv1" { + cgi_puts [cgi_img "img/cbn/div.gif"] + } + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=\"menuHdr\">[cgi_url "More Actions [cgi_img "img/cbn/menu.gif" class="wap menuDn menuImg"]" "#" "onClick=return false;"]<div>" + cgi_bullet_list { + cgi_li [cgi_url "Import vCards" "#" [noimp "vCard import"]] + cgi_li [cgi_url "Export vCards" "#" [noimp "vCard export"]] + } + cgi_puts "</div></li>" + } + } + cgi_table_data width="100%" { + cgi_puts [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } + } + cgi_puts "</tbody>" + } + } { + # MAIN PAGE CONTENT + cgi_puts "Loading..." + } { + # BOTTOM MENUBAR + cgi_table class="wap toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap pageText" id=contactCount { + cgi_puts "" + } + cgi_table_data width="100%" { + cgi_puts [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } + + # any debugging info to insert? + foreach dmsg $dmsgs { + cgi_html_comment "DEBUG: $dmsg" + cgi_puts "" + } + } + } +} diff --git a/web/cgi/alpine/2.0/css/cbn/contactdialog.css b/web/cgi/alpine/2.0/css/cbn/contactdialog.css new file mode 100644 index 00000000..8f9d64c9 --- /dev/null +++ b/web/cgi/alpine/2.0/css/cbn/contactdialog.css @@ -0,0 +1,108 @@ +/* + * $Id: contactdialog.css 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +div#contactsDialogFramework +{ + display: none; +} + +div#contactDialog +{ + overflow: hidden; +} + +div.clistInstructions +{ + padding: 15px 5px 20px 5px; + text-align: center; +} + +div.contactContent +{ + font-size: .8em; + height: 14.5em; + border: 1px solid #aaaaaa; +} + +div.clistContext +{ + border-bottom: 1px solid #36c; + padding: .5em 0; + font-weight: bold; + color: #003399; + background-color: #e7f0ff; + overflow: hidden; +} + +div.clistContext * +{ + margin-left: 5px; +} + +div.clistContext img +{ + vertical-align: text-bottom; +} + +div.clistContext a +{ + color: #003399; +} + +span.clistContact +{ + color: black; +} + +div.clistContacts +{ + overflow: auto; + height: 12em; +} + +input#dirQuery +{ + padding: 0 2px; +} + +div.clistContacts table tr td +{ + padding: none; + border: none; + font-size: .8em; + white-space: nowrap; +/* width: 100%; +*/ +} + +td.fli +{ + width: 24px; + text-align: center; +} + +tr#flPick, tr#flPick a +{ + color: #ffffff; + background-color: #417bd9; +} + +a.fln +{ + text-decoration: none; +} + +td.clcd +{ +} diff --git a/web/cgi/alpine/2.0/css/cbn/contacts.css b/web/cgi/alpine/2.0/css/cbn/contacts.css new file mode 100644 index 00000000..29a1148e --- /dev/null +++ b/web/cgi/alpine/2.0/css/cbn/contacts.css @@ -0,0 +1,87 @@ +/* + * $Id: contacts.css 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +div.clistInstructions +{ + padding: 15px 5px 20px 5px; + text-align: center; +} + +div#alpineContent +{ + font-size: .9em; +} + +div.clistContext +{ + border-bottom: 1px solid #36c; + padding: .5em 0; + font-weight: bold; + color: #003399; + background-color: #e7f0ff; + overflow: auto; +} + +div.clistContext * +{ + margin-left: 5px; +} + +div.clistContext img +{ + vertical-align: text-bottom; +} + +div.clistContext a +{ + color: #003399; +} + +div.clistContacts +{ + width: 100%; + padding-top: 3px; + overflow-y: auto; +} + +div.clistContacts table +{ + width: 100%; + padding: none; + border: none; +} + +div.clistContacts table tbody +{ + border-bottom: 1px solid #D4D4D4; +} + +div.clistContacts table tbody tr +{ + border-bottom: 1px solid #36c; +} + +table.clt +{ +} + +td.cli +{ + width: 12mm; + padding: 5mm 0 5mm 10mm; +} + +td.cln +{ +}
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/css/cbn/folderdialog.css b/web/cgi/alpine/2.0/css/cbn/folderdialog.css new file mode 100644 index 00000000..9f09c647 --- /dev/null +++ b/web/cgi/alpine/2.0/css/cbn/folderdialog.css @@ -0,0 +1,96 @@ +/* + * $Id: folderdialog.css 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +div.flistInstructions +{ + padding: 15px 5px 20px 5px; + text-align: center; +} + +div#folderList +{ + font-size: .8em; + height: 14.5em; + border: 1px solid #aaaaaa; +} + +div.flistContext +{ + border-bottom: 1px solid #36c; + padding: .5em 0; + font-weight: bold; + color: #003399; + background-color: #e7f0ff; +} + +div.flistContext * +{ + margin-left: 5px; +} + +div.flistContext img +{ + vertical-align: text-bottom; +} + +div.flistContext a +{ + color: #003399; +} + +span.flistFolder +{ + color: black; +} + +div.flistFolders +{ + overflow: auto; + height: 12em; +} + +div.flistFolders a +{ + font-size: .8em; +} + +table.flt +{ + border: none; + width: 100%; +} + +td.fli +{ + width: 24px; + text-align: center; +} + +tr#flPick, tr#flPick a +{ + color: #ffffff; + background-color: #417bd9; +} + +a.fln +{ + text-decoration: none; +} + +td.flcd +{ + font-size: .9em; + padding-left: 3em; + padding-bottom: 1.5em; +} diff --git a/web/cgi/alpine/2.0/css/cbn/folders.css b/web/cgi/alpine/2.0/css/cbn/folders.css new file mode 100644 index 00000000..5c190f75 --- /dev/null +++ b/web/cgi/alpine/2.0/css/cbn/folders.css @@ -0,0 +1,99 @@ +/* + * $Id: folders.css 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +div.flistInstructions +{ + padding: 15px 5px 20px 5px; + text-align: center; +} + +div#alpineContent +{ + font-size: .9em; +} + +div.flistContext +{ + border-bottom: 1px solid #36c; + padding: .5em 0; + font-weight: bold; + color: #003399; + background-color: #e7f0ff; + overflow: auto; +} + +div.flistContext * +{ + margin-left: 5px; +} + +div.flistContext img +{ + vertical-align: text-bottom; +} + +div.flistContext a +{ + color: #003399; +} + +span.flistFolder +{ + color: black; + vertical-align: middle; +} + +div.flistFolders +{ + padding-top: 3px; + overflow-y: auto; +} + +table.flt +{ + padding: none; + border: none; + width: 100%; +} + +td.fli +{ + width: 24px; + text-align: center; + padding-left: 12px; +} + +tr.flr +{ + border-bottom: 1px solid #36c; +} + +tr#flPick, tr#flPick a +{ + color: #ffffff; + background-color: #417bd9; +} + +.fln +{ + text-decoration: none; + font-size: .9em; +} + +td.flcd +{ + font-size: .9em; + padding-left: 3em; + padding-bottom: 1.5em; +} diff --git a/web/cgi/alpine/2.0/css/cbn/screen.css b/web/cgi/alpine/2.0/css/cbn/screen.css new file mode 100644 index 00000000..ec2107aa --- /dev/null +++ b/web/cgi/alpine/2.0/css/cbn/screen.css @@ -0,0 +1,2084 @@ +/* + * $Id: screen.css 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/*** GLOBAL ***/ +body.wap +{ + font-family: Tahoma, Helvetica, sans-serif; + margin: 0 0; +} +form.wap +{ + display: inline; +} +select.wap, input.wap, textarea.wap, button.wap, label.wap +{ + font-family: Tahomaf, Helvetica, sans-serif; + font-size: 1.0em; /* required by IE */ +} +td.wap, th.wap, div.wap +{ + white-space: nowrap; + font-size: .7em; +} +h1.wap +{ + display: inline; + font-weight: normal; + font-size: 1.0em; +} +h2.wap, h3.wap, h4.wap, h5.wap, h6.wap +{ + display: inline; +} +a.wap +{ + color: #003399; + text-decoration: none; +} +a.wap:hover +{ + text-decoration: underline; +} +img.wap +{ + border-style: none; +} +.rt +{ + text-align: right; +} +.lt +{ + text-align: left; +} +.frt +{ + float: right; +} +.flt +{ + float: left; +} +.right +{ + padding-right: 10px; + float: right; +} +.left +{ + float: left; +} +.bld +{ + font-weight: bold; +} +.top +{ + vertical-align: top; +} +.black +{ + color: black; +} +span.sp, input.sp +{ + background: url(../../img/cbn/spritelib.gif) no-repeat; +} +span.sp span +{ + display: none; +} +span.trans +{ + display: block; + width: 24px; + height: 24px; +} + +/*** STATUS MESSAGES ***/ +div#statusMessage +{ + display: none; + position: relative; +} +div.status +{ + + color: black; + margin: 0 10mm 0 20mm; + height: 15px; + overflow: hidden; + vertical-align: middle; + background: #ffffa6 url(../../img/cbn/spritelib.gif) no-repeat 0 -1104px; +} + +div.status div.center +{ + text-align: center; + margin-left: 36px; + margin-right: 36px; +} + +div.status div.edge +{ + text-align: left; + width: 32px; + height: 15px; +} + +div.status div.cap +{ + width: 1px; + height: 15px; + background: #ffffa6 url(../../img/cbn/spritelib.gif) no-repeat 0 -1104px; +} + +a#statuslink +{ + color: black; + text-decoration: none; +} +a#statuslink:hover +{ + text-decoration: underline; +} + +/*** STATUS MESSAGE ICONS ***/ +span.spsm +{ + display: block; + width: 12px; + height: 12px; + overflow: hidden; + margin: 1px 0 0 10px; +} +span.sm1 +{ + background-position: 0 -1056px; +} +span.sm2 +{ + background-position: 0 -1080px; +} + +/*** MESSAGE PRIORITY STYLES ***/ +span.prioHigh +{ + font-weight: bold; + color: #DD0000; +} +span.prioNorm +{ + color: #008800; +} +span.prioLow +{ + color: #000088; +} + +/*** SKIP TO MESSAGE LIST (for screen readers and mobility impaired) ***/ +#skip a, #skip a:visited +{ + position: absolute; + top: 0; + left: -999px; + padding: 0 5px 1px 5px; + margin: 2px 0 0 1px; +} + +#ie6Fix:active, #skip a:active, #skip a:focus, #skip a:hover +{ + position: absolute; + top: 0; + left: 0; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10pt; + color: #00FF00; + background-color: #000000; +} + +/*** PAGE LAYOUT ***/ +table.page +{ + background-color: #FFFFFF; + width: 100%; + height: 100%; +} +table.page td.checkMailandCompose +{ + height: 100%; + vertical-align: top; +} +table.page td.spc +{ + background-color: #000000; + width: 5px; +} +table.page td.topHdr +{ + vertical-align: bottom; + background: #000000 url(../../img/cbn/btnbg.gif) repeat; +} +table.content +{ + width: 100%; + height: 100%; +} +div.contentBody +{ + width: 100%; +} +div.contentBodyHTML +{ + padding: 6px; +} +div.contentDeadSession +{ + margin-top: 1.75em; + text-align: center; + font-size: 1.75em; + font-weight: bold; +} +table.page img.logo +{ + position: absolute; + top: 0; + left: 0; + width: 182px; + height: 72px; + margin-bottom: 5px; +} +table.page span.logo +{ + position: absolute; + top: 50px; + left: 14px; + color: white; + font-size: .8em; +} + +/*** NO SCRIPT WARNING ***/ +.noscript +{ + text-align: center; + font-size: .8em; + line-height: 2em; + background-color: #ffffa6; + border-left: 1px solid black; + border-right: 1px solid black; +} + + +/*** HEADER BUTTONS ***/ +div.hdrBtns +{ + float: right; +} +span.hdrBtnText +{ + display: block; + float: left; + cursor: pointer; +} +span.hdrBtnImg +{ + display: block; + float: left; + height: 16px; + width: 16px; + margin: 0 6px 0 14px; + cursor: pointer; +} +span.hbi1 { background-position: 0 -768px; } +span.hbi2 { background-position: 0 -792px; } +span.hbi3 { background-position: 0 -816px; } +span.hbi4 { background-position: 0 -840px; } + +span.newsImg +{ + display: block; + float: left; + height: 16px; + width: 16px; + margin-top: 3px; + margin-right: 6px; + cursor: pointer; + background-position: 0 -1800px; +} + +/*** SEARCH ***/ +.searchFormDiv +{ + padding: 2mm 2mm 0 2mm; + margin-top: 0; + margin-bottom: 0; +} +#searchForm +{ + margin-bottom: 0; + margin-top: 0; +} +#searchField +{ + width: 80%; +} +input.searchBtn +{ + width: 19px; + height: 19px; + margin-left: 2mm; + border: none; + background-position: 0 -1152px; +} +#searchAdvance +{ + float: left; + padding-top: 1mm; + padding-left: 2mm; +} +#searchClear +{ + float: right; + width: 2em; + padding-top: 1mm; + padding-right: 4mm; +} +#searchRefine +{ + clear: both; + padding-top: 1.5mm; + text-align: left; +} +#searchResult +{ + clear: both; + padding-left: 10px; + padding-top: 3px; +} + +span.searchMatch +{ + background-color: yellow; + font-size: larger; +} + +/*** TOOLBAR ***/ +div.toolBar +{ + border: 1px solid yellow; + height: 3em; + background: #000000 url(../../img/cbn/btnbg.gif) repeat; + color: #ffffff; + float: left; + padding: 0 0 1px 0; +} +span.toolBarText +{ + display: block; + float: left; + margin: .75em 4px 0 4px; +} +span.toolBarImg +{ + display: inline-block; + height: 24px; + width: 24px; +} +span.toolBarBtn +{ + float: left; + margin-top: .4em; + margin-left: .4em; +} +.toolBarBtnLeft +{ + margin-left: 1mm; +} +.toolBarBtnRight +{ + position: absolute; + right: 0; +} +span.toolBarNav +{ + float: right; + cursor: pointer; + margin-top: .4em; +} +span.toolBarSep +{ + display: block; + height: 24px; + margin: 4px 2px 0 2px; +} +span.toolBarSepBtn +{ + float: left; +} +span.toolBarSepNav +{ + float: right; +} +div.toolBar a +{ + height: 3em; + display: block; + float: left; + color: #FFFFFF; +} +div.toolBar a:hover +{ + cursor: pointer; + text-decoration: none; + background: #000000 url(../../img/cbn/btnhi.gif) repeat; + color: #FFFFFF; +} +div.toolBarMenu +{ + float: left; +} + +span.tbi1 { background-position: 0 -120px; } +span.tbi2 { background-position: 0 -312px; } +span.tbi3 { background-position: 0 -336px; } +span.tbi4 { background-position: 0 -864px; } +span.tbi5 { background-position: 0 -888px; } + + +table.toolbarTbl +{ + background: #000000 url(../../img/cbn/btnbg.gif) repeat; + border-left: 1px solid #777777; + border-top: 1px solid #777777; + height: 38px; + width: 100%; +} +table.toolbarTbl td +{ + border-bottom: 1px solid #777777; +} +table.toolbarTbl a +{ + color: #FFFFFF; + margin: 0 0; +} +table.toolbarTbl a:hover +{ + text-decoration: none; + background: #000000 url(../../img/cbn/btnhi.gif) repeat; + color: #FFFFFF; +} +table.toolbarTbl td.tbPad +{ + border-right: 1px solid #777777; + padding: 0; + vertical-align: top; +} +table.toolbarTbl a +{ + display: block; + padding: 3px 8px 4px 0; + text-decoration: none; +} +table.toolbarTbl a img +{ + vertical-align: middle; +} +table.toolbarTbl td.pageText +{ + color: #ffffff; + padding-left: 5px; +} +table.toolbarTbl td.pageBtns +{ + color: #ffffff; +} +table.toolbarTbl td.pageBtns a, table.toolbarTbl td.pageBtns a img +{ + padding: 0; + margin: 0; +} +table.toolbarTbl td.pageBtns a:hover +{ + background: inherit; +} + + +/**** Header Context ****/ +div.wapContext { + height: 5em; +} + +/**** Menu Bars ****/ +div.wapMenuLeft +{ + float: left; + width: 14em; /* sidebar width */ +} + +div.wapMenuRight +{ + height: 100%; + margin-left: 14em; + border-left: 4px solid black; +} + +/*** LEFT COLUMN ***/ +table.leftColumn +{ + clear: left; + width: 100%; +} + +/*** Sidebar ***/ +div.wapSidebar +{ + float: left; + width: 14em; /* sidebar width */ +} + +/*** FOLDER PANE ***/ +div.folderPane +{ + margin: 5px 0; + padding: 10px 0; + border-top: thin groove; + border-bottom: thin groove; + overflow: hidden; +} +div.folderList div +{ + clear: both; +} +div.fld +{ + height: 20px; + line-height: 18px; + padding-left: 10px; + margin-top: 3px; +} + +div.ftitle +{ + padding: 0 0 4px 12px; + font-weight: bold; +} +div.fld span +{ + color: #000000; +} +div.fld span.unrd +{ + color: #707070; +} +div.sel span.unrd, div.sel span, div.sel span a +{ + color: #ffffff; +} +div.sel +{ + color: #ffffff; + background: #dae7fc url(../../img/cbn/spritelib.gif) repeat-x 0 -912px; +} +div.sel a, div.sel a span, div.sel a:hover +{ + color: #ffffff; +} +div.folderList span.left /* requires .left class */ +{ + text-align: left; +} +div.folderList span.right /* requires .right class */ +{ + font-weight: normal; +} +div.folderList span.right a /* requires .right class */ +{ + color: #003399; +} +div.folderList div.lnk a +{ + color: #003399; +} + +/*** SIMPLE LIST ***/ +table.listTbl +{ + width: 100%; +} +table.listTbl td, table.listTbl th +{ + padding: 0 3px; +} +table.listTbl td img, table.listTbl th img +{ + vertical-align: middle; + width: 17px; + height: 17px; +} +table.listTbl tr.unread, h1.unread +{ + font-weight: bold; +} +table.listTbl tr.ac, table.listTbl tr.ac a +{ + background-color: #f4f6f8; +} +table.listTbl tr#sd, table.listTbl tr#sd a, tr.choice +{ + color: #ffffff; + background-color: #417bd9; +} +table.listTbl tbody +{ + overflow: hidden; +} +table.listTbl th.colHdr +{ + border-top: 0; + height: 17px; + background: #f3f3f3 url(../../img/cbn/spritelib.gif) repeat-x 0 -936px; +} +table.listTbl th.selColHdr a +{ + color: #000000; +} +table.listTbl th.colHdr a +{ + color: #000000; +} +table.listTbl th a:hover +{ + text-decoration: none; +} +table.listTbl th.selColHdr +{ + border-top: 0px; + height: 17px; + background: #d4d4d4 url(../../img/cbn/spritelib.gif) repeat-x 0 -960px; +} +table.listTbl th.selColHdr img.selectedDn +{ + width: 8px; + height: 8px; + vertical-align: middle; +} +table.foldermgmt td, table.foldermgmt th +{ + border-bottom: 1px solid #eeeeee; +} +table.foldermgmt a +{ + font-weight: bold; +} +table.foldermgmt td.parent a +{ + font-weight: normal; +} +table.foldermgmt img +{ + padding-right: 5px; +} +table.divider td, table.divider th +{ + border-bottom: 1px solid #eeeeee; +} +table.listTbl td.nodivider +{ + border-bottom: none; +} + +/*** FOOTER ***/ +table.page td.footer +{ + color: #FFFFFF; + background-color: #000000; + height: 30px; +} +table.page td.footer img +{ + margin-right: 6px; + vertical-align: bottom; +} +table.page td.footer a +{ + color: white; +} + +/*** MESSAGE VIEW ***/ + +table.msgHead +{ + background-color: #f9f9f9; + border-left: 1px solid #aaaaaa; + border-right: 1px solid #aaaaaa; + border-bottom: 1px solid #aaaaaa; + width: 100%; +} +table.msgHead td.subText +{ + padding: 5px 0 0 6px; + font-size: 1.1em; + font-weight: normal; +} +table.msgHead span.right +{ + font-weight: normal; +} +table.msgHead span.right a +{ + color: #003399; +} +table.msgHead td.hdrLabel +{ + padding: 4px 0 0 6px; + /* breaks on IE if width is set to 90px or less */ + width: 100px; + vertical-align: top; + font-weight: bold; +} +table.msgHead td.hdrText +{ + width: 100%; + padding: 4px 0 0 4px; + text-align: left; + white-space: normal; +} +table.msgHead td.hdrText span.return img +{ + vertical-align: top; +} +table.msgHead td.hdrText span.return a +{ + font-weight: bold; +} +table.msgHead td.hdrText span.contactAddr +{ + float: left; + padding-right: 5px; +} + +td.contentBody +{ + white-space: normal; + padding: 10px 0 0 6px; +} +table.msgHead a.addContact +{ + color: #003399; + padding-left: 10px; + vertical-align: text-top; +} +table.msgHead a.addContact img +{ + vertical-align: text-top; +} +table.msgHead span.emailAddr, table.msgHead span.attach +{ + white-space: nowrap; +} +table.msgHead span.attach img +{ + vertical-align: middle; +} +table.msgHead span.attach a +{ + text-decoration: underline; + float: left; + padding-right: 10px; +} +td.msgRawHead +{ + font-family: courier, monospace; +} + + + +/*** COMPOSE ***/ +table.compose +{ + padding: 0px 10px; + background-color: #f9f9f9; + border-left: 1px solid #aaaaaa; + border-right: 1px solid #aaaaaa; + width: 100%; +} +table.compose td.spc +{ + background-color: #f9f9f9; + height: 6px; + width: 100%; +} +table.compose td.spc * +{ + vertical-align: middle; +} +table.compose td.lbl +{ + padding-right: 5px; + vertical-align: top; + width: 1%; +} +table.compose td.lbl input +{ + width: 40px; +} +table.compose td.lbl label +{ + padding-left: 2px; +} +table.compose td.lbl * +{ + vertical-align: top; +} +table.compose td.mid +{ + width: 100%; + padding: 0px; +} +table.compose td.mid * +{ + vertical-align: top; +} +table.compose td.mid textarea, table.compose td.mid input +{ + border: 1px solid #aaaaaa; + margin: 0; + padding: 1px 3px 1px 3px; + xheight: 1.7em; + width: 100%; + overflow-y: auto; + word-wrap: break-word; +} +textarea.mid, input.mid +{ + height: 1.7em; +} +table.compose td.rgt +{ + padding-left: 5px; + vertical-align: top; + width: 1%; +} +table.compose td.rgt * +{ + vertical-align: top; +} +table.compose td.attach * +{ + vertical-align: middle; +} +table.compose img.attachment +{ + width: 17px; + height: 17px; +} +table.compose img.rmAttach +{ + vertical-align: top; + width: 15px; + height: 15px; +} +table.composeBody +{ + background-color: #f9f9f9; + border-left: 1px solid #aaaaaa; + border-right: 1px solid #aaaaaa; + width: 100%; + height: 100%; +} +table.composeBody td.textBody +{ + height: 100%; + padding: 10px 6px 0 6px; + vertical-align: top; +} +table.composeBody td.textBody textarea +{ + border: 1px solid #aaaaaa; + width: 100%; + height: 98%; + padding: 4px 6px; + word-wrap: break-word; +} +span#lessComposeHeaderText +{ + display: none; +} +div#moreComposeHeaders +{ + display: none; +} +div#composeAttachments +{ + display: none; +} +span.attachmentName +{ + white-space: nowrap; + padding-right: .25em; +} + +/*** GENERAL FIELDS (e.g. settings, advance search, contact details, etc.) ***/ +table.fields +{ + font-size: .7em; + width: 95%; + margin: 10px 20px; +} +table.fields td.title +{ + width: 20%; + font-weight: bold; + vertical-align: top; + color: #555555; +} +table.fields td.body +{ + vertical-align: top; + width: 80%; +} +table.fields td.body * +{ + vertical-align: middle; +} +table.fields td.title, table.fields td.body +{ + padding: 8px 0; + border-bottom: 1px solid #CCCCCC; +} +table.fields td.nodivider +{ + border-bottom: none; +} +table.fields td span.label +{ + font-weight: bold; +} +table.fields td a +{ + font-weight: normal; +} +table.fields td * +{ + vertical-align: bottom; +} +table.fields span.tips +{ + color: #000000; + font-weight: normal; +} + + +/*** SETTINGS (requires "fields" class) ***/ +table.settings td.title, table.settings td.body +{ + padding: 12px 12px 12px 0; +} + +div#advancedSettings +{ + display: none; +} + +/*** CONTACTS (requires "fields" class) ***/ +table.contacts *.contactText +{ + width: 90%; +} + +/*** CONTACTS EDITOR ***/ +form.contactEditor +{ + color: #555555; + font-size: .7em; + padding: 0 12px; +} +form.contactEditor div.contactSection +{ + overflow: auto; + padding: 8px 0; + border-bottom: 1px solid silver; +} +form.contactEditor div.context +{ + font-size: 1.7em; + font-weight: bold; + padding-bottom: 8px; +} +form.contactEditor div.contactField +{ + float: left; + font-weight: bold; + width: 10em; +} +form.contactEditor input, form.contactEditor select +{ + width: 370px; +} +form.contactEditor textarea +{ + height: 6em; + width: 370px; +} + +/*** ADVANCED SEARCH ***/ +form.advanceSearch +{ + color: #555555; + font-size: .7em; + padding: 0 12px; +} +form.advanceSearch div.searchSection +{ + overflow: auto; + padding: 8px 0; + border-bottom: 1px solid silver; +} +form.advanceSearch div.context +{ + font-size: 1.7em; + font-weight: bold; + padding-bottom: 8px; +} +form.advanceSearch div.scope +{ + text-align: center; + padding: 6px 0; +} +form.advanceSearch div div.searchField +{ + line-height: 2em; + font-weight: bold; + float: left; + width: 8em; +} +form.advanceSearch div div.searchType +{ + float: left; + padding-right: 10px; +} +form.advanceSearch div div.searchType select +{ + width: 12em; +} +form.advanceSearch div div.searchTerm +{ + height: 2em; + line-height: 2em; +} +form.advanceSearch div div.searchTerm input +{ + width: 18em; +} + +/*** CONTACTS (requires "fields" class) ***/ +div.attachfiles +{ + margin: 20px 20px; +} +div.attachfiles td +{ + vertical-align: middle; + padding: 3px 0; +} + + +/*** MAIN HEADER (i.e. RSS news feed, weather bar, storage meter) ***/ +div.hdrContent +{ + overflow: hidden; +} +div.hdrContent, div.hdrContent a +{ + text-decoration: none; + color: #FFFFFF; +} +div.hdrContent a:hover +{ + text-decoration: underline; +} +div.hdrContent span.RSS +{ + line-height: 2em; + clear: both; +} +div.wbar +{ + height: 15px; + line-height: 15px; + padding-left: 5px; + padding-right: 5px; + background: #000000 url(../../img/cbn/spritelib.gif) repeat-x 0 -1128px; + +} +div.wbar div.weather +{ + text-align: center; + float: left; + padding-left: 20em; +} +div.wbar div.usage +{ + float: right; + width: 18em; +} +div.hdrContent div.pageTitle +{ + width: 55%; + float: left; + clear: left; + text-align: left; + color: #FFFFFF; + font-size: 1.8em; + font-weight: normal; + padding: 4px 0 4px 5px; +} +div.hdrContent div.commands +{ + float: right; + margin: 8px 7px 0 0; +} + +/*** INLINE MESSAGES ***/ +div#bannerConfirm +{ + font-weight: bold; + text-align: center; + padding: 3px 5px; + color: #000000; + background-color: #ffecda; + border-bottom: 1px solid #aaaaaa; +} +div#bannerConfirm img +{ + vertical-align: middle; +} + +div#bannerError +{ + font-weight: bold; + text-align: center; + padding: 3px 5px; + color: #ffffff; + background-color: #ff0000; + border-bottom: 1px solid #aaaaaa; +} +div#bannerError img +{ + vertical-align: middle; +} + +div.bannerPrivacy +{ + font-weight: bold; + line-height: 1.4em; + padding: 3px 5px; + background-color: #ffffd2; + border-bottom: 1px solid #aaaaaa; +} +div.bannerPrivacy a +{ + font-weight: normal; +} +div.bannerPrivacy img +{ + padding-right: 8px; + float: left; +} + + +div.bannerSearch +{ + text-align: center; + padding: 5px 60px 5px 5px; + background-color: #eeeeee; + border-bottom: 1px solid #aaaaaa; +} +div.bannerSearch * +{ + vertical-align: middle; +} +div.bannerSearch input.text +{ + width: 15em; +} + + +div#bannerSelection +{ + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: .7em; + display: none; + text-align: center; + padding: 4px 5px; + color: #000000; + border-bottom: 1px solid #aaaaaa; +} + + +table.bannerFolderSearch +{ + width: 100%; + padding: 5px 5px 5px 5px; + background-color: #e7f0ff; + border-bottom: 1px solid #aaaaaa; +} +table.bannerFolderSearch td.title +{ + text-align: left; +} +table.bannerFolderSearch td.body +{ + text-align: right; +} +table.bannerFolderSearch img +{ + margin-right: 5px; + vertical-align: middle; +} +table.bannerFolderSearch a +{ + color: #003399; + font-weight: bold; + text-decoration: underline; +} + + +/*** MOVE/COPY TO FOLDER UI ***/ +.moveToFolder * +{ + vertical-align: middle; +} +.moveToFolder input +{ + width: .9em; + height: .9em; +} +.moveToFolder input +{ + margin-top: 2px; /* fix for IE */ +} +.moveToFolder label +{ + padding-right: 4px; + color: #FFFFFF; +} +.moveToFolder select +{ + position: relative; + bottom: 8px; +} + +.attachFiles +{ + margin: 15px; +} + +.attachFiles input[type="button"] +{ + margin-left: 5px; +} + +div.attachInput +{ + margin: 2px 2px 2px 0; +} +div.attachInput form +{ + margin-bottom: 0; +} + +div.drop +{ + background-color: #66ffff; +} + +/*** Loading Notification ***/ +div#bePatient +{ + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: .6em; + font-weight: bold; + background-color: #ffffa6; + color: #000000; + padding: 4px 5px; + border-bottom: 2px solid black; + border-right: 2px solid black; + left: -999px; + top: -999px; + margin-left: -1px; + position: absolute; +} + +/*** Normal Message Text ***/ +.messageText +{ + margin: 10px 0 0 6px; + font-family: monospace; + white-space: pre; +} + +/*** Tool Tip ***/ +div#tipDrag { + border: 1px solid black; + padding: 1px 3px; + background-color: #fffacd; + font-size: 0.7em; +} + +/*** Panel Framework ***/ +/*#panel_c.yui-panel-container.shadow .underlay +{ + left:3px; + right:-3px; + top:3px; + bottom:-3px; + position:absolute; + background-color:#000; + opacity:0.12; + filter:alpha(opacity=12); +}*/ + +.yui-panel +{ + position:relative; + border:none; + overflow:visible; + background:transparent url(../../img/cbn/border-rt.gif) repeat-y top right; +} + +.yui-panel .container-close +{ + position:absolute; + top:5px; + right:10px; + height:14px; + width:14px; + background:url(../../img/cbn/spritelib.gif) no-repeat 0 -1224px; +} + +.yui-panel .hd +{ + border:none; + background:url(../../img/cbn/spritelib.gif) repeat-x 0 -1248px; + color:#FFF; + height:24px; + margin: 0 4px; + text-align:left; + vertical-align:middle; + overflow:visible; +} + +.yui-panel .bd +{ + overflow:hidden; + padding: 10px; + border:none; + background:#FFF url(../../img/cbn/border-lt.gif) repeat-y; + margin-right:4px; +} + +.yui-panel .ft +{ + background:url(../../img/cbn/spritelib.gif) repeat-x 0 -1272px; + font-size:4px; + height:4px; + padding:0px 10px; + border:none +} + +.yui-panel .hd span +{ + padding-left: 4px; + line-height:24px; + vertical-align:middle; + font-weight:bold; +} + +.yui-panel .hd .tl +{ + width:4px; + height:24px; + top:0; + left:0; + background:url(../../img/cbn/spritelib.gif) no-repeat 0 -1296px; + position:absolute; +} + +.yui-panel .hd .tr +{ + width:4px; + height:24px; + top:0; + right:0; + background:url(../../img/cbn/spritelib.gif) no-repeat 0 -1320px; + position:absolute; +} + +.yui-panel .ft .bl +{ + width:4px; + height:4px; + bottom:0; + left:0; + background:url(../../img/cbn/spritelib.gif) no-repeat 0 -1344px; + position:absolute; +} + +.yui-panel .ft .br +{ + width:4px; + height:4px; + bottom:0; + right:0; + background:url(../../img/cbn/spritelib.gif) no-repeat 0 -1348px; + position:absolute; +} + +/*** Internal Panel Elements ***/ +div.dialogIcon +{ + width: 60px; + height:60px; + float: left; +} + +div.alert +{ + background:url(../../img/cbn/alert.gif) no-repeat top center; +} + +div.prompt +{ + background:url(../../img/cbn/question2.jpg) no-repeat top center; +} + +div.dialog +{ + background:url(../../img/cbn/question2.jpg) no-repeat center top; +} + +div#alertBody +{ + margin-left: 60px; + padding: 5px; +} + +div#promptBody +{ + margin-left: 60px; + padding: 5px; +} + +div#dialogBody +{ + margin-left: 60px; + width: 540px; + padding: 5px; + overflow: auto; +} + +div.dialogButtons +{ + padding-top: 10px; + background-color: #ffffff; + text-align:right; +} + +div.panelExplanation +{ + width: 80%; + text-align: center; + padding: 1em 0; +} + +div.panelInput +{ + text-align: center; + overflow: auto; +} + +div.panelInput input +{ + padding: 0 2px; + margin-left: 8px; +} + +/*** Viewport Height Limiter ***/ +div#alpineContent +{ + height: 100%; + overflow: auto; +} + +/*** Compose Checkpoint Result ***/ +#formResponse +{ + position: absolute; + top: 0; + left: -999px; +} + +/*** Sprite based images ****/ + +/* left column icons */ +span.splci +{ + display:block; + line-height: 24px; + padding-left: 30px; + margin-left: 4px; + cursor: pointer; +} + +span.splcs +{ + display:block; + line-height: 20px; + padding-left: 30px; + margin-left: 4px; + cursor: pointer; +} + +span.splc +{ + width: 17px; + height: 17px; + float: left; + margin-right: 8px; + margin-top: 1px; +} + +span.splc1 +{ + background-position: 0 -24px; +} + +span.splc2 +{ + background-position: 0 -48px; +} + +span.splc3 +{ + background-position: 0 -72px; +} + +span.splc4 +{ + background-position: 0 -96px; +} + +span.splc5 +{ + background-position: -4px -122px; +} + +span.splc6 +{ + background-position: -3 -146px; +} + +span.splc7 +{ + background-position: 0 -168px; +} + +span.splc8 +{ + background-position: 0 -192px; +} + +span.splc9 +{ + background-position: 0 -1632px; +} + +span.splc10 +{ + background-position: 0 -1656px; +} +span.splc11 +{ + background-position: 0 -1680px; +} +span.splc12 +{ + background-position: 0 -1776px; +} + +/* menu bar icons */ +span.spmb +{ + display: block; + width: 24px; + height: 24px; + cursor: pointer; +} + +span.spmbi +{ + display:block; + line-height: 28px; + padding-left: 28px; + margin-left: 4px; + cursor: pointer; +} + +span.spmbf +{ + background-position: 0 -216px; +} + +span.spmbp +{ + background-position: 0 -240px; +} + +span.spmbn +{ + background-position: 0 -264px; +} + +span.spmbl +{ + background-position: 0 -288px; +} + +span.spmbu +{ + background-position: 0 -1008px; +} + +span.spmbd +{ + background-position: 0 -1032px; +} + +span.spmb1 +{ + margin-left: 6px; + background-position: 0 -312px; +} + +span.spmb2 +{ + background-position: 0 -336px; +} + +span.spmb3 +{ + width: 1px; + background-position: 0 -360px; +} +span.spmb4 +{ + background-position: 0 -1368px; +} +span.spmb5 +{ + background-position: 0 -1392px; +} +span.spmb6 +{ + background-position: 0 -1416px; +} +span.spmb7 +{ + background-position: 0 -116px; +} +span.spmb7 +{ + background-position: 0 -116px; +} +span.spmb8 +{ + background-position: 0 -1438px; +} +span.spmb9 +{ + background-position: 0 -1462px; +} +span.spmb10 +{ + background-position: 0 -1486px; +} +span.spmb11 +{ + background-position: 0 -570px; +} +span.spmb12 +{ + background-position: 0 -1510px; +} +span.spmb13 +{ + background-position: 0 -140px; +} +span.spmb14 +{ + background-position: 0 -1172px; +} +span.spmb15 +{ + background-position: 0 -310px; +} +span.spmb16 +{ + background-position: 0 -334px; +} +span.spmb17 +{ + background-position: 0 -884px; +} +span.spmb18 +{ + background-position: 0 -1534px; +} +span.spmb19 +{ + background-position: 0 -1556px; +} +span.spmb20 +{ + background-position: 0 -1582px; +} +span.spmb21 +{ + background-position: 0 -1752px; +} + +span.rof +{ + display: block; + float: right; +} + +/*** Priority Radio Button ***/ + +/* radio button icons */ +span.sprb +{ + width: 20px; + height: 20px; + display: block; + float: left; + padding-right: .3em; + background-position: 0 -384px; +} + +span.prbc +{ + background-position: 0 -408px; +} + +/* message list icons */ +span.spml +{ + display: block; + width: 17px; + height: 17px; +} + +span.blank, a.mlstat span.nostar +{ + background-position: 0 0; +} + +span.spml1 +{ + background-position: 0 -456px; +} + +span.spml2 +{ + background-position: 0 -480px; +} + +span.spml3 +{ + background-position: 0 -504px; +} + +span.spml4 +{ + background-position: 0 -528px; +} + +span.spml5 +{ + background-position: 0 -552px; +} + +span.spml6 +{ + background-position: 0 -576px; +} + +span.spml7 +{ + background-position: 0 -600px; +} + +a.mlstat:hover +{ + background-position: 0 0; +} + +span.spml8, a.mlstat:hover span.nostar, a.mlstat:hover span.prihi, a.mlstat:hover span.prihier +{ + background-position: 0 -624px; +} + +span.spml9, span.star +{ + background-position: 0 -648px; +} + +span.spml10, a.mlstat span.prihi +{ + background-position: 0 -672px; +} + +span.spml11, a.mlstat span.prihier +{ + background-position: 0 -696px; +} + +span.spml12 +{ + background-position: 0 -720px; +} + +span.spml13 +{ + background-position: 0 -744px; +} + +/* message view icons */ +span.spmv +{ + display: block; + width: 15px; + height: 15px; +} +span.spmv1 +{ + float: left; + background-position: 0 -984px; +} +span.spmv2 +{ + float: left; + margin: 0 5px 0 5px; + background-position: 0 -576px; +} +span.spmv3 +{ + margin-left: 3px; + display: inline-block; + background-position: 0 -1704px; +} + +/* folderlist icons */ +span.spfl +{ + display:block; + height: 18px; + width: 18px; + margin-left: 4px; +} +span.spfl1 +{ + background-position: 0 -1608px; +} + +ul.priority li +{ + width: 10em; +} + +/*** Folder/Contacts List Context Banner ***/ +span.spfcl +{ + display: block; + width: 20px; + height: 20px; + float: left; + margin-right: 8px; + margin-top: 1px; + cursor: pointer; +} + +span.spfcl1 +{ + background-position: 0 -1176px; +} + +span.spfcl2 +{ + background-position: 0 -1200px; +} + +span.spfcl3 +{ + background-position: 0 -1728px; +} + +ul.sortList li +{ + width: 13em; +} + +div.getAuth div +{ + padding: 6px 30px 26px 30px; +} + +div.getAuth span +{ + width:40%; + display: block; + float: left; + clear: left; + padding-right: 10px; + text-align: right; +} + +div.getAuth hr +{ + color: #ffffff; + background-color: #ffffff; + border: 0 none; +} + +div.getAuth input +{ + width:50%; + display: block; + clear: right; + width: 12em; + text-align: left; +} + +/*** Message Drag Proxy ***/ +#msgDragProxy +{ + position: absolute; + visibility: hidden; + font-size: .7em; + top: -100px; + cursor: move; + filter:alpha(opacity=80); + -moz-opacity: 0.8; + opacity: 0.8; +} +#msgDragProxy div +{ + padding: 0 6px; + background-color: #d8d8d8; + white-space: nowrap; +} +.b1, .b2, .b3, .b4 +{ + background-color: #d8d8d8; + font-size: 1px; + display:block; + overflow:hidden; +} +.b1 +{ + height: 1px; + margin: 0 5px; +} +.b2 +{ + height: 1px; + margin: 0 3px; +} +.b3 +{ + height: 1px; + margin: 0 2px; +} +.b4 +{ + height: 2px; + margin: 0 1px; +} + +/*** Take Dialog ***/ +div.takeInstructions +{ + padding: 15px 5px 20px 5px; + text-align: center; +} + +div.takeList +{ + font-size: .8em; + height: 14.5em; + border: 1px solid #aaaaaa; + overflow: auto; +} + + +/*** PRINTER FORMATTING ***/ +.printInfo +{ + display: none; +} + +.fullHdrBtn +{ + vertical-align: top; + padding-right: 10px; + float: right; +} + +@media print +{ + #leftColumn, + #toolBar, + .hdrContent, + #hdrLogo, + #ftrContent, + .toolbarTbl, + .fullHdrBtn, + .addContact, + .spc, + div.bannerPrivacy + { + display: none; + } + div.printInfo + { + background-color: grey; + border-bottom: 2px groove black; + display: block; + } + div#alpineContent + { + height: 100% !important; + overflow: visible; + } + table.msgHead + { + background-color: #f9f9f9; + border: 1px solid #aaaaaa; + width: 100%; + } +} diff --git a/web/cgi/alpine/2.0/css/help.css b/web/cgi/alpine/2.0/css/help.css new file mode 100644 index 00000000..240e5d44 --- /dev/null +++ b/web/cgi/alpine/2.0/css/help.css @@ -0,0 +1,119 @@ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +* { + font-family: Tahoma, Helvetica, sans-serif; + font-size: 1em; + text-align: justify; +} +tt { + font-family: Courier, "Courier New"; +} +body { + background: #fff; + font-size: 0.7em; + margin: 0.9em; +} +#header { + height: 4.0em; + position: relative; +} +#header .logo { + background: url(../img/cbn/logo.gif) left center no-repeat; + height: 4.0em; + width: 230px; +} +#header .nav { + position: absolute; + right: .815em; + top: 4.537em; +} +#header .nav a { + color: #00f; + font-weight: bold; + text-decoration: none; +} +#header .nav a:hover { + color: #00f; + text-decoration: underline; +} +h2 { + background: #ccc; + border-color: #ddd #999 #999 #ddd; + border-style: solid; + border-width: 1px; + margin: 0 0 .9em 0; + padding: .181em .725em; +} +dl { + margin: 0; + padding: 0; +} +dt { + font-weight: bold; + margin: 0 0 0.3em 0; +} +dd { + border-bottom: dotted 1px #ccc; + margin: 0 0 .9em 0; + padding-bottom: .9em; +} +ul, ol { + margin: 0; + padding: 0; +} +ul.wide li, ol.wide li { + margin-top: 1em; +} +ul { + list-style: square; +} +ul li { + margin-left: 1.5em; +} +ol { + list-style: decimal; +} +ol li { + margin-left: 2.5em; +} +a { + color: #00f; + text-decoration: none; +} +a:hover { + color: #00f; + text-decoration: underline; +} +div.also, div.note { + border-style: solid; + border-width: 1px; + padding: .7em; +} +div.also { + background: #ddd; + border-color: #eee #aaa #aaa #eee; +} +div.note { + background: #ffa; + border-color: #eef #aaf #aaf #eef; +} +div.note h4, div.also h4 { + float: left; + margin: 0; +} +div.note div { + margin-left: 3em; +} +div.also ul { + margin-left: 5em; +} diff --git a/web/cgi/alpine/2.0/css/help_popup.css b/web/cgi/alpine/2.0/css/help_popup.css new file mode 100644 index 00000000..11be8213 --- /dev/null +++ b/web/cgi/alpine/2.0/css/help_popup.css @@ -0,0 +1,114 @@ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +* { + font-family: Tahoma, Helvetica, sans-serif; + font-size: 1em; + text-align: justify; +} +tt { + font-family: Courier, "Courier New"; +} +body { + background: #fff; + font-size: 0.7em; + margin: 0.9em; +} +#header { + height: 0em; + position: relative; +} +#header .nav { + position: absolute; + right: .815em; + top: 0.3em; +} +#header .nav a { + color: #00f; + font-weight: bold; + text-decoration: none; +} +#header .nav a:hover { + color: #00f; + text-decoration: underline; +} +h2 { + background: #ccc; + border-color: #ddd #999 #999 #ddd; + border-style: solid; + border-width: 1px; + margin: 0 0 .9em 0; + padding: .181em .725em; +} +dl { + margin: 0; + padding: 0; +} +dt { + font-weight: bold; + margin: 0 0 0.3em 0; +} +dd { + border-bottom: dotted 1px #ccc; + margin: 0 0 .9em 0; + padding-bottom: .9em; +} +ul, ol { + margin: 0; + padding: 0; +} +ul.wide li, ol.wide li { + margin-top: 1em; +} +ul { + list-style: square; +} +ul li { + margin-left: 1.5em; +} +ol { + list-style: decimal; +} +ol li { + margin-left: 2.5em; +} +a { + color: #00f; + text-decoration: none; +} +a:hover { + color: #00f; + text-decoration: underline; +} +div.also, div.note { + border-style: solid; + border-width: 1px; + padding: .7em; +} +div.also { + background: #ddd; + border-color: #eee #aaa #aaa #eee; +} +div.note { + background: #ffa; + border-color: #eef #aaf #aaf #eef; +} +div.note h4, div.also h4 { + float: left; + margin: 0; +} +div.note div { + margin-left: 3em; +} +div.also ul { + margin-left: 5em; +} diff --git a/web/cgi/alpine/2.0/css/menu.css b/web/cgi/alpine/2.0/css/menu.css new file mode 100644 index 00000000..ecf01ee6 --- /dev/null +++ b/web/cgi/alpine/2.0/css/menu.css @@ -0,0 +1,71 @@ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +.menu a, .menu a:link, .menu a:visited { + white-space: nowrap; + color: #ffffff; + display: block; + margin: 0; + padding: 0 8px; + line-height: 34px; + text-decoration: none; +} + +.menu a img +{ + border: none; + margin: 10px 0; +} + +.menu a span +{ + margin-top: 10px; +} + +.menu a:focus, .menu a:hover, .menu a:active { + background-color: #555555; + color: #ffffff; +} + +.menu li { + list-style: none; +} + +.menu li hr { + margin: 2px 0; +} + +.menu li:focus ul, .menu li:hover ul, .menu li:active ul, .menu li.sfhover ul { + left: auto; + top: auto; + z-index: 99; +} + +.menu ul { + background-color: #333333; + left: -999px; + top: -999px; + margin-left: -1px; + position: absolute; +} + +.menu ul li { + border: 0 none; + clear: left; + margin-right: 0; +} + +.menu, .menu ul { + color: #ffffff; + margin: 0; + padding: 0; +} diff --git a/web/cgi/alpine/2.0/css/print.css b/web/cgi/alpine/2.0/css/print.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/web/cgi/alpine/2.0/css/print.css diff --git a/web/cgi/alpine/2.0/detach b/web/cgi/alpine/2.0/detach new file mode 100755 index 00000000..780560cd --- /dev/null +++ b/web/cgi/alpine/2.0/detach @@ -0,0 +1,172 @@ +#!./tclsh +# $Id: detach 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006-2007 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# detach +# +# Purpose: CGI script to retrieve requested attachment +# +# Input: PATH_INFO: /<col_number>/<folder_name>/<uid_of__msg>/<part_of_msg> +# along with possible search parameters: +set detach_vars { + {download "" 0} +} + +#set detach_via_ip_address 1 +#set detach_via_local_hostname 1 + +# inherit global config +source ./alpine.tcl + +proc WPServerIP {} { + global _wp + + catch { + set ip 127.0.0.1 + set sid [socket -async [info hostname] [expr {([string length $_wp(serverport)]) ? $_wp(serverport) : 80}]] + set ip [lindex [ fconfigure $sid -sockname ] 0] + close $sid + } + + return $ip +} + +WPEval $detach_vars { + # grok PATH_INFO for collection 'c' and folder 'f' uid 'u' and part 'p' + if {!([info exists env(PATH_INFO)] && [string length $env(PATH_INFO)] + && [regexp {^/([0-9]+)/(.*)/([0-9]+)/([\.0-9]+)$} $env(PATH_INFO) dummy c f u p])} { + WPCmd PEInfo statmsg "Invalid Detach: $env(SCRIPT_NAME)" + cgi_exit + } + + # generate big random string to reference the thing + + # generate filenames to hold detached data and control file + for {set n 0} {1} {incr n} { + + set rhandle [WPCmd PESession random 64] + set cfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-control] + set dfile [file join $_wp(fileroot) $_wp(detachpath) detach.${rhandle}-data] + + if {[file exists $cfile] == 0 && [file exists $dfile] == 0} { + if {[catch {open $cfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} cfd]} { + error [list _action Detach "Cannot create control file: [cgi_quote_html $cfd]" "Please close this window"] + } else { + exec echo ${rhandle}-control | [file join $_wp(cgipath) $_wp(appdir) whackatch.tcl] >& /dev/null & + } + + if {[catch {open $dfile {RDWR CREAT EXCL} [cgi_tmpfile_permissions]} dfd]} { + catch {close $cfd} + error [list _action Detach "Cannot create command file: [cgi_quote_html $dfd]" "Please close this window"] + } else { + exec echo ${rhandle}-data | [file join $_wp(cgipath) $_wp(appdir) whackatch.tcl] >& /dev/null & + } + + # exec chmod [cgi_tmpfile_permissions] $cfile + # exec chmod [cgi_tmpfile_permissions] $dfile + break + } elseif {$n > 4} { + error [list _action Detach "Command file creation limit" "Please close this window"] + } + } + + if {[catch {WPCmd PEMessage $u detach $p $dfile} attachdata]} { + error [list _action Detach $attachdata "Please close this window"] + } + + if {[info exists detach_via_ip_address]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[WPServerIP]\]\\2" redirect] != 1} { + error [list _action Detach "Cannot determine server address" "Please close this window"] + } + } elseif {[info exists detach_via_local_hostname]} { + if {[regsub {^(http[s]?://)[A-Za-z0-9\\-\\.]+(.*)$} "[cgi_root]/pub/getach.tcl" "\\1\[[info hostname]\]\\2" redirect] != 1} { + error [list _action Detach "Cannot determine server address" "Please close this window"] + } + } else { + set redirect "[cgi_root]/pub/getach.tcl" + } + + set mimetype [lindex $attachdata 0] + set mimesubtype [lindex $attachdata 1] + set contentlength [lindex $attachdata 2] + set givenname [lindex [lindex $attachdata 3] 0] + set tmpfile [lindex $attachdata 4] + + if {[string compare $tmpfile $dfile]} { + set straytmp "&straytmp=1" + } else { + set straytmp "" + } + + if {![string length $givenname]} { + set givenname "attachment" + switch -regexp $mimetype { + ^[Tt][Ee][Xx][Tt]$ { + switch -regexp $mimesubtype { + ^[Pp][Ll][Aa][Ii][Nn]$ { + set givenname "attached.txt" + } + ^[Hh][Tt][Mm][Ll]$ { + set givenname "attached.html" + } + } + } + } + } + + set safegivenname $givenname + regsub -all {[/]} $safegivenname {-} safegivenname + regsub -all {[ ]} $safegivenname {_} safegivenname + regsub -all {[\?]} $safegivenname {X} safegivenname + regsub -all {[&]} $safegivenname {X} safegivenname + regsub -all {[#]} $safegivenname {X} safegivenname + regsub -all {[=]} $safegivenname {X} safegivenname + set safegivenname "/[WPPercentQuote $safegivenname {.}]" + + if {$download == 1} { + puts $cfd "Content-type: Application/X-Download" + puts $cfd "Content-Disposition: attachment; filename=\"$givenname\"" + } else { + puts $cfd "Content-type: ${mimetype}/${mimesubtype}" + } + + # side-step the cgi_xxx stuff in this special case because + # we don't want to buffer up the downloading attachment... + + puts $cfd "Content-Length: $contentlength" + puts $cfd "Expires: [clock format [expr {[clock seconds] + 3600}] -f {%a, %d %b %Y %H:%M:%S GMT} -gmt true]" + puts $cfd "Cache-Control: max-age=3600" + puts $cfd "" + + puts $cfd $tmpfile + + # exec chmod [cgi_tmpfile_permissions] $tmpfile + + close $cfd + + # prepare to clean up if the brower never redirects + + cgi_http_head { + # redirect to the place we stuffed the detach info. use the ip address + # to foil spilling any session cookies or the like + #cgi_redirect ${redirect}${safegivenname}?h=${rhandle} + + if {[info exists env(SERVER_PROTOCOL)] && [regexp {[Hh][Tt][Tt][PP]/([0-9]+)\.([0-9]+)} $env(SERVER_PROTOCOL) m vmaj vmin] && $vmaj >= 1 && $vmin >= 1} { + cgi_puts "Status: 303 Temporary Redirect" + } else { + cgi_puts "Status: 302 Redirected" + } + + cgi_puts "URI: ${redirect}${safegivenname}?h=${rhandle}${straytmp}" + cgi_puts "Location: ${redirect}${safegivenname}?h=${rhandle}${straytmp}" + } +} diff --git a/web/cgi/alpine/2.0/foldercache.tcl b/web/cgi/alpine/2.0/foldercache.tcl new file mode 100644 index 00000000..a491d5d5 --- /dev/null +++ b/web/cgi/alpine/2.0/foldercache.tcl @@ -0,0 +1,177 @@ +# Web Alpine folder cache routines +# $Id$ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + + + +proc saveDefault {{uid 0}} { + # "size" rather than "number" to work around temporary alpined bug + if {$uid == 0 + || [catch {WPCmd PEMessage $uid size} n] + || $n == 0 + || [catch {WPCmd PEMessage $uid savedefault} savedefault]} { + if {[WPCmd PEFolder isincoming 0]} { + set colid 1 + } else { + set colid 0 + } + + return [list $colid [lindex [WPCmd PEConfig varget default-saved-msg-folder] 0]] + } + + return $savedefault +} + +# add given folder name to the cache of saved-to folders +proc addSaveCache {f_name} { + global _wp + + if {[catch {WPSessionState save_cache} flist] == 0} { + if {[set i [lsearch -exact $flist $f_name]] < 0} { + set flist [lrange $flist 0 [expr {$_wp(save_cache_max) - 2}]] + } else { + set flist [lreplace $flist $i $i] + } + + set flist [linsert $flist 0 $f_name] + } else { + set flist [list $f_name] + } + + catch {WPSessionState save_cache $flist} +} + +# return the list of cached saved-to folders and make sure given +# default is somewhere in the list +proc getSaveCache {{def_name ""}} { + + if {![string length $def_name]} { + set savedef [saveDefault 0] + set def_name [lindex $savedef 1] + } + + set seen "" + + if {[catch {WPSessionState save_cache} flist] == 0} { + foreach f $flist { + if {[string compare $def_name $f] == 0} { + set def_listed 1 + } + + if {[string length $f] && [lsearch -exact $seen $f] < 0} { + lappend options $f + lappend options $f + lappend seen $f + } + } + } + + if {!([info exists options] && [info exists def_listed])} { + lappend options $def_name + lappend options $def_name + } + + if {[catch {WPCmd set wp_cache_folder} wp_cache_folder] + || [string compare $wp_cache_folder [WPCmd PEMailbox mailboxname]]} { + # move default to top on new folder + switch -- [set x [lsearch -exact $options $def_name]] { + 0 { } + default { + if {$x > 0} { + set options [lreplace $options $x [expr {$x + 1}]] + } + + set options [linsert $options 0 $def_name] + set options [linsert $options 0 $def_name] + } + } + + catch {WPCmd set wp_cache_folder [WPCmd PEMailbox mailboxname]} + } + + return $options +} + +# add given folder name to the visited folder cache +proc addFolderCache {f_col f_name} { + global _wp + + if {$f_col != 0 || [string compare [string tolower $f_name] inbox]} { + if {0 == [catch {WPSessionState folder_cache} flist]} { + + if {[catch {WPSessionState left_column_folders} fln]} { + set fln $_wp(fldr_cache_def) + } + + for {set i 0} {$i < [llength $flist]} {incr i} { + set f [lindex $flist $i] + if {$f_col == [lindex $f 0] && 0 == [string compare [lindex $f 1] $f_name]} { + break + } + } + + if {$i >= [llength $flist]} { + set flist [lrange $flist 0 $fln] + } else { + set flist [lreplace $flist $i $i] + } + + set flist [linsert $flist 0 [list $f_col $f_name]] + # let users of data know it's changed (cheaper than hash) + WPScriptVersion common 1 + } else { + catch {unset flist} + lappend flist [list $f_col $f_name] [list [saveDefault 0]] + # ditto + WPScriptVersion common 1 + } + + catch {WPSessionState folder_cache $flist} + } +} + +proc removeFolderCache {f_col f_name} { + global _wp + + if {$f_col != 0 || [string compare [string tolower $f_name] inbox]} { + if {0 == [catch {WPSessionState folder_cache} flist]} { + + if {[catch {WPSessionState left_column_folders} fln]} { + set fln $_wp(fldr_cache_def) + } + + for {set i 0} {$i < [llength $flist]} {incr i} { + set f [lindex $flist $i] + if {$f_col == [lindex $f 0] && 0 == [string compare [lindex $f 1] $f_name]} { + set flist [lreplace $flist $i $i] + WPScriptVersion common 1 + catch {WPSessionState folder_cache $flist} + return + } + } + } + } +} + +# return the list of cached visited folders and make sure given +# default is somewhere in the list +proc getFolderCache {} { + if {[catch {WPSessionState folder_cache} flist]} { + catch {unset flist} + lappend flist [saveDefault 0] + catch {WPSessionState folder_cache $flist} + } + + return $flist +} + diff --git a/web/cgi/alpine/2.0/folders b/web/cgi/alpine/2.0/folders new file mode 100755 index 00000000..e98197ff --- /dev/null +++ b/web/cgi/alpine/2.0/folders @@ -0,0 +1,240 @@ +#!./tclsh +# $Id: folders 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# view.tcl +# +# Purpose: CGI script folders for Web Alpine 2.0 pages +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_viewed_msg> +# along with possible search parameters: +set folders_args { +} + +# inherit global config +source ./alpine.tcl +source ./foldercache.tcl +source ./common.tcl + +# TEST +proc cgi_suffix {args} { + return "" +} + +# WHILE TESTING/DEBUGGING +proc noimp {s} { + return "onClick=return noImp('${s}');" +} + +set dmsgs "" +proc dm {s} { + global dmsgs + + lappend dmsgs $s +} + +# default location state +set c -1 +set f "" + +# grok PATH_INFO for collection 'c' and folder 'f' +if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + # look for collection number, c + if {[regexp {^/([0-9]+)(/.*)} $env(PATH_INFO) dummy c r]} { + if {![string length $r]} { + set f $c + set c -1 + } + } else { + set r $env(PATH_INFO) + } + + # look for folder name (f) in remainder, r + if {[regexp {^/([^/]+)((/.*)|$)} $r dummy f r]} { + # look for uid of page's top message, u + if {[regexp {^/([0-9a-fA-F]+)} $r dummy u]} { + } else { + } + } else { + if {[string length $r]} { + # can't grok, reset context + set c -1 + } + } +} + +WPEval $folders_args { + # verify current collection/folder + if {[catch {WPCmd PEFolder current} curfold]} { + error [list _action browse "cannot determine default folder: $curfold"] + } else { + set curc [lindex $curfold 0] + set curf [lindex $curfold 1] + } + + # "current" folder's context + if {$c < 0} { + set c $curc + } + + # "current" folder + if {0 == [string length $f]} { + set f $curf + } + + # open a different folder? + if {$c != $curc || [string compare $f $curf]} { + # BUG: validate $u? + + error [list _action browse "NOT PREPARED TO OPEN NEW FOLDER $f YET"] + if {[catch {eval WPCmd PEMailbox open [list $c $f]} reason]} { + } else { + # STATUS: Opened Folder $f + } + } + + set defc [WPCmd PEFolder defaultcollection] + set cols [WPCmd PEFolder collections] + + set charset "UTF-8" + set u 0 + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + cgi_html { + cgi_head { + cgi_content_type "text/html; charset=$charset" + cgi_title [wpPageTitle "Folder Management"] + cgi_base "href=$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + cgi_stylesheet css/menu.css + cgi_stylesheet css/cbn/screen.css + cgi_stylesheet css/cbn/folders.css + # Yahoo Styles + cgi_stylesheet $_wp(yui)/build/container/assets/container-core.css + cgi_stylesheet $_wp(yui)/build/menu/assets/skins/sam/menu.css + cgi_stylesheet $_wp(yui)/build/button/assets/skins/sam/button.css + # YahooUI libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/menu/menu-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + # local libraries + cgi_script language="JavaScript" src="lib/common.js" {} + cgi_script language="JavaScript" src="lib/folders.js" {} + cgi_javascript { + cgi_puts "YAHOO.alpine.cgi_root = '$_wp(serverpath)';" + cgi_puts "YAHOO.alpine.current.incoming = [WPCmd PEFolder isincoming $c];" + cgi_puts "YAHOO.alpine.current.c = $c;" + cgi_puts "YAHOO.alpine.current.f = \"$f\";" + foreach col $cols { + regsub {'} [lindex $col 1] {\'} colname + lappend colnames "'$colname'" + } + cgi_puts "YAHOO.alpine.current.u = $u;" + cgi_puts "YAHOO.alpine.current.collections = \[[join $colnames {,}]\];" + cgi_puts "function bodyOnLoad() {" + cgi_puts " initMenus();" + cgi_puts " if(YAHOO.env.ua.gecko > 0){ sizeVPHeight(); window.onresize = resizeVPHeight; }" + cgi_puts " setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + cgi_puts " drawFolderList('alpineContent',$defc);" + cgi_puts "}" + + # WHILE TESTING/DEBUGGING + cgi_puts "var impi = new Array(); function noImp(m){ var sm; if(impi\[m\]) {impi\[m\]++; if(impi\[m\] > 4) sm = '<b>Seriously,</b> ' + m + ' will <b>never</b> get implemented if you keep bothering me!'; else sm = m + ' is <b>still</b> not implemented!'; } else { sm = m + ' is not implemented yet!' ; impi\[m\] = 1 ;} showStatusMessage(sm,3); return false; }" + + cgi_puts "browserDetect();" + } + } + + cgi_body class=wap "onLoad=bodyOnLoad()" { + cgi_puts {<iframe name="formResponse" id="formResponse" src="img/cbn/spritelib.gif"></iframe>} + wpCommonPageLayout folders "$c" "$f" "$u" "View and Manage Folders" [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/browse/${c}/${f}"] "Folder List" 0 searchContent('folders','flistFolders')] "" { + # CONTEXT COMMANDS + cgi_division class=hdrBtns { + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi2" ""][cgi_span "class=hdrBtnText" Settings]" "settings"] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" "javascript:openHelpWindow('folders.html');" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"] + } + } { + # TO MENUBAR + cgi_anchor_name "toolbar" + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb18" "New Folder"] "#" title="Create new folder in this folder" "onClick=return addFolder();"] + } + cgi_table_data class="dv1" { + cgi_puts [cgi_img "img/cbn/div.gif" class=wap] + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb19" "View Messages"] "#" title="View Messages in selected folder" id=butChoose "onClick=return doOpen();"] + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb7" "Delete"] "#" title="Delete selected folder" "onClick=return queryDelete();"] + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb20" "Rename"] "#" title="Rename selected folder" "onClick=return renameFolder();"] + } + cgi_table_data class="dv1" { + cgi_puts [cgi_img "img/cbn/div.gif" class=wap] + } + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=\"menuHdr\">[cgi_url "More Actions [cgi_img "img/cbn/menu.gif" class="wap menuDn menuImg"]" "#" "onClick=this.blur(); return false;"]<div>" + cgi_bullet_list { + cgi_li [cgi_url "Import Email into Folder" "#" "onClick=return importFolder();"] + cgi_li [cgi_url "Export Email from Folder" "#" "onClick=return exportFolder();"] + } + cgi_puts "</div></li>" + } + } + cgi_table_data width="100%" { + cgi_puts [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } + } + cgi_puts "</tbody>" + } + } { + cgi_puts "Loading..." + } { + # BOTTOM MENUBAR + cgi_table class="wap toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody><tr><td> </td></tr></tbody>" + } + } + + cgi_text "pickFolderCollection=$defc" type=hidden id=pickFolderCollection notab + cgi_text "pickFolderPath=" type=hidden id=pickFolderPath notab + cgi_text "pickFolderName=" type=hidden id=pickFolderName notab + + # any debugging info to insert? + foreach dmsg $dmsgs { + cgi_html_comment "DEBUG: $dmsg" + cgi_puts "" + } + } + } +} diff --git a/web/cgi/alpine/2.0/forward b/web/cgi/alpine/2.0/forward new file mode 120000 index 00000000..872d4cb2 --- /dev/null +++ b/web/cgi/alpine/2.0/forward @@ -0,0 +1 @@ +compose
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/help/alpha-index.html b/web/cgi/alpine/2.0/help/alpha-index.html new file mode 100644 index 00000000..40380c77 --- /dev/null +++ b/web/cgi/alpine/2.0/help/alpha-index.html @@ -0,0 +1,225 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Alpine Help Index</title></head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="javascript:history.back()">Go Back</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+
+<div id="content">
+
+<h2>Alpine Help Index</h2>
+
+<div class="noprint"><a href="#A">A</a> <a href="#B">B</a> <a href="#C">C</a>
+<a href="#D">D</a> <a href="#E">E</a> <a href="#F">F</a> <a href="#G">G</a> <a href="#H">H</a> <a href="#I">I</a> <a href="#L">L</a> <a href="#M">M</a> <a href="#N">N</a> <a href="#O">O</a> <a href="#P">P</a> <a href="#Q">Q</a> <a href="#R">R</a> <a href="#S">S</a> <a href="#T">T</a> <a href="#U">U</a> <a href="#W">W</a> <a href="#X">X</a> <a href="#Y">Y</a> <a href="#Z">Z</a></div>
+
+<p><strong><a name="A" id="A"></a>A</strong></p>
+<p>address book, see <a href="contacts.html">Contacts</a></p>
+<p><a href="settings.html#msgview">addresses as links</a> (Settings)</p>
+<p><a href="settings.html#personal">Alternate Addresses</a> (Settings)</p>
+<p><a href="settings.html#msgview">Anti-phishing option</a> (Settings)</p>
+<p><a href="settings.html#fcc">archive sent mail</a> (Settings)</p>
+<p>attachments</p>
+<ul>
+ <li><a href="settings.html#reply">including in replies</a> (Settings)</li>
+ <li><a href="compose.html#attachments">including with messages</a></li>
+ <li><a href="read.html#attachments">viewing and downloading</a></li>
+</ul>
+
+<p><strong><a name="B" id="B"></a>B</strong></p>
+
+<p><strong><a name="C" id="C"></a>C</strong></p>
+<p><a href="settings.html#compose">compose encoding</a> (Settings)</p>
+
+<p><a href="compose.html">Compose</a> (sending mail)</p>
+<ul>
+ <li><a href="compose.html#attachments">attachments</a></li>
+ <li><a href="compose.html#autosave">automatic saves</a></li>
+ <li><a href="settings.html#compose">Compose Headers</a> (Settings)</li>
+ <li><a href="compose.html#headers">headers</a></li>
+ <li><a href="compose.html#resuming">resuming drafts</a></li>
+ <li><a href="compose.html#sending">saving drafts</a></li>
+ <li><a href="compose.html#sending">sending</a></li>
+ <li><a href="compose.html#writing">writing messages</a></li>
+</ul>
+
+<p><a href="contacts.html">Contacts</a> (address book)</p>
+<ul>
+ <li><a href="contacts.html#add">adding</a></li>
+ <li><a href="contacts.html#edit">editing</a></li>
+ <li><a href="contacts.html#group">group contacts</a></li>
+ <li><a href="contacts.html#remove">removing</a></li>
+</ul>
+
+<p><a href="settings.html#compose">Custom Headers</a> (Settings)</p>
+<p><a href="settings.html">customizing Alpine</a></p>
+
+<p><strong><a name="D" id="D"></a>D</strong></p>
+<p><a href="inbox.html#delete">deleting messages</a></p>
+<p><a href="settings.html#dirservers">Directory Server</a> (Settings)</p>
+<p><a href="settings.html#display">Display</a> (Settings)</p>
+<p><a href="settings.html#msgview">Display Deaders</a> (Settings)</p>
+<p><a href="settings.html#personal">Display Name</a> (Settings)</p>
+<p><a href="settings.html#foldernames">Draft Folder</a> (Settings)</p>
+<p><a href="inbox.html#drag">drag and drop shortcuts</a></p>
+
+<p><strong><a name="E" id="E"></a>E</strong></p>
+<p><a href="settings.html#personal">Email Signature</a> (Settings)</p>
+<p><a href="quick-start.html#trash">Emptying trash</a> (how to)</p>
+<p><a href="settings.html#foldernames">Emptying Trash</a> (Settings)</p>
+<p><a href="settings.html#compose">Encoding of outgoing messages</a> (Settings)</p>
+
+<p><strong><a name="F" id="F"></a>F</strong></p>
+<p><a href="settings.html#fcc">Fcc (sent mail folder)</a> (Settings)</p>
+<p><a href="settings.html#compose">Flowed Text Handling</a> (Settings)</p>
+
+<p><a href="folders.html">Folders</a></p>
+<ul>
+ <li><a href="folders.html#add">adding</a></li>
+ <li><a href="folders.html#delete">deleting</a></li>
+ <li><a href="folders.html#rename">renaming</a></li>
+ <li><a href="folders.html#route">routing mail to</a></li>
+ <li><a href="inbox.html#folder">saving messages to</a></li>
+ <li><a href="settings.html#folders">settings</a></li>
+ <li><a href="folders.html#view">viewing a list of</a></li>
+ <li><a href="folders.html#viewing">viewing messages in</a></li>
+</ul>
+
+<p><a href="read.html#forward">forwarding mail</a></p>
+<p><a href="settings.html#forward">forwarding options</a> (Settings)</p>
+
+<p><strong><a name="G" id="G"></a>G</strong></p>
+
+<p><strong><a name="H" id="H"></a>H</strong></p>
+<p><a href="compose.html#headers">headers</a> (for sending mail)</p>
+<p><a href="read.html#full">headers, full</a> (in received messages)</p>
+<p><a href="settings.html#reply">headers in replies</a> (Settings)</p>
+<p><a href="settings.html#newsweather">Headline News</a> (Settings)</p>
+
+<p><strong><a name="I" id="I"></a>I</strong></p>
+<p><a href="settings.html#mailservers">Inbox Server</a> (Settings)</p>
+<p><a href="inbox.html#icons">index icons</a></p>
+
+<p><strong><a name="J" id="J"></a>J</strong></p>
+
+<p><strong><a name="K" id="K"></a>K</strong></p>
+
+<p><strong><a name="L" id="L"></a>L</strong></p>
+<p><a href="settings.html#dirservers">LDAP Server</a> (Settings)</p>
+<p><a href="settings.html#display">lines per page in index</a> (Settings)</p>
+<p><a href="settings.html#msgview">links, display</a> (Settings)</p>
+
+<p><strong><a name="M" id="M"></a>M</strong></p>
+<p><a href="inbox.html#stars">marking messages with a star</a></p>
+<p><a href="settings.html#compose">Message Encoding</a> (Settings)</p>
+
+<p><strong><a name="N" id="N"></a>N</strong></p>
+<p><a href="quick-start.html#check">new mail check</a></p>
+<p><a href="settings.html#newsweather">news</a> (Settings)</p>
+
+<p><strong><a name="O" id="O"></a>O</strong></p>
+
+<p><strong><a name="P" id="P"></a>P</strong></p>
+<p><a href="settings.html#personal">personal name</a> (Settings)</p>
+<p>preferences, see <a href="settings.html">Settings</a></p>
+
+<p><strong><a name="Q" id="Q"></a>Q</strong></p>
+<p><a href="quick-start.html">Quick Start</a></p>
+
+<p><strong><a name="R" id="R"></a>R</strong></p>
+<p><a href="read.html">reading mail</a></p>
+<ul>
+ <li><a href="read.html#contacts">adding contacts</a></li>
+ <li><a href="read.html#delete">deleting</a></li>
+ <li><a href="read.html#header">displaying full headers</a></li>
+ <li><a href="read.html#forward">forwarding</a></li>
+ <li><a href="inbox.html#stars">marking with stars</a></li>
+ <li><a href="read.html#print">printing</a></li>
+ <li><a href="read.html#reply">replying</a></li>
+ <li><a href="inbox.html#spam">reporting a message as spam</a></li>
+ <li><a href="read.html#folder">saving to a folder</a></li>
+ <li><a href="inbox.html#sort">sorting</a></li>
+ <li><a href="read.html#view">viewing a message</a></li>
+ <li><a href="read.html#attachments">viewing and downloading attachments</a></li>
+</ul>
+
+<p><a href="settings.html#msglist">read messages, automove </a> (Settings)</p>
+<p><a href="settings.html#folders">recent folders displayed</a> (Settings)</p>
+<p><a href="read.html#reply">replying</a></p>
+<p><a href="settings.html#compose">Reply intro string</a> (Settings)</p>
+<p><a href="settings.html#reply">Reply Options</a> (Settings)</p>
+<p><a href="settings.html#compose">Reply prefix</a> (Settings)</p>
+<p><a href="settings.html#msgview">Rich Text Display</a> (Settings)</p>
+
+<p><strong><a name="S" id="S"></a>S</strong></p>
+<p><a href="inbox.html#folder">saving messages to a folder</a></p>
+<p><a href="settings.html#save">Save Sent</a> (Settings)</p>
+<p><a href="compose.html">sending mail</a></p>
+<p><a href="search.html">Search</a></p>
+<ul>
+ <li><a href="search.html#inbox">Basic Index Search</a></li>
+ <li><a href="search.html#advanced">Advanced Index Search</a></li>
+ <li><a href="search.html#example">Example</a></li>
+ <li><a href="search.html#other">searching Contacts and Folder List</a></li>
+</ul>
+
+<p><a href="settings.html">Settings</a></p>
+<ul>
+ <li><a href="settings.html#compose">Compose</a></li>
+ <li><a href="settings.html#dirservers">Directory Servers</a></li>
+ <li><a href="settings.html#folders">Folders</a></li>
+ <li><a href="settings.html#foldernames">Folder Names</a></li>
+ <li><a href="settings.html#forward">Forwarding options</a></li>
+ <li><a href="settings.html#mailservers">Mail Servers</a></li>
+ <li><a href="settings.html#display">Message Display</a></li>
+ <li><a href="settings.html#msglist">Message List</a></li>
+ <li><a href="settings.html#msgview">Message View</a></li>
+ <li><a href="settings.html#newsweather">News and Weather</a></li>
+ <li><a href="settings.html#personal">Personal preferences</a></li>
+ <li><a href="settings.html#reply">Reply Options</a></li>
+ <li><a href="settings.html#fcc">Sent Message Options</a></li>
+</ul>
+
+<p><a href="settings.html#fcc">Sent mail folder</a> (Settings)</p>
+<p><a href="settings.html#personal">signature content</a> (Settings)</p>
+<p><a href="settings.html#reply">signature options</a> (Settings)</p>
+<p><a href="settings.html#mailservers">SMTP Server</a> (Settings)</p>
+<p><a href="inbox.html#spam">spam</a> (reporting)</p>
+<p><a href="settings.html#msglist">Sort Order, default</a> (Settings)</p>
+<p><a href="inbox.html#sort">sorting message index</a></p>
+<p><a href="inbox.html#stars">star</a></p>
+<p><a href="settings.html#msglist">Start display at</a> (Settings)</p>
+
+<p><strong><a name="T" id="T"></a>T</strong></p>
+<p>trash</p>
+<ul>
+ <li><a href="quick-start.html#trash">emptying, deleting, and recovering</a> (how to)</li>
+ <li><a href="inbox.html#trash">Emptying</a></li>
+ <li><a href="settings.html#foldernames">Trash Folder</a> (Settings)</li>
+</ul>
+
+<p><strong><a name="U" id="U"></a>U</strong></p>
+<p><a href="settings.html#msgview">URLs as links</a> (Settings)</p>
+
+<p><strong><a name="V" id="V"></a>V</strong></p>
+<p><a href="inbox.html#view">viewing messages</a></p>
+
+<p><strong><a name="W" id="W"></a>W</strong></p>
+<p><a href="settings.html#newsweather">Weather Bar</a> (Settings)</p>
+<p><a href="settings.html#msgview">web hostnames as links</a> (Settings)</p>
+<p><a href="settings.html#display">Wrap Plain Text column</a> (Settings)</p>
+
+<p><strong><a name="X" id="X"></a>X</strong></p>
+
+<p><strong><a name="Y" id="Y"></a>Y</strong></p>
+
+<p><strong><a name="Z" id="Z"></a>Z</strong></p>
+
+<p> </p>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/compose.html b/web/cgi/alpine/2.0/help/compose.html new file mode 100644 index 00000000..6a2b7f78 --- /dev/null +++ b/web/cgi/alpine/2.0/help/compose.html @@ -0,0 +1,102 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Compose: sending mail</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+
+
+<h2>Compose: sending mail</h2>
+
+<ul>
+ <li><a href="#writing">Writing messages</a></li>
+ <li><a href="#attachments">Including attachments</a></li>
+ <li><a href="#sending">Sending, canceling, and saving drafts</a></li>
+ <li><a href="#resuming">Resuming drafts</a></li>
+ <li><a href="#headers">Headers</a></li>
+ <li><a href="#autosave">Automatic saves</a></li>
+</ul>
+
+<p>The <strong>Compose</strong> screen is where you write and send messages. The <strong>Compose</strong> screen is divided into two sections:</p>
+<ul>
+ <li>The <em>header</em> section is at the top. You use the header section to address the mail and control the text format.</li>
+ <li>The <em>message</em> section is below the header. The message section is where you enter and format the message text.</li>
+<br /><br /></ul>
+<h2><a name="writing" id="writing"></a>Writing messages</h2>
+
+<ol>
+ <li>On the menu bar, click <strong>Compose</strong> (or <strong>Reply</strong> or <strong>Forward</strong>).</li>
+ <li>In the header section, enter the addressing information. By default, the headers displayed are the <strong>To</strong>, <strong>Cc</strong>, and <strong>Subject</strong> fields. For information on displaying more header fields, see <a href="#headers">Headers</a>.</li>
+ <li>To enter rich-text click on <strong>Rich Text</strong> to the right of the Subject header. Click <strong>Plain Text</strong> to toggle this back to plain text.</li>
+ <li>In the message section, enter your message text. If you are entering Rich Text, a <em>formatting toolbar</em> at the top of the message section allows you to apply rich-text formatting to message text. You can also insert links and graphics using the formatting toolbar.</li>
+ <li>If desired, you can mark your message with a priority level. On the menu bar, point to <strong>Priority</strong>, and then select the level that you want for this message.</li>
+<br /><br /></ol>
+<h2><a name="attachments" id="attachments"></a>Including attachments</h2>
+<ol>
+ <li>On the menu bar, click <strong>Attach File</strong>.</li>
+ <li>Enter the path and file name for the file that you want to attach, or click <strong>Browse</strong> to browse for the file and select it.</li>
+<br /><br /></ol>
+<h2><a name="sending" id="sending"></a>Sending, canceling, and saving drafts</h2>
+
+<p><strong>To send mail</strong></p>
+<ul>
+ <li>On the menu bar, click <strong>Send</strong>.</li>
+</ul>
+
+<p><strong>To cancel an editing session</strong></p>
+<ol>
+ <li>On the menu bar, click <strong>Cancel</strong>, or click any item in the left pane, such as your <strong>Inbox</strong>.</li>
+ <li>Click <strong>Discard</strong> to confirm. The <strong>Compose</strong> screen closes and your <strong>Inbox</strong> appears.</li>
+</ol>
+<p><strong>To save a draft of a message</strong></p>
+<ul>
+ <li>On the menu bar, click <strong>Save Draft</strong>. A copy of the message is saved to the Drafts folder. The <strong>Compose</strong> screen closes and you are returned to the screen that was displayed before the editing session began.</li><br /><br />
+</ul>
+<div class="note">
+<h4>Note:</h4>
+<div> If you open a previously saved draft, make more changes, and then cancel the editing session and discard changes, the entire draft is deleted, not just the most recent changes. </div>
+</div>
+
+<br /><br />
+<h2><a name="resuming" id="resuming"></a>Resuming drafts</h2>
+<p>To resume editing a draft message that you previously saved go to the <strong>Drafts</strong> folder by clicking on <strong>Drafts</strong> in the left pane. Find the message you want to resume in the list and click on its Subject to resume composing.
+<h2><a name="headers" id="headers"></a>Headers</h2>
+<p> The header section is where you enter addressing information. By default, the header displays the <strong>To</strong>, <strong>Cc</strong>, and <strong>Subject</strong> fields. </p>
+<p><strong>To display all headers</strong></p>
+<ul>
+ <li>To the right of the <strong>To</strong> field, click <strong>More Headers</strong>.</li>
+</ul>
+<p><strong>To display only the default headers</strong></p>
+<ul>
+ <li>To the right of the <strong>To</strong> field, click <strong>Fewer Headers</strong>.</li>
+</ul>
+<h3>Header fields</h3>
+<p>The following header fields are available:</p>
+<ul>
+ <li><strong>To.</strong> Use this field to specify email recipients:
+ <ul>
+ <li> Type the full email address of the recipient. Separate multiple addresses with commas.</li>
+ <li> Type a name or nickname specified in your contact list and click. Alpine expands the name or nickname to the full address. Separate multiple addresses with commas.</li>
+ <li>Click <strong>To</strong> to display to your contact list and select an address or to select an address from the directory server.</li>
+ </ul>
+ </li>
+ <li><strong>Attachments.</strong> Lists any files that have been attached to the message.</li>
+ <li> <strong>Subject.</strong> Enter a brief phrase describing the topic of the message. </li>
+ <li><strong>Cc</strong> (Carbon copy). Similar to the <strong>To</strong> field. Enter one or more addresses to receive a copy of the message. These addresses are seen by all message recipients.</li>
+ <li> <strong>Bcc</strong> (Blind carbon copy). Similar to the <strong>To</strong> and <strong>Cc</strong> fields. Enter one or more addresses to receive a copy of the message. The Bcc header does not show up in the sent mail so these addresses are hidden from other recipients.</li>
+ <li><strong>Fcc</strong> (File carbon copy). Specifies a folder to which a copy of your outgoing message is saved. You can control whether messages are saved with or without attachments. For more information, see <a href="settings.html#fcc">Settings</a>.</li>
+<br /><br /></ul>
+
+<h2><a name="autosave" id="autosave"></a>Automatic saves</h2>
+<p>Alpine saves a draft every 5 minutes, overwriting the draft each time, so that only the most recent saved version is preserved. </p>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/contacts.html b/web/cgi/alpine/2.0/help/contacts.html new file mode 100644 index 00000000..690dd76c --- /dev/null +++ b/web/cgi/alpine/2.0/help/contacts.html @@ -0,0 +1,80 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Contacts: your address book</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+<h1>Contacts: your address book</h1>
+
+<ul>
+ <li><a href="#add">Adding a contact</a></li>
+ <li><a href="#remove">Removing a contact</a></li>
+ <li><a href="#edit">Editing a contact</a></li>
+ <li><a href="#group">Creating a group contact</a></li>
+<br /><br /></ul>
+
+<p>Contacts allow you to store names, email addresses, and other information in a contact list, which serves as an address book. You can quickly send mail to a contact by retreiving information from your contact list.</p>
+
+<h2><a name="add" id="add"></a>Adding a contact</h2>
+
+<p><strong>To add a contact</strong></p>
+<ol>
+ <li>In the left pane, click <strong>Contacts</strong>. Your contact list appears in the right pane.</li>
+ <li>On the menu bar, click <strong>New Contact</strong>.</li>
+ <li>Fill in the contact information:</li>
+ <ul>
+ <li><strong>Nickname.</strong> A short name that you can use for quick addressing. If you type the nickname instead of the full display name or email address, Alpine will offer a list of matching choices from your contacts list and the University of Washington directory. You can select the contact from the list.</li>
+ <li><strong>Display Name.</strong> The name that appears in the message header.</li>
+ <li><strong>Email.</strong> The contact's email address.</li>
+ <li><strong>Notes.</strong> Any text you want. Used only by you.</li>
+ <li><strong>Fcc Folder.</strong> A folder that will receive copies of all messages that you send directly to this contact.</li>
+ </ul>
+ <li>Click <strong>Add</strong>.</li>
+<br /><br /></ol>
+<p><strong>To add a contact from a message</strong></p>
+<ul>
+<li>Drag the contact's email address from the<strong> From</strong> field to the <strong>Contacts</strong> folder.
+<p><em>or</em></p></li>
+<li>To the right of the <strong>From</strong> field, click <strong>Add</strong>.</li>
+<br /><br /></ul>
+<p><strong>To add multiple contacts from a message</strong></p>
+<ul>
+ <li>On the menu bar, click <strong>More Actions</strong>, and then select <strong>Extract</strong>. Alpine extracts everything in the message that is in the format of an email address and presents a list of contacts. You can confirm each contact.</li>
+<br /><br /></ul>
+<h2><a name="remove" id="remove"></a>Removing a contact</h2>
+<ol>
+ <li>In the left pane, click <strong>Contacts</strong>. Your contact list appears in the right pane.</li>
+ <li>Select the contacts you wish to remove by checking the boxes to the left of the Display Names.</li>
+ <li>On the menu bar, click <strong>Delete</strong>.</li>
+ <li>Confirm that you want to <strong>Delete</strong> the contacts <strong>Forever</strong>.</li>
+<br /><br /></ol>
+
+<h2><a name="edit" id="edit"></a>Editing a contact</h2>
+
+<p><strong>To edit a contact</strong></p>
+<ol>
+ <li>In the left pane, click <strong>Contacts</strong>. Your contact list appears in the right pane.</li>
+ <li>Click on the <strong>Display Name</strong> to edit the corresponding entry.</li>
+<br /><br /></ol>
+
+<h2><a name="group" id="group"></a>Creating a group contact</h2>
+<p>A group contact is simply a contact with more than one email address.</p>
+<p><strong>To add a group contact</strong></p>
+<ol>
+ <li>In the left pane, click <strong>Contacts</strong>. Your contact list appears in the right pane.</li>
+ <li>On the menu bar, click <strong>New Group</strong>.</li>
+ <li>Fill in the contact information like you would for a regular contact, except</li>
+ <li><strong>Group Email.</strong> Enter all of the addresses or nicknames separated by commas.</li>
+ <li>Click <strong>Add</strong>.</li>
+<br /><br /></ol>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/folders.html b/web/cgi/alpine/2.0/help/folders.html new file mode 100644 index 00000000..dc05df0b --- /dev/null +++ b/web/cgi/alpine/2.0/help/folders.html @@ -0,0 +1,96 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Folders: organizing your mail</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+<h2>Folders: organizing your mail</h2>
+
+<ul>
+ <li><a href="#view">Viewing your list of folders</a></li>
+ <li><a href="#viewing">Viewing the messages in a folder</a></li>
+ <li><a href="#add">Adding folders</a></li>
+ <li><a href="#delete">Deleting folders</a></li>
+ <li><a href="#rename">Renaming folders</a></li>
+ <li><a href="#route">Routing mail to folders</a></li>
+</ul>
+
+<p>You can organize your mail into folders. Folders are displayed in the left pane. Some folders are provided by default:</p>
+<ul>
+ <li><strong>Inbox.</strong> Stores and displays your mail messages when they arrive, unless you have routed messages to another folder. You can drag and drop messages from the Inbox to other folders.</li>
+ <li><strong>Drafts.</strong> Stores any messages that have been saved during an editing session.</li>
+ <li><strong>Sent.</strong> By default, stores copies of all of your sent mail.</li>
+ <li><strong>Junk.</strong> Stores messages that have been caught by spam filtering and messages that you add by clicking <strong>Report Spam</strong> on the menu bar. On a weekly basis, Alpine deletes everything in the Junk folder that is dated before the previous week.</li>
+ <li><strong>Trash.</strong> Stores deleted messages, where thay can be recovered until they are permanently removed. For more information, see <a href="quick-start.html#trash">Trash</a>.</li>
+ <li><strong>Recent Folders.</strong> This is a listing of the folders that you have opened recently. You can set the number of recent folders displayed in the left pane. For more information, see <a href="settings.html#folders">Settings</a>.<br />
+ </li><br />
+ </ul>
+<div class="note">
+<h4>Note:</h4>
+<div> When viewed in the folder list displayed by clicking <strong>View/Manage Folders</strong>, the default folders named Junk and Sent in the left pane appear under the names sent-mail and junk-mail.</div>
+</div>
+
+<br />
+
+<h2><a name="view" id="view"></a>Viewing your list of folders</h2>
+<ul>
+ <li>In the left pane, click <strong>View/Manage Folders</strong>. A list of your folders appears in the right pane.</li><br /><br />
+</ul>
+<h2><a name="viewing" id="viewing"></a>Viewing the messages in a folder</h2>
+<p><strong>To view the messages contained in a folder</strong></p>
+<ol>
+ <li>In the left pane, click <strong>View/Manage Folders</strong>. A list of your folders appears in the right pane.</li>
+ <li>Select the folder that you want to view by clicking its name. On the menu bar, click <strong>View Messages</strong>.</li>
+ <li>Alternatively, double click the folder name.</li>
+<br /><br /></ol>
+<h2><a name="add" id="add"></a>Adding folders</h2>
+<ol>
+ <li>In the left pane, click <strong>View/Manage Folders</strong>. A list of your folders appears in the right pane.</li>
+ <li>On the menu bar, click <strong>New Folder</strong>.</li>
+ <li>Enter a name for the new folder and click <strong>New Folder</strong>. If you want this new folder to be a subfolder within an existing folder, enter the name of the parent folder, followed by a slash ( / ), followed by the new folder name. For example, <strong>subdir/foldername</strong>.</li>
+ <li>The new folder appears in the list.</li>
+<br /><br /></ol>
+<h2><a name="delete" id="delete"></a>Deleting folders</h2>
+<div class="note">
+<h4>Note:</h4>
+<div>Unlike deleted <strong>messages</strong>, deleted <strong>folders</strong> are not moved to the Trash, and they cannot be retrieved.</div>
+</div>
+<p><strong>To delete a folder</strong></p>
+<ol>
+ <li>In the left pane, click <strong>View/Manage Folders</strong>. A list of your folders appears in the right pane.</li>
+ <li>Click the folder that you want to delete. On the menu bar, click <strong>Delete</strong>.</li>
+ <li>Click <strong>Delete Forever</strong> to confirm.</li>
+<br /><br /></ol>
+<h2><a name="rename" id="rename"></a>Renaming folders</h2>
+
+<ol>
+ <li>In the left pane, click <strong>View/Manage Folders</strong>. A list of your folders appears in the right pane.</li>
+ <li>Click the folder that you want to rename. On the menu bar, click <strong>Rename</strong>.</li>
+ <li>Enter the new name.</li>
+ <li>Click <strong>Rename Folder</strong> to confirm.</li>
+<br /><br /></ol>
+
+<h2><a name="route" id="route"></a>Routing mail to folders</h2>
+
+<p>You can set up Alpine to route incoming and outgoing messages to designated folders.</p>
+<p><strong>To route a copy of an outgoing message to a folder</strong></p>
+<ul>
+ <li>Enter the folder name in the <strong>Fcc</strong> field in the composer.</li>
+</ul>
+
+<p><strong>To route incoming messages to a folder</strong></p>
+<ul>
+ <li>See <a href="settings.html">Settings</a>. </li>
+<br /><br /></ul>
+
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/graphics/attach_sm.gif b/web/cgi/alpine/2.0/help/graphics/attach_sm.gif Binary files differnew file mode 100644 index 00000000..cdf108cc --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/attach_sm.gif diff --git a/web/cgi/alpine/2.0/help/graphics/compose.gif b/web/cgi/alpine/2.0/help/graphics/compose.gif Binary files differnew file mode 100644 index 00000000..608eb4fb --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/compose.gif diff --git a/web/cgi/alpine/2.0/help/graphics/fwd.gif b/web/cgi/alpine/2.0/help/graphics/fwd.gif Binary files differnew file mode 100644 index 00000000..546ff6a3 --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/fwd.gif diff --git a/web/cgi/alpine/2.0/help/graphics/new.gif b/web/cgi/alpine/2.0/help/graphics/new.gif Binary files differnew file mode 100644 index 00000000..abc16be0 --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/new.gif diff --git a/web/cgi/alpine/2.0/help/graphics/parts.gif b/web/cgi/alpine/2.0/help/graphics/parts.gif Binary files differnew file mode 100644 index 00000000..90fbb390 --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/parts.gif diff --git a/web/cgi/alpine/2.0/help/graphics/replied.gif b/web/cgi/alpine/2.0/help/graphics/replied.gif Binary files differnew file mode 100644 index 00000000..8ff06835 --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/replied.gif diff --git a/web/cgi/alpine/2.0/help/graphics/replied_and_fwd.gif b/web/cgi/alpine/2.0/help/graphics/replied_and_fwd.gif Binary files differnew file mode 100644 index 00000000..b3dd5a1b --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/replied_and_fwd.gif diff --git a/web/cgi/alpine/2.0/help/graphics/screen-header.gif b/web/cgi/alpine/2.0/help/graphics/screen-header.gif Binary files differnew file mode 100644 index 00000000..f8c95dee --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/screen-header.gif diff --git a/web/cgi/alpine/2.0/help/graphics/star.gif b/web/cgi/alpine/2.0/help/graphics/star.gif Binary files differnew file mode 100644 index 00000000..5a89f298 --- /dev/null +++ b/web/cgi/alpine/2.0/help/graphics/star.gif diff --git a/web/cgi/alpine/2.0/help/help_home.htm b/web/cgi/alpine/2.0/help/help_home.htm new file mode 100644 index 00000000..559591a1 --- /dev/null +++ b/web/cgi/alpine/2.0/help/help_home.htm @@ -0,0 +1,46 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Help: WebMail</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="help_index.htm">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+ <h2>WebMail Help</h2>
+ <dl>
+ <dd>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam erat volupat. <br>
+ <br>
+ <div class="note">
+ <h4>Note</h4>
+ <div>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam erat volupat.</div>
+ </div>
+ </dd>
+ <dt>Message List (e.g. INBOX)</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Folders</dt>
+ <dd>Con sectetuer adipiscing elit, sed diam nonnumy nibh.</dd>
+ <dt>Compose</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Print</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Search</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>News and Weather</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ </dl>
+</div>
+<div class="also">
+ <h4>See also</h4>
+ <ul>
+ <li><a href="#">View/Manage Folders</a></li>
+ <li><a href="#">Contacts</a></li>
+ <li><a href="#">Settings</a></li>
+ </ul>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/help_index.htm b/web/cgi/alpine/2.0/help/help_index.htm new file mode 100644 index 00000000..ee694f73 --- /dev/null +++ b/web/cgi/alpine/2.0/help/help_index.htm @@ -0,0 +1,67 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Help: Index</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="javascript:history.back()">Go Back</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+ <h2>Index</h2>
+ <dl>
+ <dt>Message List: your inbox</dt>
+ <dd>
+ <ul>
+ <li><a href="#">INBOX</a></li>
+ <li><a href="#">Message Threading</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ <dt>Message View: reading email</dt>
+ <dd>
+ <ul>
+ <li><a href="#">Nonnumy Nibh</a></li>
+ <li><a href="#">Labore et Dolore</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ <dt>Compose: writing email</dt>
+ <dd>
+ <ul>
+ <li><a href="#">Nonnumy Nibh</a></li>
+ <li><a href="#">Labore et Dolore</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ <dt>Folders: organizing email</dt>
+ <dd>
+ <ul>
+ <li><a href="#">Nonnumy Nibh</a></li>
+ <li><a href="#">Labore et Dolore</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ <dt>Contacts: your address book</dt>
+ <dd>
+ <ul>
+ <li><a href="#">Nonnumy Nibh</a></li>
+ <li><a href="#">Labore et Dolore</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ <dt>Settings: customizing your webmail</dt>
+ <dd>
+ <ul>
+ <li><a href="#">Nonnumy Nibh</a></li>
+ <li><a href="#">Labore et Dolore</a></li>
+ <li><a href="#">Magna Ali Quam</a></li>
+ </ul>
+ </dd>
+ </dl>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/help_settings.htm b/web/cgi/alpine/2.0/help/help_settings.htm new file mode 100644 index 00000000..46cab725 --- /dev/null +++ b/web/cgi/alpine/2.0/help/help_settings.htm @@ -0,0 +1,66 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Help: Settings</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="help_index.htm">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+ <h2>Settings: General Preferences </h2>
+ <dl>
+ <dd>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam erat volupat. <br>
+ <br>
+ <div class="note">
+ <h4>Note:</h4>
+ <div>You <b>must</b> save your changes before going to another section.</div>
+ </div>
+ <div class="note">
+ <h4>Note:</h4>
+ <div>The "Reset to Default Settings" button, found at the bottom of some pages, will reset your setting to the default settings.</div>
+ </div>
+ </dd>
+ <dt>Display</dt>
+ <dd>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam.</dd>
+ <dt>Folders</dt>
+ <dd>Con sectetuer adipiscing elit, sed diam nonnumy nibh.</dd>
+ <dt>Compose Encoding</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Reply Options</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Forwarding Options</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Flag Personal Email</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>New Mail Notification</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Auto-Contacts</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Save Sent</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Archive Sent</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Emptying Trash</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Fcc Options</dt>
+ <dd>Set whether to save with or without attachments when auto-saving messages to the Fcc (Folder carbon copy) folder.</dd>
+ <dt>Keyboard Shortcuts</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ </dl>
+</div>
+<div class="also">
+ <h4>See also</h4>
+ <ul>
+ <li><a href="#">Personal Information</a></li>
+ <li><a href="#">News and Weather Bar</a></li>
+ <li><a href="#">Spam Filter</a></li>
+ <li><a href="#">Vacation Auto-Reply</a></li>
+ <li><a href="#">Advanced Settings</a></li>
+ </ul>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/inbox.html b/web/cgi/alpine/2.0/help/inbox.html new file mode 100644 index 00000000..716a19f1 --- /dev/null +++ b/web/cgi/alpine/2.0/help/inbox.html @@ -0,0 +1,145 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/cbn/screen.css">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Your Inbox</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+
+<h2>Your Inbox</h2>
+
+<ul>
+ <li><a href="#view">Viewing messages</a></li>
+ <li><a href="#sort">Sorting messages</a></li>
+ <li><a href="#delete">Deleting messages</a></li>
+ <li><a href="#folder">Saving messages to a folder</a></li>
+ <li><a href="#icons">Icons</a></li>
+ <li><a href="#stars">Marking messages with stars</a></li>
+ <li><a href="#spam">Reporting messages as spam</a></li>
+ <li><a href="#trash">Emptying trash</a></li>
+ <li><a href="#drag">Drag and Drop Shortcuts</a></li>
+</ul>
+
+<p>When you first log in to your mail account, you see your Inbox. Your Inbox stores and displays your mail messages.</p>
+<p>The main body of the display consists of one line per message. By default, your Inbox displays 25 messages on each page. Use the arrows at the right end of the menu bar or at the bottom of the browser window to move from page to page in the list.</p>
+<p>To change the number of messages displayed per page, see <a href="settings.html#display">Settings</a>.</p>
+<p>There is a checkbox at the start of each message line. To select a set of messages on which to perform an action (for example, Deleting) click in the checkbox. The checkbox at the top of the column selects/unselects all of the messages on the page.</p>
+<h2><a name="view" id="view"></a>Viewing messages</h2>
+<p><strong>To read a message</strong></p>
+<ul>
+ <li>Click the <b>Subject</b> of the message.</li>
+</ul>
+<p><strong>To read messages in other folders</strong></p>
+<ul>
+ <li>Click the desired folder in the left pane.</li>
+<br /><br /></ul>
+<h2><a name="sort" id="sort"></a>Sorting messages</h2>
+<p>By default the message index is sorted by <strong>Date</strong>, with the most recent messages coming first and the oldest messages at the bottom of the index. You can change this default sort order in <a href="settings.html">Settings</a></p>
+<ul>
+ <li><strong>Sort by columns on the list.</strong> Click a column heading, such as <strong>From</strong>, <strong>Subject</strong>, or <strong>Date</strong> to sort by that field. Click on the small triangle next to the sort heading to reverse the sort order.</li>
+
+ <li><strong>Group by Thread.</strong> Groups all messages in the same conversation together, in a a tree view. This option is available in the <strong>Arrange</strong> menu bar above the column headings.</li>
+
+ <li><strong>Group by Subject.</strong> Groups all messages with the same subject together. This option is also only available in the <strong>Arrange</strong> menu.</li>
+
+ <li><strong>Sort by Arrival.</strong> Sometimes it is convenient to sort in the order that the messages were added to the folder instead of by the Date, which is usually similar but a little different. Select this option from the <strong>Arrange</strong> menu.</li>
+<br /><br /></ul>
+
+<h2><a name="delete" id="delete"></a>Deleting messages</h2>
+<ol>
+ <li>Select the messages you wish to delete by checking the boxes to the left of the messages.</li>
+ <li>On the menu bar, click <strong>Delete</strong>.</li>
+</ol>
+
+<p>When you click <strong>Delete</strong>, the selected messages are moved to the Trash<a href="#trash"></a>, where you can delete them later. </p>
+
+<h2><a name="folder" id="folder"></a>Saving messages to a folder</h2>
+<p>You can move or copy messages from the Inbox to a folder. Moving a message removes it from the Inbox while creating a copy in the designated folder. Copying a message leaves the message in the Inbox while creating a copy in the designated folder.</p>
+<ol>
+ <li>Select the box to the left of the message or messages that you wish to put in a folder.</li>
+ <li>On the menu bar, locate the <strong>Move</strong> or <strong>Copy</strong> button. Skip this step if the one you want is already displayed. If necessary, click the button and pull down the menu to select <strong>Move</strong> or <strong>Copy</strong>.</li>
+ <li>On the menu bar, click <strong>to Folder</strong> and select the target folder from the list, or select <strong>More Folders</strong> to see a list of all folders. If you select <strong>More Folders</strong>, click the target folder in the list, and then click <strong>Copy</strong> or <strong>Move</strong>.</li>
+<br /><br /></ol>
+
+<h2><a name="icons" id="icon"></a>Icons</h2>
+<p>Several informative icons may appear to the left of the <strong>From</strong> column.</p>
+
+<table border="1">
+ <tr>
+ <th width="15%" >Icon</th>
+ <th width="80%" >Meaning</th>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml1"> </span></div></td>
+ <td>New message</td>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml6"> </span></div></td>
+ <td>The message includes an attachment</td>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml2"> </span></div></td>
+ <td>You have replied to the message</td>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml3"> </span></div></td>
+ <td>You have forwarded the message</td>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml4"> </span></div></td>
+ <td>The message is addressed directly to you</td>
+ </tr>
+ <tr>
+ <td><span class="sp spml spml5"> </span></div></td>
+ <td>The message is cc'd to you</td>
+ </tr>
+</table>
+<p>In addition, messages that have not been read are displayed in bold text.</p>
+<h2><a name="stars" id="stars"></a>Marking messages with stars</h2>
+<p>You can mark messages with stars <img src="graphics/star.gif" alt="Star" width="17" height="17" /> that appear in the far right column of the list. The stars can indicate anything that you like. For example, you might mark the most important messages with a star.</p>
+
+<p><strong>To mark a message with a star</strong></p>
+<ul>
+ <li>Click in the rightmost column of the list on the row for that message or select <strong>Set Star</strong> from the <strong>More Actions</strong> menu in the menu bar.</li>
+<br /><br /></ul>
+<h2><a name="spam" id="spam"></a>Reporting messages as spam</h2>
+<p>If you get a message that you think should have been identified by the spam detection processes but wasn't, you may submit it for review, which may help improve the effectiveness of spam detection. </p>
+<p><strong>To report spam</strong></p>
+<ol>
+ <li>Select the message or messages that you wish to report as spam by checking the boxes in the left column.</li>
+ <li>On the menu bar, click <strong>Report Spam</strong>. A copy of the message is sent to the University of Washington spam detection process and the message is moved to your <strong>Junk</strong> folder.</li>
+<br /><br /></ol>
+<h2><a name="trash" id="trash"></a>Emptying trash</h2>
+<p>When messages are deleted they are actually moved to the <strong>Trash</strong> folder and not immediately deleted. To permanently remove the messages you must empty the trash.</p>
+<p><strong>To empty the entire contents of the trash</strong></p>
+<ul>
+ <li>Find the <strong>Trash</strong> folder in the left pane. If there are messages in the Trash folder you may click on the word <strong>Empty</strong> next to the Trash folder to empty it. This is also true of the <strong>Junk</strong> folder, which may be emptied in the same way.</li>
+</ul>
+<p><strong>To permanently delete selected messages from the trash</strong></p>
+<ol>
+ <li>In the left pane, click <strong>Trash</strong>.</li>
+ <li>Select the box to the left of the messages that you want to delete.</li>
+ <li>On the menu bar, click <strong>Delete Forever</strong>. Be sure that you have selected the right messages; there is no confirmation screen for this action.</li>
+</ol>
+<p><strong>To recover messages from the trash</strong></p>
+<ol>
+ <li>In the left pane, click Trash.</li>
+ <li>Select the box to the left of the messages that you want to recover.</li>
+ <li>On the menu bar, locate the <strong>Move</strong> or <strong>Copy</strong> button. Skip this step if the one you want is already dislayed. If necessary, click the button and pull down the menu to select <strong>Move</strong> or <strong>Copy</strong>.</li>
+ <li>On the menu bar, click <strong>to Folder</strong> and select the target folder from the list, or select <strong>More Folders</strong> to see a list of all folders. If you select <strong>More Folders</strong>, click the target folder in the list, and then click <strong>Copy</strong> or <strong>Move</strong>.</li>
+<br /><br /></ol>
+<h2><a name="drag" id="drag"></a>Drag and Drop Shortcuts</h2>
+<p>You may grab a message by its From field and drag it over a folder in the left pane in order to move it to the folder. Alternatively, if you drag it to the Contacts list in the left pane and drop it there the From address will be added to your list of Contacts.</p>
+
+
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/popup/_notes/dwsync.xml b/web/cgi/alpine/2.0/help/popup/_notes/dwsync.xml new file mode 100644 index 00000000..e659193f --- /dev/null +++ b/web/cgi/alpine/2.0/help/popup/_notes/dwsync.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8" ?>
+<dwsync>
+<file name="help_set_display.htm" local="128395568460000000" remote="128413808830000000" testing="0" />
+</dwsync>
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/help/popup/help_set_display.htm b/web/cgi/alpine/2.0/help/popup/help_set_display.htm new file mode 100644 index 00000000..574ba8db --- /dev/null +++ b/web/cgi/alpine/2.0/help/popup/help_set_display.htm @@ -0,0 +1,36 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../../css/help_popup.css">
+<title>Help: WebMail</title>
+</head>
+<body>
+<div id="header">
+ <div class="nav"><a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+ <h2>Settings: Display</h2>
+ <dl>
+ <dd>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam erat volupat. <br>
+ <br>
+ <div class="note">
+ <h4>Note</h4>
+ <div>Lorem ipsum dolor sit amet, con sectetuer adipiscing elit, sed diam nonnumy nibh eeuismod tempor inci dunt ut labore et dolore magna ali quam erat volupat.</div>
+ </div>
+ </dd>
+ <dt>Themes</dt>
+ <dd>Ut wisi enim ad minim veniam.</dd>
+ <dt>Number of messages per page</dt>
+ <dd>Con sectetuer adipiscing elit, sed diam nonnumy nibh.</dd>
+ </dl>
+</div>
+<div class="also">
+ <h4>See also</h4>
+ <ul>
+ <li><a href="#">Lorem ipsum dolor sit</a></li>
+ <li><a href="#">con sectetuer</a></li>
+ </ul>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/quick-start.html b/web/cgi/alpine/2.0/help/quick-start.html new file mode 100644 index 00000000..68ce79b3 --- /dev/null +++ b/web/cgi/alpine/2.0/help/quick-start.html @@ -0,0 +1,136 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Alpine Help Pages</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+
+<h2>Alpine Quick Start</h2>
+
+
+<p>This page provides a quick overview of basic Alpine features and how to access them.</p>
+<ul>
+ <li><a href="#main">Main parts of the Alpine screen</a></li>
+ <li><a href="#compose">Parts of the Compose window</a></li>
+ <li><a href="#basic">Basic Alpine Features</a></li><br /><br />
+</ul>
+<h2><a name="main" id="main"></a>Main parts of the Alpine screen</h2>
+<p>The following figure shows a portion of the Alpine screen with the main parts identified. </p>
+<p><img src="graphics/parts.gif" alt="Main parts of the screen" width="426" height="186" /></p>
+<h3>Screen header<br /><br /><hr /></h3>
+<p><img src="graphics/screen-header.gif" alt="Screen header" width="445" height="54" /></p>
+<ul>
+ <li>The top portion provides links to University of Washington news and local weather. The top portion also displays error messages and comfirmation messages, such as confirming that you have moved or copied a message to a folder.</li>
+ <li>The right side provides a bar graph representing the portion of your account's disk space allocation that is currently used.</li>
+ <li>Below the bar graph are links for Settings (for customizing your mail), Help (for displaying this Help system), and Sign out.</li>
+</ul>
+<h3>Menu bar<br /><br /><hr /></h3>
+<p>The menu bar provides commands needed for each Alpine screen. The two leftmost commands, <a href="#check">Check Mail</a> and <a href="compose.html">Compose</a>, are the same in all Alpine screens. The other commands change according to which Alpine screen is dislayed.</p>
+<h3>Left pane<br /><br /><hr /></h3>
+<p>The left pane displays:</p>
+<ul>
+ <li><strong>Search.</strong> For a basic search, type a word in the search box and click the search icon. For more search options, click Advanced Search.</li>
+ <li><strong>Inbox and other default folders.</strong> Your inbox contains your mail as it arrives, you can use other folders to organize your mail.</li>
+ <li><strong>Contacts.</strong> Click to view and manage your contacts.</li>
+ <li><strong>Recent Folders.</strong> A list of the folders that you have recently accessed. You can control how many recent folders are listed (see Settings).</li>
+ <li><strong>View/Manage Folders.</strong> Click to view a list of all of your folders. From this list, you can add, delete, and rename folders.</li>
+ </ul>
+ <h3>Right pane<br /><br /><hr />
+ </h3>
+
+
+<p>Depending on what you are doing, the right pane displays one of five things:</p>
+<ul>
+ <li> <strong><a name="mlists" id="mlists"></a>Message lists.</strong> Display the contents of the folders in the left pane: Inbox, Drafts, Sent, and so forth. The message lists share a common format that allows you to view and manage your messages.</li>
+ <li><strong>The Compose window.</strong> Allows you to write and reply to messages.</li>
+ <li><strong>Your folder list</strong>. A list of all Alpine folders, both the standard Alpine folders such as Inbox, and any folders that you create. You can manage your folders from this list.</li>
+ <li><strong>Your contacts list.</strong> A list of all of the contacts that you have created. The contacts list functions as your address book.</li>
+ <li><strong>The Settings window.</strong> Allows you to customize the appearance and behavior of Alpine for your account.</li><br /><br />
+</ul>
+
+<h2><a name="compose" id="compose"></a>Parts of the Compose window</h2>
+<p>In the Compose window, you can write, send, and reply to messages. The following figure shows the main parts of the Compose window. </p>
+<p><img src="graphics/compose.gif" alt="Compose screen" /></p>
+<ul>
+ <li> <strong>Header section</strong> (at the top). You use the header section to address the mail and control the text format. </li>
+
+ <li><strong>Message section</strong> (below the header). The message section is where you enter and format message text. </li><br /><br />
+
+</ul>
+<h2><a name="basic" id="basic"></a>Basic Alpine Features</h2>
+<h3>Viewing messages<br /><hr /></h3>
+<p>When you first log in, your Inbox is displayed in the right pane, showing a list of your mail messages. </p>
+<ul>
+ <li>By default, the list contains 25 messages per page. Click the arrows on the right side of the menu bar to move from page to page.</li>
+ <li>You can sort messages in the list by clicking the column headings.</li>
+ <li>You can drag and drop messages from the right pane to the folders in the left pane or to your contacts: click and hold on the name or email address in the From column to drag a message.</li>
+ </ul>
+<p>For more information, see <a href="inbox.html">Your Inbox</a>.</p>
+<h3>Reading mail<br /><hr /></h3>
+
+<p>To read a message, click on its <strong>Subject</strong>. For more information, see <a href="read.html">Reading mail</a>.</p>
+
+<h3>Sending mail<br /><hr /></h3>
+
+To send a message, click <strong>Compose</strong> (or <strong>Reply</strong> or <strong>Forward</strong>) on the menu bar. For more information, see <a href="compose.html">Compose: sending mail</a>.
+
+<h3>Search<br /><hr /></h3>
+
+<p>To search for a message, type a search string in the <strong>Search</strong> box, at the top of the <a href="#main">left pane</a>. Click <strong>Advanced Search</strong> for more search options. For more information, see <a href="search.html">Search</a>.</p>
+
+<h3>Folders<br /><hr /></h3>
+
+<p>Folders help you keep your mail organized. Default folders, such as <strong>Inbox</strong> and <strong>Junk</strong>, are always there. You can also create your own folders by clicking <strong>View/Manage Folders</strong>. For more information, see <a href="folders.html">Folders</a>.</p>
+
+
+<h3>Contacts<br /><hr /></h3>
+
+<p>You can create a contact list,which is a list of addresses that are important or that you frequently use. Click <strong>Contacts</strong> to add items to your contact list. For more information, click <a href="contacts.html">Contacts</a>.</p>
+
+
+<h3><a name="check" id="check"></a>Checking for new mail<br /><hr /></h3>
+
+<p>You can check for new mail from any Alpine window or folder without returning to your Inbox.</p>
+
+<p><strong>To check for new mail </strong></p>
+<ul>
+ <li>On the menu bar, click <strong>Check Mail</strong>. Alpine checks for new mail. If you have any new mail, a message appears in the middle of the <a href="#main">screen header</a>.</li>
+ </ul>
+
+<h3>Settings<br /><hr /></h3>
+<p>You can control the appearance and behavior of many parts of the Alpine screen. For more information, see <a href="settings.html">Settings</a>.</p>
+<ul>
+
+</ul>
+<h3><a name="trash" id="trash"></a>Trash<br /><hr /></h3>
+<p>When you delete a message, it is moved to the trash. When you empty the trash or delete selected messages from the trash, they are removed permanently. You can also recover messages from the trash.</p>
+<p><strong>To empty the entire contents of the trash</strong></p>
+<ol>
+ <li>In the left pane, next to <strong>Trash</strong>, click <strong>[Empty]</strong>. </li>
+ <li>Click <strong>Empty Trash</strong> to confirm.</li>
+</ol>
+<p>This permanently deletes all of the messages in the trash.</p>
+<p><strong>To permanently delete selected messages from the trash</strong></p>
+<ol>
+ <li>In the left pane, click <strong>Trash</strong>.</li>
+ <li>Select the box to the left of the messages that you want to delete.</li>
+ <li>On the menu bar, click <strong>Delete Forever</strong>. Be sure that you have selected the right messages; there is no confirmation screen for this action.</li>
+</ol>
+<p><strong>To recover messages from the trash</strong></p>
+<ol>
+ <li>In the left pane, click Trash.</li>
+ <li>Select the box to the left of the messages that you want to recover.</li>
+ <li>On the menu bar, locate the <strong>Move</strong> or <strong>Copy</strong> button. Skip this step if the one you want is already dislayed. If necessary, click the button and pull down the menu to select <strong>Move</strong> or <strong>Copy</strong>.</li>
+ <li>On the menu bar, click <strong>to Folder</strong> and select the target folder from the list, or select <strong>More Folders</strong> to see a list of all folders. If you select <strong>More Folders</strong>, click the target folder in the list, and then click <strong>Copy</strong> or <strong>Move</strong>.</li>
+</ol>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/read.html b/web/cgi/alpine/2.0/help/read.html new file mode 100644 index 00000000..155f4caf --- /dev/null +++ b/web/cgi/alpine/2.0/help/read.html @@ -0,0 +1,145 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Reading mail</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+<h2>Reading mail</h2>
+
+<ul>
+ <li><a href="#view">Viewing a message</a></li>
+ <li><a href="#attachments">Viewing and downloading attachments</a></li>
+ <li><a href="#full">Displaying full headers</a></li>
+ <li><a href="#reply">Replying </a></li>
+ <li><a href="#forward">Forwarding </a></li>
+ <li><a href="#contacts">Adding contacts</a></li>
+ <li><a href="#folder">Saving messages to a folder</a></li>
+ <li><a href="#print">Printing </a></li>
+ <li><a href="#delete">Deleting a message</a></li>
+ <li><a href="#spam">Reporting a message as spam</a></li>
+ <br /><br />
+</ul>
+
+
+
+<h2><a name="view" id="view"></a>Viewing a message</h2>
+ <p><strong>To view a message</strong></p>
+<ul>
+
+ <li>Click its <strong>Subject</strong> in the list of messages.</li>
+<br /><br /></ul>
+<h2><a name="attachments" id="attachments"></a>Viewing and downloading attachments</h2>
+
+<p>Attachments are listed in the header area at the top of the message. Attachments are marked with the paper clip <img src="graphics/attach_sm.gif" alt="Attachment" width="17" height="17" /> icon.</p>
+<p><strong>To open an attachment</strong></p>
+<ul>
+ <li>Click the file name.</li>
+</ul>
+<p><strong>To download an attachment</strong></p>
+<ol>
+ <li>Open the attachment.</li>
+ <li>In the application that opens the attachment, save a copy of the attachment to your computer.</li>
+ <br /><br />
+</ol>
+
+<h2><a name="full" id="header"></a>Displaying full headers</h2>
+<p>When you are viewing a message, the header section at the top of the message displays a standard set of headers including the message Subject, From, To, Cc, Date, and Attachments (if there are any). It is possible to show the full set of headers in the message, which includes a complete list of all routing from the message source to your Inbox, along with all other headers. These full headers may be useful in troubleshooting.</p>
+<p><strong>To display full headers</strong></p>
+<ul>
+ <li>In the top right corner of the message, click <strong>Show Full Headers</strong>. </li>
+</ul>
+<p><strong>To cancel full headers</strong></p>
+<ul>
+ <li>In the top right corner of the message, click <strong>Show Filtered Headers</strong>. </li>
+<br /><br /></ul>
+<h2><a name="reply" id="reply"></a>Replying </h2>
+<ol>
+ <li>On the menu bar, click <strong>Reply</strong> or <strong>Reply All</strong>.
+ <ul>
+ <li><strong>Reply.</strong> Sends a reply to the address or addresses in the To field.<br />
+ or</li>
+ <li><strong>Reply All.</strong> Sends a reply to the addresses in the <strong>To</strong> and <strong>Cc</strong> fields.</li>
+ <br /></ul>
+ </li>
+ <li>Proceed as for <a href="compose.html">sending mail</a><strong></strong>.</li>
+ </ol>
+
+<p>In either case the reply is not sent immediately. Instead, you are placed in the message composer with the addresses filled in.</p>
+<p>You can control the message format and other features of your replies. The <a href="settings.html#reply">Reply settings</a> allow you to select:</p>
+<ul>
+ <li>Whether or not to include headers</li>
+ <li>Whether or not to include attachments</li>
+ <li>Whether to place your signature above or below the replied to text</li>
+ <li>Whether or not to remove the signature from the replied to text</li>
+ <br />
+ <br />
+
+</ul>
+<h2><a name="forward" id="forward"></a>Forwarding </h2>
+<ol>
+ <li>On the menu bar, click <strong>Forward</strong>.</li>
+ <li>Proceed as for <a href="compose.html">sending mail</a>.</li>
+ </ol>
+
+<p>You can control whether to forward messages as inline text or as attachments. For more information, see <a href="settings.html#forward">Settings</a>.</p>
+
+<h2><a name="contacts" id="contacts"></a>Adding contacts</h2>
+<p>When you are reading a message, you can add the sender to your list of contacts.</p>
+
+<p><strong>To add a contact</strong></p>
+
+<ul>
+<li>Drag the contact's email address from the <strong>From</strong> field to the <strong>Contacts</strong> folder.
+<p><em>or</em></p></li>
+<li>To the right of the <strong>From</strong> field, click <strong>Add</strong>.</li>
+<br /><br /></ul>
+<p><strong>To add multiple contacts from a message</strong></p>
+<ul>
+ <li>On the menu bar, click <strong>More Actions</strong>, and then select <strong>Extract</strong>. Alpine extracts everything in the message that is in the format of an email address and presents a list of contacts. You can confirm each contact.</li>
+<br /><br /></ul>
+<p><strong>To finish adding a contact</strong></p>
+<ol>
+ <li>Enter the contact information:
+ <ul>
+ <li><strong>Nickname.</strong> A short name that you can use for quick addressing. If you type the nickname instead of the full display name or email address, Alpine will offer a list of matching choices from your contacts list and the University of Washington directory. You can select the contact from the list.</li>
+ <li><strong>Display Name.</strong> The name that appears in the message header.</li>
+ <li><strong>Email.</strong> The contact's email address.</li>
+ <li><strong>Notes.</strong> Any text you want. Used only by you.</li>
+ <li><strong>Fcc folder.</strong> A folder that will receive copies of all messages that you send directly to this contact.</li>
+ <br /></ul>
+ </li>
+ <li>Click <strong>Add</strong> to commit the contact to your address book.</li>
+<br /><br /></ol>
+<h2><a name="folder" id="folder"></a>Saving messages to a folder</h2>
+<p>You can move or copy messages to folders. Moving a message removes it from the Inbox while creating a copy in the designated folder. Copying a message leaves the message in the Inbox while creating a copy in the designated folder.</p>
+<ol>
+ <li>On the menu bar, locate the <strong>Move</strong> or <strong>Copy</strong> button. Skip this step if the one you want is already displayed. If necessary, click the button and pull down the menu to select <strong>Move</strong> or <strong>Copy</strong>.</li>
+ <li>On the menu bar, click <strong>to Folder</strong> and select the target folder from the list, or select <strong>More Folders</strong> to see a list of all folders. If you select <strong>More Folders</strong>, click the target folder in the list, and then click <strong>Copy</strong> or <strong>Move</strong>.</li>
+<br /><br /></ol>
+<h2><a name="print" id="print"></a>Printing</h2>
+<p><strong>To print a message</strong></p>
+<ul>
+ <li>In the area above the menu bar on the right click <strong>Print</strong>.</li>
+</ul>
+<h2><a name="delete" id="delete"></a>Deleting a message</h2>
+<ol>
+ <li>On the menu bar, click <strong>Delete</strong>.</li>
+</ol>
+
+<p>When you click <strong>Delete</strong>, the message you are viewing is moved to the Trash folder and you will be viewing the next message in your Inbox.</p>
+<h2><a name="spam" id="spam"></a>Reporting a message as spam</h2>
+<p>If you are reading a message that you think should have been identified by the spam detection processes but wasn't, you may submit it for review, which may help improve the effectiveness of spam detection. </p>
+<p><strong>To report spam</strong></p>
+<ol>
+ <li>On the menu bar, click <strong>Report Spam</strong>. A copy of the message is sent to the University of Washington spam detection process and the message is moved to your <strong>Junk</strong> folder.</li>
+<br /><br /></ol>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/search.html b/web/cgi/alpine/2.0/help/search.html new file mode 100644 index 00000000..3518058e --- /dev/null +++ b/web/cgi/alpine/2.0/help/search.html @@ -0,0 +1,77 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Search</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+<h2>Search</h2>
+
+<ul>
+ <li><a href="#inbox">Basic Index Search</a></li>
+ <li><a href="#advanced">Advanced Index Search</a></li>
+ <li><a href="#example">Example</a></li>
+ <li><a href="#other">Other Searches (Contacts and Folder List)</a></li>
+<br /><br /></ul>
+
+<p>The <strong>Search</strong> area is in the upper portion of the left pane, just below the menu bar. At a minimum, there will be a text box for you to enter text to be searched for. If the right pane contains an index of messages there will also be an <strong>Advanced Search</strong> button. If you've already completed an index search and the right pane contains the Search Results then there are some additional button available. These are described below.</p>
+
+<h2><a name="search" id="search"></a>Basic Index Search</h2>
+
+<p>You may perform a basic search of all the messages in the index by typing some text into the search text box and clicking the search icon next to the box. This will be a search of the entire text of the messages, not just the Subject.</p>
+
+<p><strong>To search for messages</strong></p>
+<ul>
+ <li>Find the <strong>Search</strong> text box in the upper part of the left pane and click in it.</li>
+ <li>Type the search text into the box.</li>
+</ul>
+
+<p>The result of the search will be a message index containing only the subset of messages that match the search criterion. A message about the number of matches will be displayed in the Screen Header area and the heading will change from <strong>INBOX</strong> to <strong>Search Results in INBOX</strong> to show you that you are viewing a subset of the messages. Near the bottom of the page the total number of messages in the Search Result will be shown instead of the total number of messages in the INBOX.</p>
+
+<p>There will be a couple new items in the Search area of the screen. The highlighted <em>folder</em> in the search area will be called <strong>Search Results</strong>. You may go back and forth between the INBOX and the Search Results by clicking on the INBOX or on the Search Results. There will be a new button next to Advanced Search labeled <strong>Clear</strong>. Clicking that will clear the results of the search.</p>
+
+<p>You can start a brand new search by typing in more text and searching again. As long as the menu in the search area says <strong>New Search</strong> you will be searching the entire INBOX again, just like with the initial search. However, you also have the option of refining the search you have done so far by setting the menu to either <strong>Search within Results</strong> or <strong>Add to Search Results</strong>. A <strong>Search within Results</strong> search will reduce the size of the Search Results, showing you the subset of the current Search Results that also match your new search. An <strong>Add to Search Results</strong> search will increase the size of the Search Results, adding all of the new matches to the existing Search Results.</p>
+
+<p>If you are refining your Search Results and there are no matches, the Search Results will remain the same instead of showing nothing, so that you won't lose the previous results. A message in the Screen Header will say <strong>No messages matched your search</strong>.</p>
+
+<h2><a name="advanced" id="advanced"></a>Advanced Index Search</h2>
+<p>Clicking on <strong>Advanced Search</strong> allows you to more tightly control the method of searching for matching messages. For example, you could search for all messages where the Subject contains (or doesn't contain) a certain word. If you fill in more than one of the criteria they all have to match. For example, if you fill in some text that the Subject must contain <strong>and</strong> also type in some text in that the From must contain; the <strong>Search Results</strong> will only contain messages that both have a matching From and have a matching Subject.</p>
+
+<p>At the top of the <strong>Advanced Search</strong> panel is a menu similar to the one in the Basic search area where you say what sort of refinement on the current search you want to perform. This can be either a brand new search, a narrowing down of the current Search Results (<strong>search within</strong>), or a widening of the current Search Results (<strong>add results</strong>).</p>
+
+<h2><a name="example" id="example"></a>Example</h2>
+<p>Searching is often done iteratively, a step at a time, until you locate the message you are looking for.</p>
+<p>You might start out looking for a message that you can recall contains the word <strong>firefox</strong>.</p>
+
+<ul>
+ <li>Type <strong>firefox</strong> in the search text box click to search.</li>
+</ul>
+
+<p>You got way more matches than you expected so you try to think of some way to refine the search. You remember that the message also contains the word <strong>awesome</strong>.</p>
+
+<ul>
+ <li>Set the search menu to <strong>Search within Results</strong>.</li>
+ <li>Type <strong>awesome</strong> in the search text box and click to search.</li>
+</ul>
+
+<p>Maybe you see your message now or maybe you need to refine further. Suppose you know the message came within the past week.</p>
+
+<ul>
+ <li>Click <strong>Advanced Search</strong>.
+ <li>Be sure the choice at the top of the Search panel is set to <strong>Perform this search within current search results</strong>.
+ <li>Set the <strong>Date</strong> menu to <strong>Past week</strong>.
+ <li>Click <strong>Search</strong>.</li>
+<br /><br /></ul>
+
+<h2><a name="other" id="other"></a>Other Searches (Contacts and Folder List)</h2>
+<p>You can also perform basic searches while viewing your Folder List and while viewing your Contacts. In both cases, the search is a simple text search to match what you type, and only the text that is displayed on the screen is searched. The results are simply highlighted on the screen. You have to look for them yourself in order to use them.</p>
+
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/settings.html b/web/cgi/alpine/2.0/help/settings.html new file mode 100644 index 00000000..04dfa616 --- /dev/null +++ b/web/cgi/alpine/2.0/help/settings.html @@ -0,0 +1,124 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>Settings</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="topic-list.html">All Help Topics</a> | <a href="alpha-index.html">Index</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+<h2>Settings: customizing Alpine</h2>
+
+<ul>
+ <li><a href="#display">Message Display</a></li>
+ <li><a href="#folders">Folders</a></li>
+ <li><a href="#reply">Reply Options</a></li>
+ <li><a href="#forward">Forwarding Options</a></li>
+ <li><a href="#fcc">Sent Message Options</a></li>
+ <li><a href="#personal">Personal Preferences</a></li>
+ <li><a href="#newsweather">News and Weather</a></li>
+ <li><a href="#msglist">Message List</a></li>
+ <li><a href="#msgview">Message View</a></li>
+ <li><a href="#foldernames">Folder Names</a></li>
+ <li><a href="#compose">Compose</a></li>
+ <li><a href="#mailservers">Mail Servers</a></li>
+ <li><a href="#dirservers">Directory Servers</a></li>
+</ul>
+
+
+<p>The settings pages allow you to customize the behavior and appearance of Alpine.</p>
+<p><a name="show" id="show"></a><strong>To display the Settings pages</strong></p>
+<ul><li>In the upper right-corner of the screen, above the menu bar, click <strong>Settings</strong>.</li>
+<br /><br />
+</ul>
+
+<h2><a name="display" id="display"></a>Message Display</h2>
+<ul>
+ <li><strong>Display ___ messages per page.</strong> Controls the number of messages displayed on each page.</li>
+ <li> <strong>Wrap Plain Text message at ___ characters.</strong> Controls the overall width of the text block in plain text messages.</li>
+<br /><br /></ul>
+<h2><a name="folders" id="folders"></a>Folders</h2>
+<ul>
+ <li><strong>Display ___ recent folders in left column.</strong> Controls how many folders are displayed under <strong>Recent Folders</strong> in the left pane. <strong>Recent Folders</strong> are the folders that you have recently accessed, listed with the most recent at the top.</li>
+<br /><br /></ul>
+<h2><a name="reply" id="reply"></a>Reply Options</h2>
+<ul>
+ <li><strong>Include headers in replies.</strong> Includes the header section of the original message in the reply.</li>
+ <li><strong>Include attachments in replies.</strong> The recipient of the reply gets the attachments as well as the original message.</li>
+ <li><strong>Append signature below reply text.</strong> Adds your signature to the bottom of the reply instead of the top.</li>
+ <li><strong>Strip signatures when replying.</strong> Removes the signature that was in the message being replied to (if it can be identified).</li>
+<br /><br /></ul>
+<h2><a name="forward" id="forward"></a>Forwarding Options</h2>
+<ul>
+ <li> <strong>Forward messages inline.</strong> The recipient gets an ordinary text message.</li>
+ <li><strong>Forward messages as attachments.</strong> The recipient gets a message with the forwarded message attached.</li>
+<br /><br /></ul>
+<h2><a name="fcc" id="fcc"></a>Sent Message Options</h2>
+<ul>
+ <li><strong>Name of your Sent mail folder.</strong> Save messages you send to this folder (default is sent-mail). To disable the saving of sent mail set this to double double quotes ("").</li>
+ <li><strong>Save sent messages to Sent folder without attachments.</strong> Remove any attachments being sent before saving the message in your Sent mail folder.</li>
+<br /><br /></ul>
+<h2><a name="personal" id="personal"></a>Personal Preferences</h2>
+<ul>
+ <li><strong>Display Name.</strong> This is your full name (e.g., Fred Flintstone). It will be included as part of your From address in outgoing mail.</li>
+ <li><strong>Email Signature.</strong> This signature is automatically included in messages you compose. You will have the opportunity to edit it before sending.</li>
+ <li><strong>Alternate Addresses.</strong> You may enter a list of alternate addresses so that Alpine can tell when an address is you. This will affect the index display (messages will be marked with an icon showing it is to you when it is addressed to one of your addresses), the From address displayed in the index display (when the From address is one of your addresses the To address will be shown instead), and the <strong>Reply All</strong> command (addresses listed here will not be included).</li>
+</ul>
+<p><strong>To add Alternate Addresses</strong></p>
+<ul><li>On the Personal Preferences page find the <strong>Alternate Addresses</strong> option. Type alternate addresses into the text field. The <strong>Add</strong> button can be used to add additional addresses and the <strong>X</strong> buttons can be used to remove addresses. The addresses you enter should be the actual email address part of an address without the fullname or brackets. For example, <strong>user@example.com</strong>. The matching is not sensitive to upper or lower case differences, all will match. For the advanced user, a regular expression may be entered.</li>
+<br /><br />
+</ul>
+<h2><a name="newsweather" id="newsweather"></a>News and Weather</h2>
+<ul>
+ <li><strong>Headline News.</strong> RSS URL for news.</li>
+ <li><strong>Weather Bar.</strong> RSS URL for weather.</li>
+<br /><br /></ul>
+<h2><a name="msglist" id="msglist"></a>Message List</h2>
+<ul>
+ <li><strong>Default Sort Order.</strong> Sets the default sort order for the Message List. By default the sort order is set to <strong>Date/Reverse</strong>. The <strong>/Reverse</strong> part means that the newest messages will be at the top. It is also possible to temporarily change the sort order in the message list screen itself.</li>
+ <li><strong>Start display at.</strong> This just tells Alpine where to start in the index of messages. The message you specify here will be included in the first page of messages you see.</li>
+ <li><strong>Automatically Move Read Messages.</strong> Automatically move read messages to a Read Messages folder.</li>
+<br /><br /></ul>
+
+<h2><a name="msgview" id="msgview"></a>Message View</h2>
+<ul>
+ <li><strong>Display Headers.</strong> Specify which headers are to be displayed in the Message View. If you specify any headers here you must list all of the headers you wish to have displayed, not just the additional headers.</li>
+ <li><strong>Display complete URLs as links.</strong> URLs contained in a message are shown as active links when viewing the message.</li>
+ <li><strong>Display hostnames and incomplete URLs as links.</strong> Hostnames that begin with <strong>www</strong> and incomplete URLs contained in a message are shown as active links when viewing the message.</li>
+ <li><strong>Display email addresses as links.</strong> Email addresses contained in a message are displayed as active links that can be used for sending mail.</li>
+ <li><strong>Rich Text Display.</strong> Turning on this option will cause rich text messages to be shown as plain text.</li>
+ <li><strong>Anti-phishing.</strong> Usually the real hostname is displayed after links to make it easier to see if the link looks suspicious or not. Turning on this option will hide that information and is not recommended.</li>
+<br /><br /></ul>
+<h2><a name="foldernames" id="foldernames"></a>Folder Names</h2>
+<ul>
+ <li><strong>Draft Folder.</strong> Actual name of the folder that is usually referred to in Alpine as the <strong>Drafts</strong> folder. The default is <strong>postponed-msgs</strong>.</li>
+ <li><strong>Trash Folder.</strong> Actual name of the folder that is usually referred to in Alpine as the <strong>Trash</strong> folder. The default is <strong>Trash</strong>.</li>
+<br /><br /></ul>
+<h2><a name="compose" id="compose"></a>Compose</h2>
+<ul>
+ <li><strong>Compose Headers.</strong> You can control which headers you want visible when composing outgoing email using this option. You can specify any of the regular set, any of the Headers you see with More Headers, or any Customized Headers that you have already defined. If you use this setting at all, you must specify all the headers you want to see, you can't just add to the regular header set. The default set is To:, Cc:, and Subject:.</li>
+ <li><strong>Custom Headers.</strong> You may add your own custom headers to outgoing messages. Each header you specify here must include the header tag (Reply-To:, Approved:, etc.) and may optionally include a value for that header. If you want to see these custom headers each time you compose a message, you must add them to your Compose Headers list, otherwise they become part of the rich header set that you only see when you press the More Headers command. (If you are looking for a way to change which headers are displayed when you view a message, take a look at the Display Headers option in the Message View section instead.)</li>
+ <li><strong>Message Encoding.</strong> Send messages using the character encoding you set here.</li>
+ <li><strong>Reply intro string.</strong> This option is used to customize the content of the introduction line that is included when replying to a message and including the original message in the reply. It is not yet described here.</li>
+ <li><strong>Reply prefix.</strong> When a message is replied to and the text of the message is included, the included text usually has the text ">Â " prepended to each line, to indicate it is quoted text. It is recommended that you leave this option set to that value since that is a standard that other email reading programs will recognize and treat specially.</li>
+ <li><strong>Flowed Text Handling.</strong> Normally, when sending a message, Alpine generates flowed text where possible. The method for generating flowed text is defined in RFC 3676, the benefit of doing so is to send message text that can properly be viewed both on normal width displays and on displays with smaller or larger than normal screen widths. This feature turns off the generation of flowed text, as it might be desired to more tightly control how a message is displayed on the receiving end.</li>
+<br /><br /></ul>
+<h2><a name="mailservers" id="mailservers"></a>Mail Servers</h2>
+<ul>
+ <li><strong>Inbox Server.</strong> Technical name of the folder that is your <strong>INBOX</strong> folder. This will usually have to be set for you. An example is <strong>{example.com}inbox</strong>. The server name comes inside the brackets and the folder name comes after the brackets.</li>
+ <li><strong>SMTP Server.</strong> A list (usually a list of size one) consisting of the names of your SMTP servers. An SMTP server is used for sending mail. This is a domainname such as<strong>smtp.example.com</strong> and it may contain some options after the hostname. The options are introduced with a slash (/) and the name of the option. To use the submit port append <strong>/submit</strong> after the hostname. To use authentication append <strong>/user=username</strong> where <strong>username</strong> is the name you use to authenticate to the server. A more complicated example might look something like <strong>smtp.example.com/submit/user=myusername</strong>.<li>
+<br /><br /></ul>
+<h2><a name="dirservers" id="dirservers"></a>Directory Servers</h2>
+<ul>
+ <li><strong>LDAP Server.</strong> This option is currently too complicated to be set from within Web Alpine. The value it is looking for has the format of a raw ldap-servers config string found in an Alpine pinerc configuration file.</li>
+<br /><br /></ul>
+
+<p> </p>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/help/topic-list.html b/web/cgi/alpine/2.0/help/topic-list.html new file mode 100644 index 00000000..6b75bf07 --- /dev/null +++ b/web/cgi/alpine/2.0/help/topic-list.html @@ -0,0 +1,101 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1">
+<link type="text/css" rel="stylesheet" href="../css/help.css">
+<title>All Help Topics</title>
+</head>
+<body>
+<div id="header">
+ <div class="logo"> </div>
+ <div class="nav"><a href="alpha-index.html">Index</a> | <a href="javascript:history.back()">Go Back</a> | <a href="javascript:self.close();">Close</a></div>
+</div>
+<div id="content">
+
+
+ <h2>All Help Topics</h2>
+ <dl>
+ <dt><a href="quick-start.html">Alpine Quick Start</a></dt>
+ <dd>
+ <a href="quick-start.html#main">Main parts of the Alpine screen</a> -
+ <a href="quick-start.html#compose">Parts of the Compose window</a> -
+ <a href="quick-start.html#basic">Basic Alpine Features</a></li>
+ </dd>
+ <dt><a href="inbox.html">Your Inbox</a></dt>
+ <dd><a href="inbox.html#view">Viewing messages</a> -
+ <a href="inbox.html#sort">Sorting messages</a> -
+ <a href="inbox.html#delete">Deleting messages</a> -
+ <a href="inbox.html#folder">Saving messages to a folder</a> -
+ <a href="inbox.html#icons">Icons</a> -
+ <a href="inbox.html#stars">Marking messages with stars</a> -
+ <a href="inbox.html#spam">Reporting messages as spam</a> -
+ <a href="inbox.html#trash">Emptying trash</a> -
+ <a href="inbox.html#drag">Drag and Drop Shortcuts</a>
+ </dd>
+ <dt><a href="read.html">Reading mail</a></dt>
+ <dd>
+
+ <a href="read.html#view">Viewing a message</a> -
+ <a href="read.html#attachments">Viewing and downloading attachments</a> -
+ <a href="read.html#full">Displaying full headers</a> -
+ <a href="read.html#reply">Replying </a> -
+ <a href="read.html#forward">Forwarding </a> -
+ <a href="read.html#contacts">Adding contacts</a> -
+ <a href="read.html#folder">Saving messages to a folder</a> -
+ <a href="read.html#print">Printing </a> -
+ <a href="read.html#delete">Deleting a message </a> -
+ <a href="read.html#spam">Reporting a message as spam</a>
+ </dd>
+ <dt><a href="compose.html">Compose: sending mail</a></dt>
+ <dd>
+
+ <a href="compose.html#writing">Writing messages</a> -
+ <a href="compose.html#attachments">Including attachments</a> -
+ <a href="compose.html#sending">Sending, canceling, and saving drafts</a> -
+ <a href="compose.html#resuming">Resuming drafts</a> -
+ <a href="compose.html#headers">Headers</a> -
+ <a href="compose.html#autosave">Automatic saves</a>
+
+ </dd>
+ <dt><a href="search.html">Search</a></dt>
+ <dd>
+
+ <a href="search.html#inbox">Basic Index Search</a> -
+ <a href="search.html#advanced">Advanced Index Search</a> -
+ <a href="search.html#example">Example</a> -
+ <a href="search.html#other">Other Searches (Contacts and Folder List)</a>
+
+ </dd>
+ <dt><a href="folders.html">Folders: organizing your mail</a></dt>
+ <dd>
+
+ <a href="folders.html#view">Viewing your list of folders</a> -
+ <a href="folders.html#viewing">Viewing the messages in a folder</a> -
+ <a href="folders.html#add">Adding folders</a> -
+ <a href="folders.html#delete">Deleting folders</a> -
+ <a href="folders.html#rename">Renaming folders</a> -
+ <a href="folders.html#route">Routing mail to folders</a>
+
+ </dd>
+<dt><a href="settings.html">Settings: customizing Alpine</a></dt>
+ <dd>
+ <a href="settings.html#display">Message Display</a> -
+ <a href="settings.html#folders">Folders</a> -
+ <a href="settings.html#reply">Reply Options</a> -
+ <a href="settings.html#forward">Forwarding Options</a> -
+ <a href="settings.html#fcc">Sent Message Options</a> -
+ <a href="settings.html#personal">Personal Preferences</a> -
+ <a href="settings.html#newsweather">News and Weather</a> -
+ <a href="settings.html#msglist">Message List</a> -
+ <a href="settings.html#msgview">Message View</a> -
+ <a href="settings.html#folders">Folders</a> -
+ <a href="settings.html#compose">Compose</a> -
+ <a href="settings.html#mailservers">Mail Servers</a> -
+ <a href="settings.html#dirservers">Direcory Servers</a>
+ </dd>
+<dt><a href="alpha-index.html">Index</a></dt>
+ <dd> </dd>
+ </dl>
+</div>
+</body>
+</html>
diff --git a/web/cgi/alpine/2.0/img/cbn/Thumbs.db b/web/cgi/alpine/2.0/img/cbn/Thumbs.db Binary files differnew file mode 100644 index 00000000..1c7332e2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/Thumbs.db diff --git a/web/cgi/alpine/2.0/img/cbn/_notes/dwsync.xml b/web/cgi/alpine/2.0/img/cbn/_notes/dwsync.xml new file mode 100644 index 00000000..a15e49fc --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/_notes/dwsync.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8" ?>
+<dwsync>
+<file name="addcontact_sm.gif" local="128322025280000000" remote="128413808870000000" testing="0" />
+<file name="addfolder.gif" local="128324595100000000" remote="128413808870000000" testing="0" />
+<file name="attach.gif" local="128408549140000000" remote="128413808880000000" testing="0" />
+<file name="attach_sm.gif" local="128285018180000000" remote="128413808880000000" testing="0" />
+<file name="base.gif" local="126795687600000000" remote="128413808890000000" testing="0" />
+<file name="btnbg.gif" local="128149620340000000" remote="128413808890000000" testing="0" />
+<file name="btnhi.gif" local="128322774920000000" remote="128413808890000000" testing="0" />
+<file name="checkmail.gif" local="128408580420000000" remote="128413808900000000" testing="0" />
+<file name="close.gif" local="128287413900000000" remote="128413808900000000" testing="0" />
+<file name="col.gif" local="128282447240000000" remote="128413808900000000" testing="0" />
+<file name="colsel.gif" local="128407627840000000" remote="128413808910000000" testing="0" />
+<file name="compose.gif" local="128408546020000000" remote="128413808910000000" testing="0" />
+<file name="contacts.gif" local="128408580180000000" remote="128413808910000000" testing="0" />
+<file name="dawg.gif" local="128346358620000000" remote="128413808920000000" testing="0" />
+<file name="delete.gif" local="128408543180000000" remote="128413808920000000" testing="0" />
+<file name="detach.gif" local="128291071260000000" remote="128413808930000000" testing="0" />
+<file name="div.gif" local="128242883360000000" remote="128413808930000000" testing="0" />
+<file name="div2.gif" local="128242883360000000" remote="128413808930000000" testing="0" />
+<file name="dn.gif" local="128311444180000000" remote="128413808940000000" testing="0" />
+<file name="edit.gif" local="128408579240000000" remote="128413808940000000" testing="0" />
+<file name="fldsel.gif" local="128329923120000000" remote="128413808940000000" testing="0" />
+<file name="folder.gif" local="126795687600000000" remote="128413808950000000" testing="0" />
+<file name="folderopen.gif" local="126795687600000000" remote="128413808950000000" testing="0" />
+<file name="forward.gif" local="128408538380000000" remote="128413808950000000" testing="0" />
+<file name="fwd.gif" local="128297060120000000" remote="128413808960000000" testing="0" />
+<file name="f_contacts.gif" local="128408575980000000" remote="128413808960000000" testing="0" />
+<file name="f_delete.gif" local="128335113800000000" remote="128413808970000000" testing="0" />
+<file name="f_drafts.gif" local="128285005940000000" remote="128413808970000000" testing="0" />
+<file name="f_folder.gif" local="128335113040000000" remote="128413808970000000" testing="0" />
+<file name="f_inbox.gif" local="128408820000000000" remote="128413808980000000" testing="0" />
+<file name="f_manage.gif" local="128286587360000000" remote="128413808980000000" testing="0" />
+<file name="f_minus.gif" local="128408616920000000" remote="128413808990000000" testing="0" />
+<file name="f_plus.gif" local="128408615620000000" remote="128413808990000000" testing="0" />
+<file name="f_search.gif" local="128348118840000000" remote="128413808990000000" testing="0" />
+<file name="f_sent.gif" local="128408819900000000" remote="128413809000000000" testing="0" />
+<file name="f_spam.gif" local="128284929720000000" remote="128413809000000000" testing="0" />
+<file name="group_contact.gif" local="128408576620000000" remote="128413809010000000" testing="0" />
+<file name="help.gif" local="128408588340000000" remote="128413809010000000" testing="0" />
+<file name="help_sm.gif" local="128395563540000000" remote="128413809010000000" testing="0" />
+<file name="high.gif" local="128397216540000000" remote="128413809020000000" testing="0" />
+<file name="highest.gif" local="128397216560000000" remote="128413809020000000" testing="0" />
+<file name="inbox.gif" local="128408627500000000" remote="128413809020000000" testing="0" />
+<file name="info.gif" local="128285031840000000" remote="128413809030000000" testing="0" />
+<file name="infomsg.gif" local="126795687600000000" remote="128413809030000000" testing="0" />
+<file name="lo.gif" local="128242883560000000" remote="128413809040000000" testing="0" />
+<file name="logo.gif" local="128268543280000000" remote="128413809040000000" testing="0" />
+<file name="logo.png" local="128268542820000000" remote="128413809040000000" testing="0" />
+<file name="lookup.gif" local="128408547020000000" remote="128413809050000000" testing="0" />
+<file name="low.gif" local="128287410740000000" remote="128413809050000000" testing="0" />
+<file name="menu.gif" local="128294434100000000" remote="128413809060000000" testing="0" />
+<file name="musicfolder.gif" local="126795687600000000" remote="128413809060000000" testing="0" />
+<file name="navbg.gif" local="128149620340000000" remote="128413809070000000" testing="0" />
+<file name="new.gif" local="128297901460000000" remote="128413809070000000" testing="0" />
+<file name="page.gif" local="126795687600000000" remote="128413809070000000" testing="0" />
+<file name="parent.gif" local="128334255560000000" remote="128413809080000000" testing="0" />
+<file name="partly.gif" local="128286602780000000" remote="128413809080000000" testing="0" />
+<file name="pg_down.gif" local="128296919540000000" remote="128413809080000000" testing="0" />
+<file name="pg_first.gif" local="128296917000000000" remote="128413809090000000" testing="0" />
+<file name="pg_last.gif" local="128296918820000000" remote="128413809090000000" testing="0" />
+<file name="pg_next.gif" local="128296918060000000" remote="128413809100000000" testing="0" />
+<file name="pg_prev.gif" local="128296917260000000" remote="128413809100000000" testing="0" />
+<file name="pg_up.gif" local="128296920120000000" remote="128413809100000000" testing="0" />
+<file name="print.gif" local="128408544200000000" remote="128413809110000000" testing="0" />
+<file name="remove.gif" local="128390294960000000" remote="128413809110000000" testing="0" />
+<file name="rename.gif" local="128408558040000000" remote="128413809110000000" testing="0" />
+<file name="replied.gif" local="128297052960000000" remote="128413809120000000" testing="0" />
+<file name="replied_and_fwd.gif" local="128315874020000000" remote="128413809120000000" testing="0" />
+<file name="reply.gif" local="128408531760000000" remote="128413809130000000" testing="0" />
+<file name="replyall.gif" local="128408531880000000" remote="128413809130000000" testing="0" />
+<file name="return.gif" local="128348041200000000" remote="128413809130000000" testing="0" />
+<file name="rt.gif" local="128354170440000000" remote="128413809140000000" testing="0" />
+<file name="save.gif" local="128408602740000000" remote="128413809140000000" testing="0" />
+<file name="search.gif" local="128346326260000000" remote="128413809150000000" testing="0" />
+<file name="send.gif" local="128408579860000000" remote="128413809150000000" testing="0" />
+<file name="settings.gif" local="128322068820000000" remote="128413809160000000" testing="0" />
+<file name="sound.gif" local="128359185200000000" remote="128413809160000000" testing="0" />
+<file name="spam.gif" local="128408542660000000" remote="128413809160000000" testing="0" />
+<file name="spell.gif" local="128287375540000000" remote="128413809170000000" testing="0" />
+<file name="star.gif" local="128407651700000000" remote="128413809180000000" testing="0" />
+<file name="starred.gif" local="128408642720000000" remote="128413809180000000" testing="0" />
+<file name="sunny.gif" local="128286601840000000" remote="128413809180000000" testing="0" />
+<file name="trans.gif" local="128242883360000000" remote="128413809190000000" testing="0" />
+<file name="up.gif" local="128311446360000000" remote="128413809190000000" testing="0" />
+<file name="uw.gif" local="128268544420000000" remote="128413809190000000" testing="0" />
+<file name="uwlogo.gif" local="128300589020000000" remote="128413809200000000" testing="0" />
+<file name="wbar.gif" local="128285214500000000" remote="128413809200000000" testing="0" />
+<file name="msglist.gif" local="128408824100000000" remote="128413809060000000" testing="0" />
+<file name="spam2.gif" local="128408777680000000" remote="128413809170000000" testing="0" />
+</dwsync>
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/img/cbn/addcontact_sm.gif b/web/cgi/alpine/2.0/img/cbn/addcontact_sm.gif Binary files differnew file mode 100644 index 00000000..cda1baf5 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/addcontact_sm.gif diff --git a/web/cgi/alpine/2.0/img/cbn/addfolder.gif b/web/cgi/alpine/2.0/img/cbn/addfolder.gif Binary files differnew file mode 100644 index 00000000..81b5c230 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/addfolder.gif diff --git a/web/cgi/alpine/2.0/img/cbn/alert.gif b/web/cgi/alpine/2.0/img/cbn/alert.gif Binary files differnew file mode 100644 index 00000000..e5726c12 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/alert.gif diff --git a/web/cgi/alpine/2.0/img/cbn/alpinelogo.gif b/web/cgi/alpine/2.0/img/cbn/alpinelogo.gif Binary files differnew file mode 100644 index 00000000..bb68de83 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/alpinelogo.gif diff --git a/web/cgi/alpine/2.0/img/cbn/attach.gif b/web/cgi/alpine/2.0/img/cbn/attach.gif Binary files differnew file mode 100644 index 00000000..ea0829a2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/attach.gif diff --git a/web/cgi/alpine/2.0/img/cbn/attach_sm.gif b/web/cgi/alpine/2.0/img/cbn/attach_sm.gif Binary files differnew file mode 100644 index 00000000..cdf108cc --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/attach_sm.gif diff --git a/web/cgi/alpine/2.0/img/cbn/base.gif b/web/cgi/alpine/2.0/img/cbn/base.gif Binary files differnew file mode 100644 index 00000000..eb129763 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/base.gif diff --git a/web/cgi/alpine/2.0/img/cbn/blank.gif b/web/cgi/alpine/2.0/img/cbn/blank.gif Binary files differnew file mode 100644 index 00000000..e565824a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/blank.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-bl.gif b/web/cgi/alpine/2.0/img/cbn/border-bl.gif Binary files differnew file mode 100644 index 00000000..0e27a994 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-bl.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-br.gif b/web/cgi/alpine/2.0/img/cbn/border-br.gif Binary files differnew file mode 100644 index 00000000..494e4fdd --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-br.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-ft.gif b/web/cgi/alpine/2.0/img/cbn/border-ft.gif Binary files differnew file mode 100644 index 00000000..201d1be3 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-ft.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-lt-2.gif b/web/cgi/alpine/2.0/img/cbn/border-lt-2.gif Binary files differnew file mode 100644 index 00000000..445d1984 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-lt-2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-lt.gif b/web/cgi/alpine/2.0/img/cbn/border-lt.gif Binary files differnew file mode 100644 index 00000000..765c028e --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-lt.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-rt-2.gif b/web/cgi/alpine/2.0/img/cbn/border-rt-2.gif Binary files differnew file mode 100644 index 00000000..93d40267 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-rt-2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-rt.gif b/web/cgi/alpine/2.0/img/cbn/border-rt.gif Binary files differnew file mode 100644 index 00000000..dc2f5661 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-rt.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-tl.gif b/web/cgi/alpine/2.0/img/cbn/border-tl.gif Binary files differnew file mode 100644 index 00000000..64c223e9 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-tl.gif diff --git a/web/cgi/alpine/2.0/img/cbn/border-tr.gif b/web/cgi/alpine/2.0/img/cbn/border-tr.gif Binary files differnew file mode 100644 index 00000000..10ce91ed --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/border-tr.gif diff --git a/web/cgi/alpine/2.0/img/cbn/btnbg.gif b/web/cgi/alpine/2.0/img/cbn/btnbg.gif Binary files differnew file mode 100644 index 00000000..3cbf352a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/btnbg.gif diff --git a/web/cgi/alpine/2.0/img/cbn/btnhi.gif b/web/cgi/alpine/2.0/img/cbn/btnhi.gif Binary files differnew file mode 100644 index 00000000..ac407ae2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/btnhi.gif diff --git a/web/cgi/alpine/2.0/img/cbn/but_back.gif b/web/cgi/alpine/2.0/img/cbn/but_back.gif Binary files differnew file mode 100644 index 00000000..899f9832 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/but_back.gif diff --git a/web/cgi/alpine/2.0/img/cbn/ccme.gif b/web/cgi/alpine/2.0/img/cbn/ccme.gif Binary files differnew file mode 100644 index 00000000..3b6de47f --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/ccme.gif diff --git a/web/cgi/alpine/2.0/img/cbn/check2.gif b/web/cgi/alpine/2.0/img/cbn/check2.gif Binary files differnew file mode 100644 index 00000000..5f1149ae --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/check2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/checkmail.gif b/web/cgi/alpine/2.0/img/cbn/checkmail.gif Binary files differnew file mode 100644 index 00000000..41c37d5c --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/checkmail.gif diff --git a/web/cgi/alpine/2.0/img/cbn/close.gif b/web/cgi/alpine/2.0/img/cbn/close.gif Binary files differnew file mode 100644 index 00000000..69183a09 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/close.gif diff --git a/web/cgi/alpine/2.0/img/cbn/close2.gif b/web/cgi/alpine/2.0/img/cbn/close2.gif Binary files differnew file mode 100644 index 00000000..8ac7e070 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/close2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/close3.gif b/web/cgi/alpine/2.0/img/cbn/close3.gif Binary files differnew file mode 100644 index 00000000..b8d46aa4 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/close3.gif diff --git a/web/cgi/alpine/2.0/img/cbn/col.gif b/web/cgi/alpine/2.0/img/cbn/col.gif Binary files differnew file mode 100644 index 00000000..674de394 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/col.gif diff --git a/web/cgi/alpine/2.0/img/cbn/colsel.gif b/web/cgi/alpine/2.0/img/cbn/colsel.gif Binary files differnew file mode 100644 index 00000000..fab172f2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/colsel.gif diff --git a/web/cgi/alpine/2.0/img/cbn/compose.gif b/web/cgi/alpine/2.0/img/cbn/compose.gif Binary files differnew file mode 100644 index 00000000..97adb285 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/compose.gif diff --git a/web/cgi/alpine/2.0/img/cbn/contacts.gif b/web/cgi/alpine/2.0/img/cbn/contacts.gif Binary files differnew file mode 100644 index 00000000..3992f1d1 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/contacts.gif diff --git a/web/cgi/alpine/2.0/img/cbn/dawg.gif b/web/cgi/alpine/2.0/img/cbn/dawg.gif Binary files differnew file mode 100644 index 00000000..7d8fd606 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/dawg.gif diff --git a/web/cgi/alpine/2.0/img/cbn/dbar.gif b/web/cgi/alpine/2.0/img/cbn/dbar.gif Binary files differnew file mode 100644 index 00000000..95bcde54 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/dbar.gif diff --git a/web/cgi/alpine/2.0/img/cbn/delete.gif b/web/cgi/alpine/2.0/img/cbn/delete.gif Binary files differnew file mode 100644 index 00000000..2a160927 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/delete.gif diff --git a/web/cgi/alpine/2.0/img/cbn/detach.gif b/web/cgi/alpine/2.0/img/cbn/detach.gif Binary files differnew file mode 100644 index 00000000..939f8fb1 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/detach.gif diff --git a/web/cgi/alpine/2.0/img/cbn/div.gif b/web/cgi/alpine/2.0/img/cbn/div.gif Binary files differnew file mode 100644 index 00000000..51d339b5 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/div.gif diff --git a/web/cgi/alpine/2.0/img/cbn/div2.gif b/web/cgi/alpine/2.0/img/cbn/div2.gif Binary files differnew file mode 100644 index 00000000..c4982c4a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/div2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/dn.gif b/web/cgi/alpine/2.0/img/cbn/dn.gif Binary files differnew file mode 100644 index 00000000..0274736c --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/dn.gif diff --git a/web/cgi/alpine/2.0/img/cbn/edit.gif b/web/cgi/alpine/2.0/img/cbn/edit.gif Binary files differnew file mode 100644 index 00000000..d2ecc2ef --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/edit.gif diff --git a/web/cgi/alpine/2.0/img/cbn/exclaim.gif b/web/cgi/alpine/2.0/img/cbn/exclaim.gif Binary files differnew file mode 100644 index 00000000..e67522cd --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/exclaim.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_contacts.gif b/web/cgi/alpine/2.0/img/cbn/f_contacts.gif Binary files differnew file mode 100644 index 00000000..a85a8ea2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_contacts.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_delete.gif b/web/cgi/alpine/2.0/img/cbn/f_delete.gif Binary files differnew file mode 100644 index 00000000..9c0de43a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_delete.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_drafts.gif b/web/cgi/alpine/2.0/img/cbn/f_drafts.gif Binary files differnew file mode 100644 index 00000000..23a6219d --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_drafts.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_folder.gif b/web/cgi/alpine/2.0/img/cbn/f_folder.gif Binary files differnew file mode 100644 index 00000000..6e44b4e8 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_folder.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_inbox.gif b/web/cgi/alpine/2.0/img/cbn/f_inbox.gif Binary files differnew file mode 100644 index 00000000..609c6be7 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_inbox.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_manage.gif b/web/cgi/alpine/2.0/img/cbn/f_manage.gif Binary files differnew file mode 100644 index 00000000..b242c8a9 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_manage.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_minus.gif b/web/cgi/alpine/2.0/img/cbn/f_minus.gif Binary files differnew file mode 100644 index 00000000..7071aa5a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_minus.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_plus.gif b/web/cgi/alpine/2.0/img/cbn/f_plus.gif Binary files differnew file mode 100644 index 00000000..1d35602f --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_plus.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_search.gif b/web/cgi/alpine/2.0/img/cbn/f_search.gif Binary files differnew file mode 100644 index 00000000..6193a3b3 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_search.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_sent.gif b/web/cgi/alpine/2.0/img/cbn/f_sent.gif Binary files differnew file mode 100644 index 00000000..8812a3f3 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_sent.gif diff --git a/web/cgi/alpine/2.0/img/cbn/f_spam.gif b/web/cgi/alpine/2.0/img/cbn/f_spam.gif Binary files differnew file mode 100644 index 00000000..db33fe25 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/f_spam.gif diff --git a/web/cgi/alpine/2.0/img/cbn/fldsel.gif b/web/cgi/alpine/2.0/img/cbn/fldsel.gif Binary files differnew file mode 100644 index 00000000..2d0181b7 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/fldsel.gif diff --git a/web/cgi/alpine/2.0/img/cbn/folder.gif b/web/cgi/alpine/2.0/img/cbn/folder.gif Binary files differnew file mode 100644 index 00000000..eb129763 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/folder.gif diff --git a/web/cgi/alpine/2.0/img/cbn/folderopen.gif b/web/cgi/alpine/2.0/img/cbn/folderopen.gif Binary files differnew file mode 100644 index 00000000..c5c31102 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/folderopen.gif diff --git a/web/cgi/alpine/2.0/img/cbn/foldersopen.gif b/web/cgi/alpine/2.0/img/cbn/foldersopen.gif Binary files differnew file mode 100644 index 00000000..43ce5978 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/foldersopen.gif diff --git a/web/cgi/alpine/2.0/img/cbn/forward.gif b/web/cgi/alpine/2.0/img/cbn/forward.gif Binary files differnew file mode 100644 index 00000000..aa513040 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/forward.gif diff --git a/web/cgi/alpine/2.0/img/cbn/fwd.gif b/web/cgi/alpine/2.0/img/cbn/fwd.gif Binary files differnew file mode 100644 index 00000000..546ff6a3 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/fwd.gif diff --git a/web/cgi/alpine/2.0/img/cbn/group_contact.gif b/web/cgi/alpine/2.0/img/cbn/group_contact.gif Binary files differnew file mode 100644 index 00000000..fe47f2b9 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/group_contact.gif diff --git a/web/cgi/alpine/2.0/img/cbn/help.gif b/web/cgi/alpine/2.0/img/cbn/help.gif Binary files differnew file mode 100644 index 00000000..8eea6cbe --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/help.gif diff --git a/web/cgi/alpine/2.0/img/cbn/help_sm.gif b/web/cgi/alpine/2.0/img/cbn/help_sm.gif Binary files differnew file mode 100644 index 00000000..97c369c7 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/help_sm.gif diff --git a/web/cgi/alpine/2.0/img/cbn/high.gif b/web/cgi/alpine/2.0/img/cbn/high.gif Binary files differnew file mode 100644 index 00000000..a4d52bf4 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/high.gif diff --git a/web/cgi/alpine/2.0/img/cbn/highest.gif b/web/cgi/alpine/2.0/img/cbn/highest.gif Binary files differnew file mode 100644 index 00000000..79df8035 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/highest.gif diff --git a/web/cgi/alpine/2.0/img/cbn/inbox.gif b/web/cgi/alpine/2.0/img/cbn/inbox.gif Binary files differnew file mode 100644 index 00000000..dcf5e684 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/inbox.gif diff --git a/web/cgi/alpine/2.0/img/cbn/info.gif b/web/cgi/alpine/2.0/img/cbn/info.gif Binary files differnew file mode 100644 index 00000000..9fdf8503 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/info.gif diff --git a/web/cgi/alpine/2.0/img/cbn/infomsg.gif b/web/cgi/alpine/2.0/img/cbn/infomsg.gif Binary files differnew file mode 100644 index 00000000..5fa3d9ca --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/infomsg.gif diff --git a/web/cgi/alpine/2.0/img/cbn/lo.gif b/web/cgi/alpine/2.0/img/cbn/lo.gif Binary files differnew file mode 100644 index 00000000..817eaeb2 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/lo.gif diff --git a/web/cgi/alpine/2.0/img/cbn/logo.gif b/web/cgi/alpine/2.0/img/cbn/logo.gif Binary files differnew file mode 100644 index 00000000..ea072725 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/logo.gif diff --git a/web/cgi/alpine/2.0/img/cbn/logo.png b/web/cgi/alpine/2.0/img/cbn/logo.png Binary files differnew file mode 100644 index 00000000..e2ba8952 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/logo.png diff --git a/web/cgi/alpine/2.0/img/cbn/logoff.gif b/web/cgi/alpine/2.0/img/cbn/logoff.gif Binary files differnew file mode 100644 index 00000000..cf1fba05 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/logoff.gif diff --git a/web/cgi/alpine/2.0/img/cbn/lookup.gif b/web/cgi/alpine/2.0/img/cbn/lookup.gif Binary files differnew file mode 100644 index 00000000..a9ab6dcb --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/lookup.gif diff --git a/web/cgi/alpine/2.0/img/cbn/low.gif b/web/cgi/alpine/2.0/img/cbn/low.gif Binary files differnew file mode 100644 index 00000000..f2924496 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/low.gif diff --git a/web/cgi/alpine/2.0/img/cbn/menu.gif b/web/cgi/alpine/2.0/img/cbn/menu.gif Binary files differnew file mode 100644 index 00000000..f763c448 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/menu.gif diff --git a/web/cgi/alpine/2.0/img/cbn/msglist.gif b/web/cgi/alpine/2.0/img/cbn/msglist.gif Binary files differnew file mode 100644 index 00000000..ad7c9b47 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/msglist.gif diff --git a/web/cgi/alpine/2.0/img/cbn/msglist.gif.bak b/web/cgi/alpine/2.0/img/cbn/msglist.gif.bak Binary files differnew file mode 100644 index 00000000..ed77a81f --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/msglist.gif.bak diff --git a/web/cgi/alpine/2.0/img/cbn/musicfolder.gif b/web/cgi/alpine/2.0/img/cbn/musicfolder.gif Binary files differnew file mode 100644 index 00000000..f620789f --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/musicfolder.gif diff --git a/web/cgi/alpine/2.0/img/cbn/navbg.gif b/web/cgi/alpine/2.0/img/cbn/navbg.gif Binary files differnew file mode 100644 index 00000000..3cbf352a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/navbg.gif diff --git a/web/cgi/alpine/2.0/img/cbn/new.gif b/web/cgi/alpine/2.0/img/cbn/new.gif Binary files differnew file mode 100644 index 00000000..abc16be0 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/new.gif diff --git a/web/cgi/alpine/2.0/img/cbn/page.gif b/web/cgi/alpine/2.0/img/cbn/page.gif Binary files differnew file mode 100644 index 00000000..42d7318c --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/page.gif diff --git a/web/cgi/alpine/2.0/img/cbn/parent.gif b/web/cgi/alpine/2.0/img/cbn/parent.gif Binary files differnew file mode 100644 index 00000000..48e54a65 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/parent.gif diff --git a/web/cgi/alpine/2.0/img/cbn/partly.gif b/web/cgi/alpine/2.0/img/cbn/partly.gif Binary files differnew file mode 100644 index 00000000..858c6dca --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/partly.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_down.gif b/web/cgi/alpine/2.0/img/cbn/pg_down.gif Binary files differnew file mode 100644 index 00000000..9fba9e1b --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_down.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_first.gif b/web/cgi/alpine/2.0/img/cbn/pg_first.gif Binary files differnew file mode 100644 index 00000000..fdd4784c --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_first.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_last.gif b/web/cgi/alpine/2.0/img/cbn/pg_last.gif Binary files differnew file mode 100644 index 00000000..10f45d49 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_last.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_next.gif b/web/cgi/alpine/2.0/img/cbn/pg_next.gif Binary files differnew file mode 100644 index 00000000..15a3b5fd --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_next.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_prev.gif b/web/cgi/alpine/2.0/img/cbn/pg_prev.gif Binary files differnew file mode 100644 index 00000000..7db4db96 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_prev.gif diff --git a/web/cgi/alpine/2.0/img/cbn/pg_up.gif b/web/cgi/alpine/2.0/img/cbn/pg_up.gif Binary files differnew file mode 100644 index 00000000..e9f48410 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/pg_up.gif diff --git a/web/cgi/alpine/2.0/img/cbn/print.gif b/web/cgi/alpine/2.0/img/cbn/print.gif Binary files differnew file mode 100644 index 00000000..69f75b53 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/print.gif diff --git a/web/cgi/alpine/2.0/img/cbn/question.gif b/web/cgi/alpine/2.0/img/cbn/question.gif Binary files differnew file mode 100644 index 00000000..90d5be3e --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/question.gif diff --git a/web/cgi/alpine/2.0/img/cbn/question.jpg b/web/cgi/alpine/2.0/img/cbn/question.jpg Binary files differnew file mode 100644 index 00000000..a62edb48 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/question.jpg diff --git a/web/cgi/alpine/2.0/img/cbn/question.png b/web/cgi/alpine/2.0/img/cbn/question.png Binary files differnew file mode 100644 index 00000000..82f3c144 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/question.png diff --git a/web/cgi/alpine/2.0/img/cbn/question2.jpg b/web/cgi/alpine/2.0/img/cbn/question2.jpg Binary files differnew file mode 100644 index 00000000..0a36fe45 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/question2.jpg diff --git a/web/cgi/alpine/2.0/img/cbn/remove.gif b/web/cgi/alpine/2.0/img/cbn/remove.gif Binary files differnew file mode 100644 index 00000000..fb1a338a --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/remove.gif diff --git a/web/cgi/alpine/2.0/img/cbn/rename.gif b/web/cgi/alpine/2.0/img/cbn/rename.gif Binary files differnew file mode 100644 index 00000000..3cedb691 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/rename.gif diff --git a/web/cgi/alpine/2.0/img/cbn/replied.gif b/web/cgi/alpine/2.0/img/cbn/replied.gif Binary files differnew file mode 100644 index 00000000..8ff06835 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/replied.gif diff --git a/web/cgi/alpine/2.0/img/cbn/replied_and_fwd.gif b/web/cgi/alpine/2.0/img/cbn/replied_and_fwd.gif Binary files differnew file mode 100644 index 00000000..b3dd5a1b --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/replied_and_fwd.gif diff --git a/web/cgi/alpine/2.0/img/cbn/reply.gif b/web/cgi/alpine/2.0/img/cbn/reply.gif Binary files differnew file mode 100644 index 00000000..c51ca60b --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/reply.gif diff --git a/web/cgi/alpine/2.0/img/cbn/replyall.gif b/web/cgi/alpine/2.0/img/cbn/replyall.gif Binary files differnew file mode 100644 index 00000000..88d840ec --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/replyall.gif diff --git a/web/cgi/alpine/2.0/img/cbn/return.gif b/web/cgi/alpine/2.0/img/cbn/return.gif Binary files differnew file mode 100644 index 00000000..0c04ee77 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/return.gif diff --git a/web/cgi/alpine/2.0/img/cbn/rt.gif b/web/cgi/alpine/2.0/img/cbn/rt.gif Binary files differnew file mode 100644 index 00000000..bff6423d --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/rt.gif diff --git a/web/cgi/alpine/2.0/img/cbn/save.gif b/web/cgi/alpine/2.0/img/cbn/save.gif Binary files differnew file mode 100644 index 00000000..5f3ef2c7 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/save.gif diff --git a/web/cgi/alpine/2.0/img/cbn/search.gif b/web/cgi/alpine/2.0/img/cbn/search.gif Binary files differnew file mode 100644 index 00000000..1bef6fac --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/search.gif diff --git a/web/cgi/alpine/2.0/img/cbn/send.gif b/web/cgi/alpine/2.0/img/cbn/send.gif Binary files differnew file mode 100644 index 00000000..2c140bdf --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/send.gif diff --git a/web/cgi/alpine/2.0/img/cbn/settings.gif b/web/cgi/alpine/2.0/img/cbn/settings.gif Binary files differnew file mode 100644 index 00000000..9889b4fd --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/settings.gif diff --git a/web/cgi/alpine/2.0/img/cbn/sound.gif b/web/cgi/alpine/2.0/img/cbn/sound.gif Binary files differnew file mode 100644 index 00000000..b9bd62aa --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/sound.gif diff --git a/web/cgi/alpine/2.0/img/cbn/spam.gif b/web/cgi/alpine/2.0/img/cbn/spam.gif Binary files differnew file mode 100644 index 00000000..6bef9cea --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/spam.gif diff --git a/web/cgi/alpine/2.0/img/cbn/spam2.gif b/web/cgi/alpine/2.0/img/cbn/spam2.gif Binary files differnew file mode 100644 index 00000000..569183a1 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/spam2.gif diff --git a/web/cgi/alpine/2.0/img/cbn/spell.gif b/web/cgi/alpine/2.0/img/cbn/spell.gif Binary files differnew file mode 100644 index 00000000..79e7a1d3 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/spell.gif diff --git a/web/cgi/alpine/2.0/img/cbn/spritelib.gif b/web/cgi/alpine/2.0/img/cbn/spritelib.gif Binary files differnew file mode 100644 index 00000000..56be9494 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/spritelib.gif diff --git a/web/cgi/alpine/2.0/img/cbn/spritelib.png b/web/cgi/alpine/2.0/img/cbn/spritelib.png Binary files differnew file mode 100644 index 00000000..4b067efd --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/spritelib.png diff --git a/web/cgi/alpine/2.0/img/cbn/star.gif b/web/cgi/alpine/2.0/img/cbn/star.gif Binary files differnew file mode 100644 index 00000000..5a89f298 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/star.gif diff --git a/web/cgi/alpine/2.0/img/cbn/starred.gif b/web/cgi/alpine/2.0/img/cbn/starred.gif Binary files differnew file mode 100644 index 00000000..c2622b01 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/starred.gif diff --git a/web/cgi/alpine/2.0/img/cbn/statbak.gif b/web/cgi/alpine/2.0/img/cbn/statbak.gif Binary files differnew file mode 100644 index 00000000..a10a496f --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/statbak.gif diff --git a/web/cgi/alpine/2.0/img/cbn/statbakend.gif b/web/cgi/alpine/2.0/img/cbn/statbakend.gif Binary files differnew file mode 100644 index 00000000..577c4ad8 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/statbakend.gif diff --git a/web/cgi/alpine/2.0/img/cbn/statbakl.gif b/web/cgi/alpine/2.0/img/cbn/statbakl.gif Binary files differnew file mode 100644 index 00000000..4a95ed64 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/statbakl.gif diff --git a/web/cgi/alpine/2.0/img/cbn/statbakr.gif b/web/cgi/alpine/2.0/img/cbn/statbakr.gif Binary files differnew file mode 100644 index 00000000..595f6177 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/statbakr.gif diff --git a/web/cgi/alpine/2.0/img/cbn/sunny.gif b/web/cgi/alpine/2.0/img/cbn/sunny.gif Binary files differnew file mode 100644 index 00000000..285e7826 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/sunny.gif diff --git a/web/cgi/alpine/2.0/img/cbn/tome.gif b/web/cgi/alpine/2.0/img/cbn/tome.gif Binary files differnew file mode 100644 index 00000000..11472f78 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/tome.gif diff --git a/web/cgi/alpine/2.0/img/cbn/trans.gif b/web/cgi/alpine/2.0/img/cbn/trans.gif Binary files differnew file mode 100644 index 00000000..93b42998 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/trans.gif diff --git a/web/cgi/alpine/2.0/img/cbn/up.gif b/web/cgi/alpine/2.0/img/cbn/up.gif Binary files differnew file mode 100644 index 00000000..0d3f5df5 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/up.gif diff --git a/web/cgi/alpine/2.0/img/cbn/uw.gif b/web/cgi/alpine/2.0/img/cbn/uw.gif Binary files differnew file mode 100644 index 00000000..a3834ce8 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/uw.gif diff --git a/web/cgi/alpine/2.0/img/cbn/uwlogo.gif b/web/cgi/alpine/2.0/img/cbn/uwlogo.gif Binary files differnew file mode 100644 index 00000000..2f636710 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/uwlogo.gif diff --git a/web/cgi/alpine/2.0/img/cbn/wbar.gif b/web/cgi/alpine/2.0/img/cbn/wbar.gif Binary files differnew file mode 100644 index 00000000..73885025 --- /dev/null +++ b/web/cgi/alpine/2.0/img/cbn/wbar.gif diff --git a/web/cgi/alpine/2.0/lib/INSTALL b/web/cgi/alpine/2.0/lib/INSTALL new file mode 100644 index 00000000..1c8f3bdf --- /dev/null +++ b/web/cgi/alpine/2.0/lib/INSTALL @@ -0,0 +1,3 @@ + +Before running, the Yahoo U/I Library has to be installed +so the "yui" link will work. diff --git a/web/cgi/alpine/2.0/lib/common.js b/web/cgi/alpine/2.0/lib/common.js new file mode 100644 index 00000000..89587f3a --- /dev/null +++ b/web/cgi/alpine/2.0/lib/common.js @@ -0,0 +1,1586 @@ +/* $Id: common.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +// Globals +YAHOO.namespace('alpine'); +YAHOO.alpine.current = { c:0, f:null, u:0 }; +YAHOO.alpine.mailcheck = { interval:null, timer:null }; +YAHOO.alpine.status = { timeout:null, message:[] }; +YAHOO.alpine.panel = { count: 0, width: 0 }; +YAHOO.alpine.containers = {}; + + +// INIT +function browserDetect() { + if (YAHOO.env.ua.webkit > 0) { + document.write("<style type='text/css'> body {font-family:Helvetica,Tahoma,Sans Serif;} td,th {font-size:.75em;} </style>"); + } +} + +// GENERAL + +function clearTextField(txt, promptText) { + if (txt.value == promptText) { + txt.value = ""; + } +} + +function recallTextField(txt, promptText) { + if (txt.value == "") { + txt.value = promptText; + } +} + +function showDisplayDiv(id) { + YAHOO.util.Dom.setStyle(id,'display','block'); +} + +function hideDisplayDivOrSpan(id) { + YAHOO.util.Dom.setStyle(id,'display','none'); +} + +function showDisplaySpan(id) { + YAHOO.util.Dom.setStyle(id,'display','inline'); +} + +function showLoading(){ + var bp = document.getElementById("bePatient"); + if(bp){ + bp.style.top = "auto"; + bp.style.left = "auto"; + } +} + +function hideLoading(){ + var bp = document.getElementById("bePatient"); + if(bp){ + bp.style.top = "-999px"; + bp.style.left = "-999px"; + } +} + +// MENU +function menuSwap() { + this.className = "sfhover"; +} + +function menuBack() { + this.className = "menuHdr"; +} + +function menuFocus() { + this.parentNode.parentNode.parentNode.className = "sfhover"; +} + +function menuBlur() { + this.parentNode.parentNode.parentNode.className = "menuHdr"; +} + +function initMenus() { + if (document.getElementById) { + var LI = document.getElementsByTagName("li"); + var zLI = LI.length; + for (var i = 0; i < zLI; i++) { + if (LI[i].parentNode.parentNode.className == "menuHdr") { + if (LI[i].firstChild.href) { + LI[i].firstChild.onfocus = menuFocus; + LI[i].firstChild.onblur = menuBlur; + } + } + if (LI[i].className == "menuHdr") { + LI[i].onmouseover = menuSwap; + LI[i].onmouseout = menuBack; + } + } + } +} + +function updateElementHtml(id,html){ + var el = document.getElementById(id); + if(el){ + el.innerHTML = html; + return true; + } + + return false; +} + +function updateElementHref(id,href){ + var el = document.getElementById(id); + if(el) el.href = href; +} + +function updateElementValue(id,value){ + var el = document.getElementById(id); + if(el) el.value = value; +} + +function quoteHtml(s){ + return s.replace(/</g, '<').replace(/>/g, '>'); +} + +// SETTINGS + +function showAdvancedSettings() { + hideDisplayDivOrSpan('normalSettings'); + showDisplayDiv('advancedSettings'); + return false; +} + +function showNormalSettings() { + hideDisplayDivOrSpan('advancedSettings'); + showDisplayDiv('normalSettings'); + return false; +} + +// COMPOSE + +function showMoreComposeHeaders() { + hideDisplayDivOrSpan('moreComposeHeaderText'); + showDisplaySpan('lessComposeHeaderText'); + showDisplayDiv('moreComposeHeaders'); + return false; +} + +function showLessComposeHeaders() { + hideDisplayDivOrSpan('lessComposeHeaderText'); + showDisplaySpan('moreComposeHeaderText'); + hideDisplayDivOrSpan('moreComposeHeaders'); + return false; +} + +// URI encode folder + +function encodeURIFolderPath(path) { + return encodeURIComponent(path).replace(/%2F/g,'/'); +} + +// HELP +function openMailboxHelp(){ + var d = YAHOO.util.Dom.getStyle('listTopMenubar','display'); + if(d && d == 'none') openHelpWindow('read.html'); + else openHelpWindow('inbox.html'); + return(false); +} + +function openHelpWindow(url) { + var top = 30; + var left = Math.floor(screen.availWidth * 0.66) - 10; + var width = Math.min(Math.floor(screen.availWidth * 0.33), 400); + var height = Math.floor(screen.availHeight * 0.8) - 30; + var win = window.open(document.getElementsByTagName('base')[0].href + "help/" + url, "helpwindow", "top=" + top + ",left=" + left + ",width=" + width + ",height=" + height + ",resizable=yes,scrollbars=yes,statusbar=no"); + win.focus(); +} + +// NEW MAIL CHECK FUNCTIONS +function setCheckMailFunction(elem,f){ + var event = YAHOO.util.Event; + event.removeListener(elem,'click'); + event.addListener(elem, 'click', function(e,o){ o.f(); }, { f:f }); +} + +function setNewMailCheckInterval(interval,onNewMail){ + YAHOO.alpine.mailcheck.interval = interval; + startNewMailTimer(onNewMail); +} + +function startNewMailTimer(onNewMail){ + stopNewMailTimer(); + var nmc = "newMailCheck(1,'"+onNewMail+"')"; + YAHOO.alpine.mailcheck.timer = window.setTimeout(nmc, YAHOO.alpine.mailcheck.interval * 1000); +} + +function stopNewMailTimer(){ + if(YAHOO.alpine.mailcheck.timer){ + window.clearTimeout(YAHOO.alpine.mailcheck.timer); + YAHOO.alpine.mailcheck.timer = null; + } +} + +function newMailCheck(r,onNewMail){ + stopNewMailTimer(); + if(!r) r = 0; + YAHOO.util.Connect.asyncRequest('GET', + 'conduit/newmail.tcl' + encodeURI('?reload=' + r) + urlSalt('&'), + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){ + eval('var objNM = '+o.responseText); + if(objNM.error){ + addStatusMessage('Mail Check Error: ' + objNM.error,2); + } + else if(objNM.length > 0){ + for(var i = 0; i < objNM.length; i++) + addStatusMessage(objNM[i].verbiage,10); + + if(onNewMail && onNewMail.length) eval(onNewMail); + } + else if(!r) + addStatusMessage('No new mail has arrived',2); + + displayStatusMessages(); + }, + failure: function(o){ + addStatusMessage('newMailCheck Failure: '+o.statusText,15); + displayStatusMessages(); + } + }); + + startNewMailTimer(onNewMail); + return false; +} + +// STATUS MESSAGES + +function showStatusMessage(smText,smTimeout){ + if(updateElementHtml('statusMessageText', smText)){ + var dom = YAHOO.util.Dom; + dom.setStyle('statusMessage','display','block'); + dom.setStyle('weatherBar','display','none'); + + clearStatusMessageTimeout(); + // number arg to setTimeout is how long status messages are displayed + YAHOO.alpine.status.timeout = window.setTimeout('flipStatusMessages(hideStatusMessageOnInput)', ((smTimeout > 0) ? smTimeout : 10) * 1000); + } +} + +function clearStatusMessageLine(){ + var dom = YAHOO.util.Dom; + dom.setStyle('statusMessage','display','none'); + dom.setStyle('weatherBar','display','block'); +} + +function actuallyHideStatusMessage(){ + var event = YAHOO.util.Event; + event.removeListener(window,'click'); + event.removeListener(window,'keydown'); + clearStatusMessageLine(); +} + +function hideStatusMessageOnInput(){ + var event = YAHOO.util.Event; + event.addListener(window,'keydown',actuallyHideStatusMessage); + event.addListener(window,'click',actuallyHideStatusMessage); +} + +function flipStatusMessages(fn){ + clearStatusMessageTimeout(); + // nothing else to display, then restore original content + if(!displayStatusMessages()) fn(); +} + +function hideStatusMessage(){ + flipStatusMessages(clearStatusMessageLine); +} + +function clearStatusMessageTimeout(){ + var t = YAHOO.alpine.status.timeout; + if(t){ + window.clearTimeout(t); + t = null; + } +} + +function displayStatusMessages(){ + var smq = YAHOO.alpine.status.message; + if(smq.length){ + var statusMessage = smq[0]; + smq.splice(0,1); + showStatusMessage(statusMessage.text,statusMessage.timeout); + return true; + } + + return false; +} + +function addStatusMessage(smText,smTimeout){ + if(smText){ + var smEntry = {}; + var smq = YAHOO.alpine.status.message; + if(typeof smText == 'object') smEntry.text = smText.html; + else smEntry.text = smText.replace(/</g,'<'); + if(smTimeout) smEntry.timeout = smTimeout; + smq[smq.length] = smEntry; + } +} + +// LIST SELECTION +function markAll(o,listId,mark) { + var chk = document.getElementsByName(listId); + var isChecked = o.checked; + if (chk) { + if (isNaN(chk.length)) { + chk.checked = isChecked; + mark(chk); + } + else { + for(var i = 0; i < chk.length; i++) { + chk[i].checked = isChecked; + mark(chk[i]); + } + } + } +} + +function markOne(o) { + var elTR = o.parentNode.parentNode; + if(elTR.tagName == 'TR'){ + var dom = YAHOO.util.Dom; + if(o.checked){ + if(!dom.hasClass(elTR, 'choice')) dom.addClass(elTR, 'choice'); + } + else{ + if(dom.hasClass(elTR, 'choice')) dom.removeClass(elTR, 'choice'); + } + } +} + +// SCRIPT EVAL +function evalScripts(htmlText){ + var reScript = '<script[^>]*>([\\S\\s]*?)<\/script>'; + var scriptOuter = new RegExp(reScript,'img'); + var scriptInner = new RegExp(reScript,'im'); + var scripts = htmlText.match(scriptOuter); + if(scripts) + for(var si = 0; si < scripts.length; si++){ + var script = scripts[si].match(scriptInner); + if(script) eval(script[1]); + } +} + +// MAINTAIN UNREAD COUNT +function incUnreadCount(fl,n){ + var unreadObj = document.getElementById('unread' + fl); + if(unreadObj){ + var unreadMatch = unreadObj.innerHTML.match(/ \((\d+)\)/m); + if(unreadMatch && unreadMatch[1]){ + var unreadCount = unreadMatch[1]; + while(n-- > 0) unreadCount++; + if(unreadCount > 0) unreadObj.innerHTML = ' (' + unreadCount + ')'; + else unreadObj.innerHTML = ''; + } + else if(n > 0){ + unreadObj.innerHTML = ' (' + n + ')'; + } + } +} + +function decUnreadCount(fl,n){ + var unreadObj = document.getElementById('unread' + fl); + if(unreadObj){ + var unreadMatch = unreadObj.innerHTML.match(/ \((\d+)\)/m); + if(unreadMatch && unreadMatch[1]){ + var unreadCount = unreadMatch[1]; + while(n-- > 0 && unreadCount > 0) unreadCount--; + if(unreadCount > 0) unreadObj.innerHTML = ' (' + unreadCount + ')'; + else unreadObj.innerHTML = ''; + } + } +} + +function urlSalt(conjunction){ + var now = new Date(); + return conjunction + 'salt=' + now.getTime(); +} + +// EMPTY TRASH +function emptyFolder(c,f,u,oDone) { + var eUrl = 'conduit/empty.tcl?c=' + encodeURIComponent(c) + '&f=' + encodeURIFolderPath(f); + if(u) eUrl += '&u=' + encodeURIComponent(u); + YAHOO.util.Connect.asyncRequest('GET', + eUrl + urlSalt('&'), + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o) { + // valid response is "<numApplied> <numSelected> <numTotalMsgs>" + var matchResult; + if((matchResult = o.responseText.match(/^(\d+)$/m)) == null){ + showStatusMessage('Error: ' + o.responseText, 10); + } + else if(oDone){ + if(oDone.status){ + showStatusMessage(matchResult[1] + ' messages from ' + f + ' deleted forever', 3); + YAHOO.alpine.current.count -= matchResult[1]; + if(u == 'selected' && matchResult[1] > 0){ + YAHOO.alpine.current.selected -= matchResult[1]; + hideSelectAllInfo(); + } + } + if(oDone.fn) eval(oDone.fn); + } + }, + failure: function(o) { showStatusMessage('Request Failure: ' + o.statusText + '. Please report this.', 10)} + }); + return false; +} + +// ALERTS AND DIALOGS +function newPanel(width){ + var dom = YAHOO.util.Dom; + YAHOO.alpine.panel.count++; + var panelId = 'panel' + YAHOO.alpine.panel.count; + var panel = new YAHOO.widget.Panel(panelId, + { + //fixedcenter: true, + xy:[210,120], + underlay: 'none', + width:width, + visible: false, + modal:true, + dragOnly:true, + close: true, + constraintoviewport: true + }); + + // common footer + var pFoot = document.createDocumentFragment(); + var div = document.createElement('div'); + dom.addClass(div,'bl'); + pFoot.appendChild(div); + div = document.createElement('div'); + dom.addClass(div,'br'); + pFoot.appendChild(div); + panel.setFooter(pFoot); + return(panel); +} + +function closePanel(panel){ + YAHOO.alpine.panel.button = null; + if(YAHOO.alpine.panel.keylistener){ + YAHOO.alpine.panel.keylistener.disable(); + YAHOO.alpine.panel.keylistener = null; + } + + panel.hide(); + panel.destroy(); +} + +function panelHeader(content){ + var dom = YAHOO.util.Dom; + var pHead = document.createDocumentFragment(); + + var el = document.createElement('div'); + dom.addClass(el,'tl'); + pHead.appendChild(el); + + el = document.createElement('span'); + el.innerHTML = content; + pHead.appendChild(el); + + el = document.createElement('div'); + dom.addClass(el,'tr'); + pHead.appendChild(el); + + return pHead; +} + +function panelBody(kind,content,buttons){ + var frag, div; + var dom = YAHOO.util.Dom; + + var frag = document.createDocumentFragment(); + + div = document.createElement('div'); + dom.addClass(div,'dialogIcon'); + dom.addClass(div,kind); + frag.appendChild(div); + + div = document.createElement('div'); + div.setAttribute('id',kind+'Body'); + dom.addClass(div,'dialogBody'); + if(content.html) div.innerHTML = content.html; + else if(content.frag) div.appendChild(content.frag); + + frag.appendChild(div); + + div = document.createElement('div'); + dom.addClass(div,'yui-skin-sam'); + dom.addClass(div,'dialogButtons'); + frag.appendChild(div); + if(buttons){ + for(var n = 0; n < buttons.length; n++){ + var butCont = document.createElement('span'); + butCont.setAttribute('id','pb' + (n + 1)); + dom.addClass(butCont,'yuibutton'); + div.appendChild(butCont); + var oButAtt = buttons[n]; + oButAtt.container = butCont.id; + var b = new YAHOO.widget.Button(oButAtt); + if(oButAtt.disabled){ + YAHOO.alpine.panel.button = b; + YAHOO.alpine.panel.keylistener = oButAtt.keylistener; + } + } + } + + return frag; +} + +function panelAlert(s,f){ + var buttons = [{ id:'butClose',type:'button',label:'OK',onclick:{ fn: function(){ closePanel(panel); }}}]; + var panel = newPanel('26em'); + panel.setHeader(panelHeader('Alert!')); + if(f) buttons[0].onclick = function(){ f(); closePanel(panel); }; + panel.setBody(panelBody('alert',{html:s},buttons)); + panel.render(document.body); + getPanelBodyWidth('alert'); + panel.show(); + return false; +} + +function panelConfirm(s,oYes,oNo){ + var buttons = [{id:'butYes',type:'button',label:'OK'},{id:'butClose',label:'Cancel',onclick:{ fn:function(){ closePanel(panel); }}}]; + var panel = newPanel('30em'); + panel.setHeader(panelHeader('Confirm')); + if(oYes){ + if(oYes.text) buttons[0].label = oYes.text; + if(oYes.url){ + buttons[0].type = 'link'; + buttons[0].href = oYes.url; + } + else if(oYes.fn){ + buttons[0].type = 'button'; + buttons[0].onclick = { fn: function() { oYes.fn(oYes.args) ; closePanel(panel); }}; + } + } + + if(oNo){ + if(oNo.text) buttons[1].label = oNo.text; + if(oNo.fn) buttons[1].onclick = { fn: function(){ closePanel(panel); oNo.fn(); }}; + } + + panel.setBody(panelBody('prompt',{html:s},buttons)); + panel.render(document.body); + panel.show(); + getPanelBodyWidth('prompt'); + return false; +} + +function panelDialog(title,body,done,onClose){ + var buttons = []; + var panel = newPanel('640px'); + panel.setHeader(panelHeader(title)); + if(done && done.fn){ + var i = buttons.length; + buttons[i] = { + type:'button', + id:done.label.replace(/ /g,'_').toLowerCase(), + label:done.label, + disabled:done.disabled, + onclick:{ + fn: function(){ + done.fn(); + closePanel(panel); + } + } + }; + + if(done.doonreturn){ + buttons[i].keylistener = new YAHOO.util.KeyListener(document, { keys:13 }, + { + fn:function() { done.fn(); closePanel(panel) }, + scope:panel, + correctScope: true + }); + + if(!done.disabled) panel.cfg.queueProperty("keylisteners", buttons[i].keylistener); + } + + if(done.buttonId) buttons[i].id = done.butId; + } + + buttons[buttons.length] = { + id:'butClose', + type:'button', + label:'Cancel', + onclick:{ fn: function(){ if(onClose) onClose(); closePanel(panel); } } + }; + + panel.setBody(panelBody('dialog',{frag:body},buttons)); + panel.render(document.body); + panel.show(); + getPanelBodyWidth('dialog'); + return false; +} + +function drawFolderList(idContainer,defCollection){ + if(idContainer && idContainer.length){ + var el = document.getElementById(idContainer); + if(el){ + newFolderList(el,null,defCollection); + YAHOO.alpine.containers.folderlist = el; + } + } +} + +function newFolderList(elContainer,controlObj,collection,path,objParm){ + var alp = YAHOO.alpine; + alp.resubmitRequest = function(){ newFolderList(elContainer,controlObj,collection,path,objParm); }; + alp.cancelRequest = function(){ newFolderList(elContainer,controlObj,alp.current.c,"",objParm); }; + if(elContainer){ + var nUrl = 'conduit/folderlist.tcl/' + collection + '/'; + if(path && path.length) nUrl += encodeURIFolderPath(path) + '/'; + var conj = '?'; + var prop, parms = ''; + if(objParm){ + for(prop in objParm){ + parms += conj + prop + '=' + encodeURIComponent(objParm[prop]); + conj = '&'; + } + } + YAHOO.util.Connect.asyncRequest('GET', + nUrl + parms + urlSalt(conj), + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){ + elContainer.innerHTML = o.responseText; + evalScripts(o.responseText); + window.scrollTo(0,0); + }, + failure: function(o) { showStatusMessage('Error getting list: '+o.statusText,10); }, + argument: [elContainer] + }); + if(controlObj) controlObj.blur(); + } + + return false; +} + +function processAuthException(o){ + switch(o.code){ + case 'CERTQUERY' : + panelConfirm('The SSL/TLS certificate for the server<p><center>' + o.server + '</center><br>cannot be validated.<p>The problem is: ' + o.reason, + {text:'Accept Certificate',fn:acceptCert,args:{server:o.server}},{fn:YAHOO.alpine.cancelRequest}); + break; + case 'CERTFAIL' : + panelAlert('The security certificate on server ' + o.server +' is not acceptable<p>The problem is: ' + o.reason); + break; + case 'NOPASSWD' : + getCredentials(o); + break; + case 'BADPASSWD' : + getCredentials(o); + break; + default : + addStatusMessage('Unknown Authorization Code: ' + o.code, 15); + displayStatusMessages(); + break; + } +} + +function acceptCert(o){ + YAHOO.util.Connect.asyncRequest('GET', + 'conduit/cert.tcl?server=' + encodeURIComponent(o.server) + '&accept=yes' + urlSalt('&'), + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){ if(YAHOO.alpine.resubmitRequest) YAHOO.alpine.resubmitRequest(); }, + failure: function(o){ + addStatusMessage('Certificate Acceptance Failure: '+o.statusText,15); + displayStatusMessages(); + } + }); +} + +function getCredentials(o){ + var dom = YAHOO.util.Dom; + var alp = YAHOO.alpine; + + var div = document.createElement('div'); + dom.addClass(div,'getAuth'); + + var d = document.createElement('div'); + var tail = (o.server) ? ' to '+ o.server + '.' : '...'; + var e = document.createTextNode('Authorization is required to ' + o.reason + '. Please login'+tail); + d.appendChild(e); + div.appendChild(d); + + e = document.createElement('span'); + e.innerHTML = 'Username:'; + div.appendChild(e); + var u = createInputElement('text','u'); + div.appendChild(u); + + e = document.createElement('hr'); + div.appendChild(e); + + e = document.createElement('span'); + e.innerHTML = 'Password:'; + div.appendChild(e); + var p = createInputElement('password','p'); + div.appendChild(p); + + hideLoading(); + + panelDialog('Login', + div, + { + label:'Login', + doonreturn: true, + fn:function(){ + YAHOO.util.Connect.asyncRequest('POST', + alp.cgi_root + '/session/setauth2.tcl', + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){ if(alp.resubmitRequest) alp.resubmitRequest(); }, + failure: function(o){ + addStatusMessage('Login Failure: '+o.statusText,15); + displayStatusMessages(); + } + }, + 'auths=Login&user=' + encodeURIComponent(u.value) + '&pass=' + encodeURIComponent(p.value) + '&c=' + encodeURIComponent(o.c) + '&f=' + encodeURIComponent(o.server) + '&sessid=' + encodeURIComponent(o.sessid)+ urlSalt('&')); + } + }, + alp.cancelRequest); + + u.focus(); + return false; +} + +function getSmimePassphrase(o){ + var dom = YAHOO.util.Dom; + var alp = YAHOO.alpine; + + var div = document.createElement('div'); + dom.addClass(div,'getAuth'); + + var d = document.createElement('div'); + var addr = (o.addr) ? ' for '+ o.addr : ''; + var e = document.createTextNode('Passphrase is required'+addr+' to decrypt.'); + d.appendChild(e); + div.appendChild(d); + + e = document.createElement('span'); + e.innerHTML = 'Passphrase:'; + div.appendChild(e); + var p = createInputElement('password','p'); + div.appendChild(p); + + hideLoading(); + + panelDialog('Enter S/MIME Passphrase', + div, + { + label:'Done', + fn:function(){ + YAHOO.util.Connect.asyncRequest('POST', + alp.cgi_root + '/session/setpassphrase.tcl', + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){newMessageText(o);}, + failure: function(o){} + }, + 'auths=Smime&pass=' + encodeURIComponent(p.value) + '&sessid=' + encodeURIComponent(o.sessid)+ urlSalt('&')); + } + }); + + return false; +} + + +function flistPick(elChoice,fn){ + elChoice.blur(); + var el = document.getElementById('flPick'); + if(el) el.removeAttribute('id'); + elChoice.parentNode.parentNode.setAttribute('id','flPick'); + updateElementValue('pickFolderName', decodeURIComponent(fn)); + panelDialogEnableButton(true); + return false; +} + +function flistPickPick(elChoice){ + var el = document.getElementById('butChoose'); + if(el){ // two contexts for this element: View/Manage, cp/mv dialog + if('A' == el.nodeName) window.location.href = elChoice.href; + else if('SPAN' == el.nodeName) el.firstChild.firstChild.click(); + } + return false; +} + +function panelDialogEnableButton(tf){ + if(YAHOO.alpine.panel.button) YAHOO.alpine.panel.button.set('disabled',!tf); + if(YAHOO.alpine.panel.keylistener){ + if(tf) + YAHOO.alpine.panel.keylistener.enable(); + else + YAHOO.alpine.panel.keylistener.disable(); + } +} + +function panelDialogInputChange(e){ + panelDialogEnableButton(YAHOO.util.Event.getTarget(e).value.length > 0); +} + +function showFolderList(e){ + hideDisplayDivOrSpan('showFolderList'); + showDisplaySpan('hideFolderList'); + showDisplayDiv('folderList'); + YAHOO.util.Event.preventDefault(e); +} + +function hideFolderList(e){ + hideDisplayDivOrSpan('hideFolderList'); + showDisplaySpan('showFolderList'); + hideDisplayDivOrSpan('folderList'); + YAHOO.util.Event.preventDefault(e); +} + +function pickFolder(containerID,label,defCollection,onDone){ + var dom = YAHOO.util.Dom; + var dbody = document.createDocumentFragment(); + var div = document.createElement('div'); + dom.addClass(div,'flistInstructions'); + div.innerHTML = label + ' to: ' + + var elFolderName = createInputElement('text','pickFolderName'); + elFolderName.setAttribute('id','pickFolderName'); + elFolderName.value = ''; + div.appendChild(elFolderName); + YAHOO.util.Event.addListener(elFolderName,'keyup',panelDialogInputChange); + + el = document.createTextNode(' '); + div.appendChild(el); + + var elFolderCollection = createInputElement('hidden','folderCollection'); + elFolderCollection.value = defCollection; + elFolderCollection.setAttribute('id','pickFolderCollection'); + div.appendChild(elFolderCollection); + + var elFolderPath = createInputElement('hidden','pickFolderPath'); + elFolderPath.setAttribute('id','pickFolderPath'); + div.appendChild(elFolderPath); + + dbody.appendChild(div); + div = document.createElement('div'); + div.setAttribute('id',containerID); + div.innerHTML = 'Loading...'; + dbody.appendChild(div); + + panelDialog(label, + dbody, + { + buttonId:'butChoose', + label:label, + disabled: true, + doonreturn: true, + fn: function(){ + var fc = elFolderCollection.value; + var fp = elFolderPath.value; + var fn = elFolderName.value; + if(fp && fp.length) fn = fp + '/' + fn; + if(fc >= 0 && fn && fn.length) onDone({c:fc,f:fn}); + else showStatusMessage('No folder name provided. No messages moved or copied.',5); + } + }); + + elFolderName.focus(); + drawFolderList(containerID,defCollection); + return false; +} + +function getPanelBodyWidth(panelType){ + var region = YAHOO.util.Dom.getRegion(panelType+'Body'); + YAHOO.alpine.panel.width = region.right - region.left - 12; +} + +function setPanelBodyWidth(className){ + if(YAHOO.env.ua.ie > 0 && YAHOO.alpine.panel.width){ + var dom = YAHOO.util.Dom; + var elArray = dom.getElementsByClassName(className,'div'); + if(elArray){ + for(var i = 0; i < elArray.length; i++){ + dom.setStyle(elArray[i],'width', YAHOO.alpine.panel.width); + } + } + } +} + +// CONTACTS EDITOR +function contactEditor(oMode,onDone){ + var dom = YAHOO.util.Dom; + var form, input, div, label, el; + + function newField(fieldName,input,inputId,defaultValue){ + var div = document.createElement('div'); + dom.addClass(div,'contactSection'); + var el = document.createElement('div'); + div.appendChild(el); + dom.addClass(el,'contactField'); + el.innerHTML = fieldName +':'; + input.setAttribute('id',inputId); + if(defaultValue) input.value = defaultValue; + div.appendChild(input); + return(div); + } + + function validateFields(){ + var n = 0; + var fields = {book:'',ai:'',contactNick:'',contactName:'',contactEmail:'',contactNotes:'',contactFcc:''}; + + for(var f in fields) { + var el = document.getElementById(f); + if(el && el.value && el.value.length){ + var val = el.value.replace(/\n/g, '').replace(/^[ \t]*/, '').replace(/[ \t]*$/, ''); + if(val.length){ + fields[f] = val; + n++; + } + } + } + + return((n > 0) ? fields : null); + } + + if(oMode.which == 'add'){ + label = 'Add'; + } + else if(oMode.which == 'edit'){ + label = 'Change'; + } + else return false; + + form = document.createElement('form'); + dom.addClass(form,'contactEditor'); + + if(oMode.books == null){ + el = createInputElement('hidden','book'); + form.appendChild(el); + el.setAttribute('id','book'); + el.value = (oMode.book > 0) ? oMode.book : 0; + } + + el = createInputElement('hidden','ai'); + form.appendChild(el); + el.setAttribute('id','ai'); + el.value = (oMode.index) ? oMode.index : -1; + + el = createInputElement('hidden','origNick'); + form.appendChild(el); + el.setAttribute('id','origNick'); + if(oMode.nickname) el.value = oMode.nickname; + + el = document.createElement('div'); + form.appendChild(el); + dom.addClass(el,'context'); + el.innerHTML = label + ' Contact'; + + input = createInputElement('text','contactNick'); + form.appendChild(newField('Nickname',input,'contactNick',oMode.nickname)); + form.appendChild(newField('Display Name',createInputElement('text','contactName'),'contactName',oMode.personal)); + + if(oMode.group){ + var elEmail = createNameValueElement('textarea', 'name', 'contactEmail'); + form.appendChild(newField('Group Email',elEmail,'contactEmail',oMode.email)); + if(oMode.which){ + var checked = contactsChecked(); + if(checked.length){ + var comma = ''; + for(var i = 0; i < checked.length; i++){ + getContact({ book:checked[i].book, index:checked[i].index, f:function(c){ elEmail.value += comma + c.email ; comma = ',\n'; } }); + } + } + } + } + else + form.appendChild(newField('Email',createInputElement('text', 'contactEmail'),'contactEmail',oMode.email)); + + form.appendChild(newField('Notes',createNameValueElement('textarea', 'name', 'contactNotes'),'contactNotes',oMode.note)); + form.appendChild(newField('Fcc Folder',createInputElement('text','contactFcc'),'contactFcc',oMode.fcc)); + + if(oMode.books != null){ + var sel = document.createElement('select'); + sel.setAttribute('name','book'); + sel.setAttribute('id','book'); + for(var i = 0; i < oMode.books.length; i++){ + var opt = new Option(oMode.books[i].name,oMode.books[i].book); + sel.options[sel.options.length] = opt; + } + + sel.selectedIndex = 0; + form.appendChild(newField('Address Book',sel,'book')); + } + + if(!onDone) onDone = storeContact; + panelDialog(label, form, { label:label, fn: function(){ onDone(validateFields()); }}); + input.focus(); + return false; +} + +function getContact(o){ + o.which = 'edit'; + var takeDS = new YAHOO.util.DataSource('conduit/getcontact.tcl?book=' + o.book + '&index='); + takeDS.responseType = YAHOO.util.DataSource.TYPE_XML; + takeDS.responseSchema = { + resultNode: 'Result', + fields: ['Nickname','Personal','Mailbox','Fcc','Note'] + }; + takeDS.sendRequest(o.index, + { + success: function(oReq,oResp,oPayload){ + if(oResp.results.length == 1){ + o.nickname = oResp.results[0].Nickname; + o.personal = oResp.results[0].Personal; + o.email = oResp.results[0].Mailbox; + if(o.email.search(/,/) >= 0) o.group = true; + o.note = oResp.results[0].Note; + o.fcc = oResp.results[0].Fcc; + o.f(o); + } + else showStatusMessage('Too many entries to Edit', 10); + }, + failure: function(oReq,oResp,oPayload){ + showStatusMessage('Error Taking Address: ' + oResp.responseText, 10); + }, + scope: this, + argument:[o] + }); + return(false); +} + +function storeContact(oFields){ + if(oFields){ + var sUrl = 'conduit/storecontact.tcl?'; + for(var f in oFields) sUrl += '&' + f + '=' + encodeURIComponent(oFields[f]); + storeDS = new YAHOO.util.DataSource(sUrl); + storeDS.responseType = YAHOO.util.DataSource.TYPE_XML; + storeDS.responseSchema = { + resultNode: 'Result', + fields: ['StatusText'] + }; + // bug: if present, store parts should be passed in draw request + storeDS.sendRequest('', + { + success: function(oReq,oResp,oPayload){ + for(var i = 0; i < oResp.results.length; i++) addStatusMessage(oResp.results[i].StatusText, 10); + displayStatusMessages(); + }, + failure: function(oReq,oResp,oPayload){ + showStatusMessage('Error Taking Address: ' + oResp.responseText, 10); + }, + scope: this + }); + } +} + + +function contactsChecked(gripe){ + var chkd = []; + var i, entry, l = document.getElementsByName('nickList'); + if(l){ + for(i = 0; i < l.length; i++){ + if(l[i].checked){ + entry = l[i].value.match(/^(\d+)\.(\d+)\.(.*)$/); + if(entry) chkd[chkd.length] = { book:entry[1], index:entry[2], nick:entry[3] }; + } + } + } + + if(gripe != undefined && 0 == chkd.length){ + var t = 'No Contacts Selected<p>Choose contacts by clicking checkbox to left of contact.'; + if(gripe.length) t += 'Then press ' + gripe; + panelAlert(t); + } + + return(chkd); +} + +// LOAD From: INTO CONTACT EDITOR +function takeAddressFrom(uid,o){ + var books = (o) ? o.books : null; + // get personal and email based on uid + takeDSRequest = 'conduit/take.tcl?op=from&u='; + takeDS = new YAHOO.util.DataSource(takeDSRequest); + takeDS.responseType = YAHOO.util.DataSource.TYPE_XML; + takeDS.responseSchema = { + resultNode: 'Result', + fields: ['Type','Email','Personal','Nickname','Fcc','Note'] + }; + takeDS.sendRequest(uid, + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(oReq,oResp,oPayload){ + if(oResp.results.length == 1){ + var o = { + which:oResp.results[0].Type, + nickname:oResp.results[0].Nickname, + personal:oResp.results[0].Personal, + email:oResp.results[0].Email, + fcc:oResp.results[0].Fcc, + note:oResp.results[0].Note + }; + if(books) o.books = books; + contactEditor(o); + } + else showStatusMessage('Too many From addresses, Use Take', 10); + }, + failure: function(oReq,oResp,oPayload){ + showStatusMessage('Error Taking Address: ' + oResp.responseText, 10); + }, + scope: this, + arguments:[books] + }); + + return true; +} + +// CONTACT LISTER + +function newContactList(elContainer,controlObj,idBook,objParm){ + if(elContainer){ + var nUrl = 'conduit/contactlist.tcl/' + idBook; + var conj = '?'; + var prop, parms = ''; + if(objParm){ + for(prop in objParm){ + parms += conj + prop + '=' + encodeURIComponent(objParm[prop]); + conj = '&'; + } + } + YAHOO.util.Connect.asyncRequest('GET', + nUrl + parms + urlSalt(conj), + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o){ + elContainer.innerHTML = o.responseText; + evalScripts(o.responseText); + setPanelBodyWidth('clistContacts'); + window.scrollTo(0,0); + }, + failure: function(o){ + showStatusMessage('Cannot build list: '+o.statusText,10); + }, + argument: [elContainer] + }); + if(controlObj) controlObj.blur(); + } + return false; +} + +function drawContactList(idContainer,idBook,objParm){ + if(idContainer && idContainer.length){ + var el = document.getElementById(idContainer); + if(el){ + newContactList(el,null,idBook,objParm); + YAHOO.alpine.containers.contactlist = el; + } + } +} + +// Search within Content +function searchContent(context,treeId){ + var elSearch = document.getElementById('searchField'); + if(elSearch && elSearch.value && elSearch.value.length){ + var dom = YAHOO.util.Dom; + var i, j, node, nodeParent; + var oldMatches = dom.getElementsByClassName('searchMatch','span',treeId); + for(i = 0; i < oldMatches.length; i++){ + // BUG: coalesce node's text and prev/next sibling's text into single node + node = oldMatches[i]; + nodeParent = node.parentNode; + for(j = 0; j < node.childNodes.length; j++) nodeParent.insertBefore(node.childNodes[j].cloneNode(true),node); + nodeParent.removeChild(node); + } + + var lcSearch = elSearch.value.toLowerCase(); + var nodeText, matchOffset, found = {n:0}; + var removeNodes = []; + var nodeArray = function(root){ + var textNodes = []; + + function appendTextNodes(el){ + for(var o = el.firstChild; o; o = o.nextSibling){ + switch(o.nodeType){ + case 3 : textNodes[textNodes.length] = o; break; + case 1 : appendTextNodes(o); break; + } + } + } + + appendTextNodes(root); + return(textNodes); + }(document.getElementById(treeId)); + + var nodeBefore, nodeAfter, span; + for(i = 0; i < nodeArray.length; i++){ + node = nodeArray[i]; + nodeText = node.nodeValue; + matchOffset = nodeText.toLowerCase().indexOf(lcSearch); + if(matchOffset >= 0){ + parentNode = node.parentNode; + nodeBefore = document.createTextNode(nodeText.substr(0,matchOffset)); + nodeAfter = document.createTextNode(nodeText.substr(matchOffset+lcSearch.length)); + matchText = nodeText.substr(matchOffset, lcSearch.length); + span = document.createElement("span"); + dom.addClass(span,'searchMatch'); + span.appendChild(document.createTextNode(matchText)); + parentNode.insertBefore(nodeBefore,node); + parentNode.insertBefore(span,node); + parentNode.insertBefore(nodeAfter,node); + removeNodes[removeNodes.length] = {child: node, parent: parentNode}; + found.n++; + if(!found.o) found.o = parentNode; + } + } + + for(i = 0; i < removeNodes.length; i++){ + node = removeNodes[i]; + node.parent.removeChild(node.child) + } + } + + if(found.n > 0){ + var plural = (found.n > 1) ? 'es' : ''; + showStatusMessage(found.n + ' match' + plural + ' found', 3); + found.o.scrollIntoView(); + } + else showStatusMessage('No ' + context + ' found matching your seach', 3); + + return(false); +} + +// Advanced search +function advanceSearch(){ + var dom = YAHOO.util.Dom; + var i, d, form, el, span, dates; + var elScope, elWhichAddr, elWhichAddrText, elWhichSubj, elWhichSubjText, elWhichBody, elWhichBodyText, elWhichStatus, elWhichDate, elMonth, elDay, elYear; + function newSearchDiv(cl,el){ + var div = document.createElement('div'); + dom.addClass(div,cl); + if(el) div.appendChild(el); + return(div); + } + + function newSearch(title,elSelect,elCriteria){ + var div = document.createElement('div'); + dom.addClass(div,'searchSection'); + div.appendChild(newSearchDiv('searchField',document.createTextNode(title + ':'))); + div.appendChild(newSearchDiv('searchType',elSelect)); + div.appendChild(newSearchDiv('searchTerm',elCriteria)); + return(div); + } + + function newSelect(id,opts,onchange){ + var elSel = document.createElement('select'); + elSel.setAttribute('name',id); + elSel.setAttribute('id',id); + if(onchange) YAHOO.util.Event.addListener(elSel,'change',onchange); + for(var i = 0; i < opts.length; i++) elSel.options[elSel.options.length] = new Option(opts[i],i); + return elSel; + } + + function newInput(id){ + var el = createInputElement('text',id); + el.setAttribute('id',id); + YAHOO.util.Event.addListener(el,'keypress',searchOnEnter,'_search_'); + return(el); + } + + form = document.createElement('form'); + dom.addClass(form,'advanceSearch'); + + el = document.createElement('div'); + form.appendChild(el); + dom.addClass(el,'context'); + el.innerHTML = 'Search in ' + quoteHtml(YAHOO.alpine.current.f); + + el = document.getElementById('searchRefine'); + if(el){ + d = dom.getStyle(el,'display'); + if(d && d != 'none'){ + el = document.createElement('div'); + form.appendChild(el); + dom.addClass(el,'scope'); + elScope = newSelect('searchScope',['Perform this search within current search results','Add results of this search to current results','Perform a fresh search, abandoning the current results']); + el.appendChild(elScope); + } + } + + elWhichAddr = newSelect('whichAddr',['From:','To:','Cc:','From:, Cc:','From:, To:, Cc:']); + elWhichAddrText = newInput('textAddr'); + form.appendChild(newSearch('Address',elWhichAddr,elWhichAddrText)); + elWhichSubj = newSelect('whichSubj',['Contains','Does Not Contain']); + elWhichSubjText = newInput('textSubj'); + form.appendChild(newSearch('Subject',elWhichSubj,elWhichSubjText)); + elWhichBody = newSelect('whichBody',['Contains','Does Not Contain']); + elWhichBodyText = newInput('textBody'); + form.appendChild(newSearch('Message Text',elWhichBody,elWhichBodyText)); + + // prep date fields + span = document.createElement('span'); + span.setAttribute('id','searchDates'); + dom.setStyle(span,'display','none'); + elMonth = newSelect('searchMonth',['------','January','February','March','April','May','June','July','August','September','October','November','December']); + span.appendChild(elMonth); + dates = ['--']; + for(i = 1; i < 32; i++) dates[dates.length] = i; + elDay = newSelect('searchDay', dates); + span.appendChild(elDay); + el= document.createTextNode(', '); + span.appendChild(el); + dates = ['----']; + d = new Date(); + for(i = d.getFullYear(); i > 1970; i--) dates[dates.length] = i; + elYear = newSelect('searchYear',dates); + span.appendChild(elYear); + elWhichDate = newSelect('whichDate',['Anytime','Today','Past week','Past month','On','Since','Before'],advanceSearchDate); + form.appendChild(newSearch('Date',elWhichDate,span)); + + // empty searchTerm + elWhichStatus = newSelect('whichStatus',['All Messages','Unread Messages','Read Messages','Starred Messages','Unstarred Messages']); + form.appendChild(newSearch('Status',elWhichStatus)); + + panelDialog('Advanced Search', + form, + { + label:' Search ', + doonreturn: true, + fn: function() { + var scope = 'new', criteria = ''; + + if(elScope){ + scope = ['narrow','broad'][elScope.selectedIndex]; + } + + if(elWhichAddrText.value.length){ + criteria += '{text ton ' + ['from','to','cc','recip','partic'][elWhichAddr.selectedIndex] + ' {' + elWhichAddrText.value + '}} '; + } + + if(elWhichSubjText.value.length){ + criteria += '{text '; + criteria += (elWhichSubj.selectedIndex > 0) ? 'not' : 'ton'; + criteria += ' subj {' + elWhichSubjText.value + '}} '; + } + + if(elWhichBodyText.value.length){ + criteria += '{text '; + criteria += (elWhichBody.selectedIndex > 0) ? 'not' : 'ton'; + criteria += ' body {' + elWhichBodyText.value + '}} '; + } + + if(elWhichDate.selectedIndex > 0 && elMonth.selectedIndex > 0 && elDay.selectedIndex > 0 && elYear.selectedIndex > 0){ + criteria += '{date ' + ['','on','since','since','on','since','before'][elWhichDate.selectedIndex]; + criteria += ' ' + elYear.options[elYear.selectedIndex].text; + criteria += ' ' + elMonth.options[elMonth.selectedIndex].text.substring(0,3).toLowerCase(); + criteria += (elDay.selectedIndex < 10) ? ' 0' : ' '; + criteria += elDay.selectedIndex; + criteria += '} '; + } + + if(elWhichStatus.selectedIndex > 0){ + criteria += '{status ' + ['','ton new','not new','ton imp','not imp'][elWhichStatus.selectedIndex] + '} '; + } + + newMessageList({parms:{op:'search',type:'compound',scope:scope,criteria:criteria,page:'new'}}); + } + }); + + return false; +} + +function advanceSearchDate(e){ + var y, d = new Date(); + + function setSelect(id,i){ + var el = document.getElementById(id); + if(el) el.selectedIndex = i; + } + + function setSearchDate(m,d,y){ + setSelect('searchMonth',m); + setSelect('searchDay',d); + setSelect('searchYear',y); + } + + switch(YAHOO.util.Event.getTarget(e).selectedIndex){ + case 0 : + hideDisplayDivOrSpan('searchDates'); + setSearchDate(0,0,0); + break; + case 1: + hideDisplayDivOrSpan('searchDates'); + setSearchDate(d.getMonth() + 1, d.getDate(), 1); + break; + case 2 : + hideDisplayDivOrSpan('searchDates'); + y = d.getFullYear(); + d.setDate(d.getDate() - 7); + setSearchDate(d.getMonth() + 1,d.getDate(),(y - d.getFullYear()) + 1); + break; + case 3 : + hideDisplayDivOrSpan('searchDates'); + y = d.getFullYear(); + if(d.getMonth()) d.setMonth(d.getMonth() - 1); else d.setMonth(11); + setSearchDate(d.getMonth() + 1, d.getDate(),(y - d.getFullYear()) + 1); + break; + default : + showDisplaySpan('searchDates'); + setSearchDate(d.getMonth() + 1, d.getDate(), 1); + break; + } +} + +function searchOnEnter(e,btn){ + if(YAHOO.util.Event.getCharCode(e) == 13){ + var el = document.getElementById(btn); + if(el){ + // dig thru any decoration to find button + while(el && !el.click) el = el.firstChild; + if(el && el.click){ + el.click(); + return false; + } + } + } + + return true; +} + +function rotateNews(el){ + if(el.parentNode){ + var dom = YAHOO.util.Dom; + var node = el.parentNode; + + dom.setStyle(node, 'display', 'none'); + if(node.nextSibling && node.nextSibling.tagName == 'SPAN'){ + node = node.nextSibling; + } + else{ + for(var node = el.parentNode; node.previousSibling && node.previousSibling.tagName == 'SPAN'; node = node.previousSibling) + ; + } + + dom.setStyle(node,'display','inline'); + } + + return false; +} + +function printContent(){ + window.print(); + return false; +} + +// Test to see if a folder exists, create if asked +function folderExists(o){ + var eUrl = 'conduit/exists.tcl' + encodeURI('?c=' + o.c + '&f=' + o.f); + + function onYes(o){ + folderExists(o); + if(o.onDone) o.onDone(); + } + + if (o.create != undefined) + eUrl += '&create=' + o.create; + + YAHOO.util.Connect.asyncRequest('GET', + eUrl + urlSalt('&'), + { + success: function(retObj) { + eval('var exObj = '+retObj.responseText); + if(exObj.exists != undefined){ + if(!exObj.exists){ + o.create = 'yes'; + panelConfirm('Folder does not exist. Create it?',{text:'Create',fn:onYes,args:o},{fn:o.oncancel}); + } + else if(o.onDone){ + o.onDone(); + } + } + else{ + if(exObj.error != undefined) + alert('ERROR: '+exObj.error); + else + alert('INCONCLUSIVE: '+retObj.responseText); + } + }, + failure: function(retObj) { newStatusMessage('Request Failure: ' + retObj.statusText); } + }); +} + +// Hacks to work around IE +function createInputElement(type,name){ + if(YAHOO.env.ua.ie > 0){ + return(document.createElement('<input type="' + type + '" type="' + name + '" name="' + name + '">')); + } + + var el = document.createElement('input'); + el.setAttribute('type',type); + el.setAttribute('id',name); + el.setAttribute('name',name); + return(el); +} + +function createNameValueElement(tag, name, nameAttr){ + if(YAHOO.env.ua.ie > 0){ + return(document.createElement('<' + tag + ' ' + name + '="' + nameAttr + '">')); + } + + var el = document.createElement(tag); + el.setAttribute(name,nameAttr); + return(el); +} + +// HACKS TO MAINTAIN FIX DIV IN VIEWPORT +function sizeVPHeight(){ + // force msg txt container to fit in viewport + var dom = YAHOO.util.Dom; + var docHeight = dom.getDocumentHeight(); + var topToolbarY = dom.getY('topToolbar'); + var alpineContentY = dom.getY('alpineContent'); + var bottomToolbarY = dom.getY('bottomToolbar'); + var bottomHeight = docHeight - bottomToolbarY; + var contentHeight = dom.getViewportHeight() - (alpineContentY + bottomHeight); + var leftColumnHeight = contentHeight + (alpineContentY - topToolbarY); + if(contentHeight > 0){ + dom.setStyle('alpineContent','height', Math.round(contentHeight)); + dom.setStyle('leftColumn','height', Math.round(leftColumnHeight)); + } +} + +function resizeVPHeight(){ + var dom = YAHOO.util.Dom; + dom.setStyle('alpineContent','height', 'auto'); + dom.setStyle('leftColumn','height', 'auto'); + sizeVPHeight(); +} + +// DEBUGGING +function dumpProp(o){ + var s = ''; + for(p in o) s += p + ' = ' + o[p] + '\n'; + return s; +} diff --git a/web/cgi/alpine/2.0/lib/compose.js b/web/cgi/alpine/2.0/lib/compose.js new file mode 100644 index 00000000..52eddea9 --- /dev/null +++ b/web/cgi/alpine/2.0/lib/compose.js @@ -0,0 +1,833 @@ +/* $Id: compose.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +// globals in our namespace +YAHOO.alpine.autodraft = { timeout:0, timer:null, reporttimer:null }; +YAHOO.alpine.pickcontact = { tabs:null, markup:null }; +YAHOO.alpine.uploading = 0; +YAHOO.alpine.expandaddress = 1; + + +function initSimpleEditor(focus){ + var dom = YAHOO.util.Dom; + var edRegion = dom.getRegion('composeText'); + var textareaHeight = edRegion.bottom - edRegion.top; + var textareaWidth = edRegion.right - edRegion.left - 10; + if(edRegion){ + var editAttrib = { + height:textareaHeight, + width: textareaWidth, + toolbar: { + draggable: false, + buttons: [ + { group: 'fontstyle', label: 'Font Name and Size', + buttons: [ + { type: 'select', label: 'Arial', value: 'fontname', disabled: true, + menu: [ + { text: 'Arial', checked: true }, + { text: 'Arial Black' }, + { text: 'Comic Sans MS' }, + { text: 'Courier New' }, + { text: 'Lucida Console' }, + { text: 'Tahoma' }, + { text: 'Times New Roman' }, + { text: 'Trebuchet MS' }, + { text: 'Verdana' } + ] + }, + { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true } + ] + }, + { type: 'separator' }, + { group: 'textstyle', label: 'Font Style', + buttons: [ + { type: 'push', label: 'Bold', value: 'bold' }, + { type: 'push', label: 'Italic', value: 'italic' }, + { type: 'push', label: 'Underline', value: 'underline' }, + { type: 'separator' }, + { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }, + { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true } + ] + }, + { type: 'separator' }, + { group: 'indentlist', label: 'Lists', + buttons: [ + { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' }, + { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' } + ] + }, + { type: 'separator' }, + { group: 'alignment', label: 'Alignment', + buttons: [ + { type: 'push', label: 'Align Left', value: 'justifyleft' }, + { type: 'push', label: 'Align Center', value: 'justifycenter' }, + { type: 'push', label: 'Align Right', value: 'justifyright' }, + { type: 'push', label: 'Justify', value: 'justifyfull' } + ] + }, + { type: 'separator' }, + { group: 'insertitem', label: 'Insert Item', + buttons: [ + { type: 'push', label: 'Insert/Edit HTML Link', value: 'createlink', disabled: true }, + { type: 'push', label: 'Insert Image', value: 'insertimage' } + ] + } + ] + } + }; + if(focus){ + editAttrib.focusAtStart = true; + } + gRichtextEditor = new YAHOO.widget.SimpleEditor('composeText', editAttrib); + gRichtextEditor.textareaHeight = textareaHeight; + gRichtextEditor.textareaWidth = textareaWidth; + } +} + + +function flipRichText(){ + var dom = YAHOO.util.Dom; + if(gRichState){ + gRichState = 0; + gRichtextEditor.saveHTML(); + var stripHTML = /<\S[^><]*>/g; + gRichtextEditor.get('textarea').value = gRichtextEditor.get('textarea').value.replace(/<br>/gi, '\n').replace(stripHTML, '').replace(/</g,'<').replace(/>/g,'>'); + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'position', 'absolute'); + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'top', '-9999px'); + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'left', '-9999px'); + gRichtextEditor.get('element_cont').removeClass('yui-editor-container'); + dom.setStyle(gRichtextEditor.get('element'), 'visibility', 'visible'); + dom.setStyle(gRichtextEditor.get('element'), 'top', ''); + dom.setStyle(gRichtextEditor.get('element'), 'left', ''); + dom.setStyle(gRichtextEditor.get('element'), 'height', gRichtextEditor.textareaHeight); + dom.setStyle(gRichtextEditor.get('element'), 'width', gRichtextEditor.textareaWidth); + dom.setStyle(gRichtextEditor.get('element'), 'position', 'static'); + document.getElementById('flipRich').innerHTML = 'Rich Text'; + } + else{ + if(!gRichtextRendered){ + // fixup initial text + var t = document.getElementById('composeText').value.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>'); + document.getElementById('composeText').value = t; + initSimpleEditor(1); + gRichtextEditor.render(); + gRichtextRendered = true; + } + gRichState = 1; + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'position', 'static'); + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'top', '0'); + dom.setStyle(gRichtextEditor.get('element_cont').get('firstChild'), 'left', '0'); + dom.setStyle(gRichtextEditor.get('element'), 'visibility', 'hidden'); + dom.setStyle(gRichtextEditor.get('element'), 'top', '-9999px'); + dom.setStyle(gRichtextEditor.get('element'), 'left', '-9999px'); + dom.setStyle(gRichtextEditor.get('element'), 'position', 'absolute'); + gRichtextEditor.get('element_cont').addClass('yui-editor-container'); + gRichtextEditor._setDesignMode('on'); + if(gRichtextEditor.get('textarea')) gRichtextEditor.setEditorHTML(gRichtextEditor.get('textarea').value.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>')); + document.getElementById('flipRich').innerHTML = 'Plain Text'; + } + + return false; +} + +function autoSizeThis(e){ + if(e.keyCode == 13 || e.keyCode == 10) YAHOO.util.Event.preventDefault(e); + else autoSize(this); +} + +function autoSize(el){ + var dom = YAHOO.util.Dom; + var r = dom.getRegion(el) + var th = r.bottom - r.top; + var maxh = 3 * gFieldHeight; + if(!el.value.length){ + dom.setStyle(el,'height',(gFieldHeight + 4)+'px'); + } + else if(th < maxh){ + if(el.scrollHeight > gFieldHeight){ + var h = (2 * (gFieldHeight)); + if(el.scrollHeight > h) h += gFieldHeight; + dom.setStyle(el,'height',h + 'px'); + } + } +} + +function autoSizeAddressField(id){ + var el = document.getElementById(id); + if(el){ + if(!gFieldHeight){ + var r = YAHOO.util.Dom.getRegion(el); + gFieldHeight = r.bottom - r.top - 4; + } + + YAHOO.util.Event.addListener(el,'keypress',autoSizeThis); + autoSize(el); + } +} + +function autoCompleteDefaults(o){ + if(o){ + o.delimChar = ','; + o.maxResultsDisplayed = 12; + o.minQueryLength = 2; + o.queryDelay = 0.25; + o.autoHighlight = true; + o.animSpeed = 0.1; + o.formatResult = function(aResults, sQuery) { + var r, where; + // highlight matching substrings + var oREHilite = new RegExp(sQuery,'ig'); + var sEmail = aResults[0].replace(/[<]/,'<') + var sNick = aResults[1].replace(/[<]/,'<') + r = sEmail.replace(oREHilite,'<b>$&</b>'); + where = sNick.replace(oREHilite,'<b>$&</b>'); + if(where.length) r += ' (' + where + ')'; + return r; + }; + + o.textboxBlurEvent.subscribe(function(oSelf){ + var el = o.getInputEl(); + if(el.value.length) validateAddressField(el); + }); + o.containerCollapseEvent.subscribe(function(oSelf){ + var el = o.getInputEl(); + if(el.value.length) validateAddressField(el); + }); + } +} + +function actuallySend(o){ + YAHOO.alpine.resubmitRequest = function(){ actuallySend(o); }; + + if(YAHOO.alpine.disablePost) return; + + stopAutoDrafting(); + + document.getElementById('sendOp').value = o.op; + + if(gRichtextEditor && gRichState){ + gRichtextEditor.saveHTML(); + document.getElementById('contentSubtype').value = 'HTML'; + } + + showLoading(); + + while(YAHOO.alpine.uploading > 0) + panelAlert('Finishing attachment upload before sending...'); + + document.getElementById('composeForm').submit(); +} + +function sendSuccess(m){ + var alp = YAHOO.alpine; + alp.disablePost = true; + window.location.replace(alp.cgi_base + 'browse/' + alp.current.c + '/' + alp.current.f); +} + +function sendFailure(m){ + addStatusMessage('Send Failure: ' + m, 10); + displayStatusMessages(); + hideLoading(); +} + +function processPostAuthException(o){ + YAHOO.alpine.cancelRequest = null; + processAuthException(o); +} + +function cancelComposition(dest){ + stopAutoDrafting(); + var changes = 0; + var el, changeFields = ['fieldTo','fieldCc','fieldBcc','fieldSubject']; + for (f in changeFields){ + el = document.getElementById(changeFields[f]); + changes += el.value.length; + } + + if(!changes){ + if(gRichState){ + changes += gRichtextEditor.getEditorHTML().length; + } + else{ + el = document.getElementById('composeText'); + if(el) changes += el.value.length; + } + } + + if(changes) panelConfirm('You have unsaved changes.<br><br>Click <b>Discard</b> to abandon your text and exit Compose.<br>Click <b>Cancel</b> to continue editing.',{text:'Discard',fn:abandonComposition,args:{url:dest}},{fn:startAutoDrafting}); + else abandonComposition({url:dest}); + + return false; +} + +function sendComposition(){ + stopAutoDrafting(); + + if(!(document.getElementById('fieldTo').value.length + || document.getElementById('fieldCc').value.length + || document.getElementById('fieldBcc').value.length + || document.getElementById('fieldFcc').value.length)){ + panelAlert('Message must contain at least one To, Cc, Bcc, or Fcc recipient!', startAutoDrafting); + } + else{ + //panelConfirm('Are you sure you want to send this message?',{text:'Send',fn:actuallySend,args:{op:'send'}},{fn:startAutoDrafting}); + actuallySend({op:'send'}); + } + + return false; +} + +function saveDraft(){ + actuallySend({op:'postpone'}); + return false; +} + +function setAutoDraftInterval(iTimeOut){ + YAHOO.alpine.autodraft.timeout = iTimeOut; + startAutoDrafting(); +} + +function startAutoDrafting(){ + var aa = YAHOO.alpine.autodraft; + if(aa.timeout) aa.timer = window.setTimeout('autoDraft();', aa.timeout * 1000); +} + +function stopAutoDrafting(){ + var aa = YAHOO.alpine.autodraft; + if(aa.timer) clearTimeout(aa.timer); + aa.timer = null; +} + +function autoDraft(){ + var form = document.getElementById('composeForm'); + var formTarget = form.getAttribute('target'); + form.setAttribute('target','formResponse'); + actuallySend({op:'autodraft'}); + form.setAttribute('target', formTarget); + startAutoDrafting(); + var date = new Date(); + YAHOO.alpine.autodraft.drafted = date.getTime(); +} + +function reportAutoDraftUpdate(){ + var aa = YAHOO.alpine.autodraft; + var nn = new Date(); + var drafted = new Date(aa.drafted); + var delt = Math.floor((nn.getTime() - aa.drafted) / 60000); + var hours = ( drafted.getHours() % 12 ); + var minutes = drafted.getMinutes(); + var ispm = ( drafted.getHours() > 12 ); + if(hours < 1) hours = 12; + if(minutes < 10) minutes = '0' + minutes; + var t = 'Copy saved to Drafts at ' + hours + ':' + minutes + ' '; + if(ispm) + t += 'PM'; + else + t += 'AM'; + + if(delt > 0){ + t += ' (' + delt + ' minute'; + if(delt > 1) t += 's'; + t += ' ago)'; + } + + document.getElementById('lastAutoDraft').innerHTML = t; +} + +function reportAutoDraft(result){ + if(result.match(/^[0-9]+$/)){ + var aa = YAHOO.alpine.autodraft; + var date = new Date(); + document.getElementById('autoDraftUid').value = result; + var drafted = new Date(aa.drafted); + var minutes = drafted.getMinutes(); + if(minutes < 10) minutes = '0' + minutes; + document.getElementById('lastAutoDraft').innerHTML = 'Copy saved to Drafts at ' + ( drafted.getHours() % 12 ) + ':' + minutes + ' (less than one minute ago)'; + if(aa.reporttimer) clearInterval(aa.reporttimer); + aa.reporttimer = setInterval('reportAutoDraftUpdate();', + 60000); + } + else{ + document.getElementById('lastAutoDraft').innerHTML = 'Copy save to Drafts FAILED: ' + result; + addStatusMessage('Copy autosave to Drafts failed: ' + result, 10); + displayStatusMessages(); + } +} + +function abandonComposition(o){ + var u = document.getElementById('autoDraftUid').value; + if(u.match(/^\d+$/) && u > 0){ + emptyFolder(gDefCol, gDraftFolder, u, {fn:'window.location.href="' + o.url + '"'}); + } + else{ + window.location.href = o.url; + } +} + +function drawAttachmentList(o){ + var dom = YAHOO.util.Dom; + var el, attachList = document.getElementById('attachList'); + var idList = ''; + var comma = ''; + hideLoading(); + while(attachList.childNodes.length) attachList.removeChild(attachList.childNodes[0]); + if(o){ + if(o.error){ + addStatusMessage('Attach Error: ' + o.error, 10); + displayStatusMessages(); + } + + if(o.attachments && o.attachments.length){ + var frag = document.createDocumentFragment(); + var delim = '', len, size, bytes; + for(var i = 0; i < o.attachments.length; i++){ + idList += comma + o.attachments[i].id; + + if(delim.length){ + el = document.createTextNode(delim); + frag.appendChild(el); + } + + el = document.createElement('img'); + el.setAttribute('src','img/cbn/attach_sm.gif'); + frag.appendChild(el); + + l = o.attachments[i].size.length; + if(l > 6){ + size = o.attachments[i].size.substr(0, l - 6); + bytes = 'MB'; + } + else if(o.attachments[i].size.length > 3){ + size = o.attachments[i].size.substr(0, l - 3); + bytes = 'KB'; + } + else{ + size = o.attachments[i].size; + bytes = 'B'; + } + + el = document.createElement('span'); + dom.addClass(el,'attachmentName'); + el.innerHTML = o.attachments[i].fn + ' ' + '(' + size + ' ' + bytes + ')'; + frag.appendChild(el); + + el = document.createElement('a'); + el.setAttribute('href','#'); + YAHOO.util.Event.addListener(el,'click',removeAttachment,{id:o.attachments[i].id}); + var img = document.createElement('img'); + img.setAttribute('src','img/cbn/remove.gif'); + dom.addClass(img,'wap'); + el.appendChild(img); + frag.appendChild(el); + + delim = ': '; + comma = ','; + } + + attachList.appendChild(frag); + dom.setStyle('composeAttachments','display','block'); + } + else{ + dom.setStyle('composeAttachments','display','none'); + if(el) el.innerHTML = ''; + } + } + + el = document.getElementById('attachments'); + if(el) el.setAttribute('value',idList); +} + +function attachFile(e){ + var target = YAHOO.util.Event.getTarget(e); + if(target.value.length){ + var elRemove = target.parentNode.parentNode; + var elParent = elRemove.parentNode; + YAHOO.util.Connect.setForm(target.parentNode,true); + YAHOO.alpine.uploading++; + YAHOO.util.Connect.asyncRequest('POST','conduit/attach.tcl', { + upload: function(response){ + YAHOO.alpine.uploading--; + elParent.removeChild(elRemove); + } + }); + } + else + panelAlert('No File Attached'); + + return false; +} + +function addAttachField(){ + var event = YAHOO.util.Event; + var dom = YAHOO.util.Dom; + + dom.setStyle('composeAttachments','display','block'); + + var parentDiv = document.getElementById('fileUpload'); + if(parentDiv.childNodes.length < 20){ + var div = document.createElement('div'); + parentDiv.appendChild(div); + dom.addClass(div,'attachInput'); + + var form = document.createElement('form'); + div.appendChild(form); + + form.setAttribute('action','conduit/attach.tcl'); + form.setAttribute('method','POST'); + form.setAttribute('enctype','multipart/form-data'); + form.setAttribute('target','formResponse'); + dom.generateId(form); + + var input = createInputElement('file','file'); + form.appendChild(input); + input.setAttribute('accept','*/*'); + event.addListener(input,'change',attachFile); + + /* + var el = createInputElement('button','Attach') + div.appendChild(el); + el.setAttribute('value','Attach'); + event.addListener(el,'click',attachFile); + */ + } + + return false; +} + +function removeAttachment(e,o){ + var form = document.createElement('form'); + this.parentNode.appendChild(form); + YAHOO.util.Dom.setStyle(form,'display','none'); + form.setAttribute('action','conduit/attach.tcl'); + form.setAttribute('method','GET'); + form.setAttribute('target','formResponse'); + + var input = createInputElement('hidden','op'); + input.setAttribute('value','delete'); + form.appendChild(input); + + input = createInputElement('hidden','id'); + input.setAttribute('value',o.id); + form.appendChild(input); + + form.submit(); + + YAHOO.util.Event.preventDefault(e); +} + +function setCursorPosition(inputId, cursorOffset) { + var inputEl = document.getElementById(inputId); + if(inputEl){ + if (inputEl.setSelectionRange) { + inputEl.focus(); + inputEl.setSelectionRange(cursorOffset, cursorOffset); + } else if (inputEl.createTextRange) { + var range = inputEl.createTextRange(); + range.collapse(true); + range.moveEnd('character', cursorOffset); + range.moveStart('character', cursorOffset); + range.select(); + } + } +} + +function pickFccDone(o){ + updateElementValue('fieldFcc', o.f); + return false; +} + +function fccExists(force){ + var elF = document.getElementById('fieldFcc'); + var elC = document.getElementById('fieldFccCollection'); + var o = { + c:elC.value, + f:elF.value, + oncancel: function(){ + elF.focus(); + elF.select() + } + }; + + if(force) + o.create = 'yes'; + + if(elF && elC && elF.value.length && elC.value.length) + folderExists(o); +} + +function expandAddress(expObj){ + var eUrl = 'conduit/expand.tcl?'; + if(expObj.book){ + eUrl += 'book=' + expObj.book; + eUrl += '&index=' + expObj.ai; + } + else if(expObj.addrs){ + eUrl += 'addrs=' + encodeURIComponent(expObj.addrs); + } + else + return; + + var expandDS = new YAHOO.util.DataSource(eUrl); + expandDS.responseType = YAHOO.util.DataSource.TYPE_XML; + expandDS.responseSchema = { + resultNode: 'Result', + fields: ['Error','Address','Fcc'] + }; + expandDS.sendRequest('', + { + success: function(oReq,oResp,oPayload){ + var errs = false; + if(expObj.addrs && oResp.results[0] && !oResp.results[0].Error) updateElementValue(expObj.fieldId, ''); + for(var i = 0; i < oResp.results.length; i++){ + if(oResp.results[i].Error){ + addStatusMessage('Address Error: '+oResp.results[i].Error, 10); + errs++; + } + else if(oResp.results[i].Address){ + appendAddress(expObj.fieldId, oResp.results[i].Address); + if(expObj.fieldId == 'fieldTo' && oResp.results[i].Fcc && oResp.results[i].Fcc.length) updateElementValue('fieldFcc', oResp.results[i].Fcc); + } + } + if(errs){ + displayStatusMessages(); + var el = document.getElementById(expObj.fieldId); + if(el) el.focus(); + } + }, + failure: function(oReq,oResp,oPayload){ + showStatusMessage('Error expanding Field: ' + oResp.responseText, 10); + }, + scope: this, + argument:[expObj] + }); + +} + +function donePickContact(fieldId){ + switch (YAHOO.alpine.pickcontact.tabs.get('activeIndex')){ + case 0 : + var l = document.getElementsByName('nickList'); + if(l){ + var i, ai = contactsChecked('Add'); + for(i in ai) expandAddress({book:ai[i].book,ai:ai[i].index,fieldId:fieldId}); + } + break; + case 1 : + var l = document.getElementsByName('qrList'); + if(l){ + var i, el, addrs = ''; + for(i = 0; i < l.length; i++){ + if(l[i].checked){ + if(addrs.length) addrs += ', '; + el = document.getElementById('qrPers'+l[i].value); + if(el){ + var specials = el.innerHTML.match(/[()<>@,;:\\\".\[\]]/); + if(specials) addrs += '"' + el.innerHTML + '"'; + else addrs += el.innerHTML; + } + el = document.getElementById('qrAddr'+l[i].value); + if(el) addrs += ' <' + el.innerHTML + '>'; + } + } + + appendAddress(fieldId,addrs); + } + break; + } +} + +function appendAddress(fieldId, addrs){ + if(addrs.length){ + var el = document.getElementById(fieldId); + if(el){ + if(el.value.length) el.value += ', '; + el.value += addrs; + } + } +} + +function validateAddressField(o){ + if(YAHOO.alpine.expandaddress){ + if(o.value.length) expandAddress({addrs:o.value,fieldId:o.id}); + } + return(false); +} + +function pickContact(fieldName, fieldId, objParm, markUp){ + var dom = YAHOO.util.Dom; + var alp = YAHOO.alpine.pickcontact; + if (alp.markup){ + var div = document.createElement('div'); + div.innerHTML = alp.markup; + document.body.appendChild(div); + + var contactDialog = document.getElementById('contactDialog'); + if(contactDialog){ + alp.tabs = new YAHOO.widget.TabView('contactDialog'); + alp.tabs.subscribe('activeTabChange', + function(e){ + if(alp.tabs.getTabIndex(e.newValue) == 1){ + boxChecked(null); // set action button + var el = document.getElementById('dirQuery'); + el.focus(); + el.select(); + } + }); + } + else contactDialog = document.getElementById('contactList'); + + var objDone = { + label:'Add ' + fieldName + ' Address', + disabled: true, + fn: function(){ donePickContact(fieldId); }, + doonreturn:true + }; + + panelDialog('Add ' + fieldName + ' Address', contactDialog, objDone); + setPanelBodyWidth('clistContacts'); + drawContactList('contactList',0,objParm); + } + + return false; +} + + +function drawLDAPResult(objResult){ + var dom = YAHOO.util.Dom; + var el = document.getElementById('dirResult'); + if(el){ + var elResult; + if(objResult.error){ + elResult = document.createElement('span'); + elResult.innerHTML = objResult.error; + } + else if(objResult.results){ + var o, n, t, qrPers, elTR, elTD, elCB, resId, elLabel; + elResult = document.createElement('table'); + elResult.setAttribute('width','100%'); + elResult.setAttribute('cellSpacing','0'); + elResult.setAttribute('cellPadding','0'); + for(var i = 0; i < objResult.results.length; i++){ + o = objResult.results[i]; + n = (o.email) ? o.email.length : 0; + if(n){ + elTR = elResult.insertRow(elResult.rows.length); + elTD = elTR.insertCell(elTR.cells.length); + + elCB = createInputElement('checkbox','qrList'); + elCB.setAttribute('value',elResult.rows.length); + resId = 'dirEnt' + elResult.rows.length; + elCB.setAttribute('id',resId); + + YAHOO.util.Event.addListener(elCB,'click',boxClicked); + elTD.appendChild(elCB); + + elTD = elTR.insertCell(elTR.cells.length); + dom.addClass(elTD,'wap'); + if(o.personal){ + qrPers = o.personal; + } + else + qrPers = ''; + + elLabel = createNameValueElement('label','for',resId); + elTD.appendChild(elLabel); + elLabel.setAttribute('id','qrPers'+elResult.rows.length); + elLabel.innerHTML = o.personal; + + + for(var j = 0; j < n; j++){ + if(j > 0){ + elTR = elResult.insertRow(elResult.rows.length); + elTD = elTR.insertCell(elTR.cells.length); + elCB = createInputElement('checkbox','qrList'); + elCB.setAttribute('value',elResult.rows.length); + resId = 'dirEnt' + elResult.rows.length; + elCB.setAttribute('id',resId); + + YAHOO.util.Event.addListener(elCB,'click',boxClicked); + elTD.appendChild(elCB); + elTD = elTR.insertCell(elTR.cells.length); + dom.addClass(elTD,'wap'); + + + elLabel = createNameValueElement('label','for',resId); + elTD.appendChild(elLabel); + elLabel.setAttribute('id','qrPers'+elResult.rows.length); + elLabel.innerHTML = qrPers; + } + elTD = elTR.insertCell(elTR.cells.length); + dom.addClass(elTD,'wap'); + + elLabel = createNameValueElement('label','for',resId); + elTD.appendChild(elLabel); + elLabel.setAttribute('id','qrAddr'+elResult.rows.length); + elLabel.innerHTML = o.email[j]; + } + } + } + } + + el.replaceChild(elResult,el.firstChild); + el = document.getElementById('dirQuery'); + if(el) el.focus(); + } +} + +function boxClicked(e){ + boxChecked(YAHOO.util.Event.getTarget(e)); +} + +function boxClear(){ + var l = (YAHOO.alpine.pickcontact.tabs.get('activeIndex') == 0) ? 'nickList' : 'qrList'; + var el = document.getElementsByName(l); + if(el){ + for(var i = 0; i < el.length; i++) el[i].checked = false; + } + + panelDialogEnableButton(false); +} + +function boxChecked(o){ + if(o) markOne(o); + var l = (YAHOO.alpine.pickcontact.tabs.get('activeIndex') == 0) ? 'nickList' : 'qrList'; + var el = document.getElementsByName(l); + if(el){ + for(var i = 0; i < el.length; i++){ + if(el[i].checked){ + panelDialogEnableButton(true); + return; + } + } + } + + panelDialogEnableButton(false); +} + +function setPriority(elClick,priority){ + var el, pos, dom = YAHOO.util.Dom; + for(var i = 0; i <= 5; i++){ + el = document.getElementById('pri'+i); + if(dom.hasClass(el.firstChild,'spfcl3')){ + dom.removeClass(el.firstChild,'spfcl3'); + dom.addClass(el.firstChild,'blank'); + break; + } + } + + dom.removeClass(elClick.firstChild,'blank'); + dom.addClass(elClick.firstChild,'spfcl3'); + el = document.getElementById('priority'); + el.value = priority; + elClick.blur(); + return false; +} diff --git a/web/cgi/alpine/2.0/lib/contacts.js b/web/cgi/alpine/2.0/lib/contacts.js new file mode 100644 index 00000000..c4d13be1 --- /dev/null +++ b/web/cgi/alpine/2.0/lib/contacts.js @@ -0,0 +1,121 @@ +/* $Id: contacts.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +function boxChecked(o){ + if(o) markOne(o); +} + +function editContact(o){ + getContact({ book:o.book, index:o.index, f:function(c){ contactEditor(c,storeEditedContact); }}); + return(false); +} + +function editCheckedContact(){ + var checked = contactsChecked(''); + switch (checked.length){ + case 1 : + getContact({ book:checked[0].book, index:checked[0].index, f:function(c){ contactEditor(c,storeEditedContact); }}); + break; + default : + panelAlert('Choose just one contact to Edit'); + case 0 : + break; + } + + return(false); +} + +function contactDelete(){ + var checked = contactsChecked(''); + var plural = (checked.length > 1) ? 's' : ''; + var count = (checked.length > 1) ? '<b>' + checked.length + '</b> ' : ''; + if(checked.length) panelConfirm('Are you sure you want to permanently delete the ' + count + 'selected contact' + plural + '?',{text:'Delete Forever',fn:doContactDelete}); + return false; +} + +function doContactDelete(o){ + var checked = contactsChecked(''); + if(checked.length){ + var el = YAHOO.alpine.containers.contactlist; + var elist = ''; + for(var i = 0; i < checked.length; i++){ + if(elist.length) elist += ','; + elist += checked[i].book + '.' + checked[i].index; + } + + if(el && elist.length){ + var o = { + hdr:'on', + sendto:'on', + canedit:'on', + op:'delete', + entryList:elist + } + + newContactList(el,null,gCurrentAbook,o); + } + } +} + +function storeEditedContact(oFields){ + var el = YAHOO.alpine.containers.contactlist; + if(el){ + var o = { + hdr:'on', + sendto:'on', + canedit:'on', + op:'change' + } + + for(var f in oFields){ + o[f] = oFields[f]; + } + + newContactList(el,null,gCurrentAbook,o); + } +} + +function storeNewContact(oFields){ + var el = YAHOO.alpine.containers.contactlist; + if(el){ + var o = { + hdr:'on', + sendto:'on', + canedit:'on', + op:'add' + } + + for(var f in oFields){ + o[f] = oFields[f]; + } + + newContactList(el,null,gCurrentAbook,o); + } +} + +function sendToContact(){ + var checked = contactsChecked('Send Email'); + if(checked.length){ + var cUrl = 'compose?contacts='; + var comma = ''; + for(var i = 0; i < checked.length; i++){ + cUrl += comma + checked[i].book + '.' + checked[i].index; + comma = ','; + } + + window.location.href = cUrl; + } + + return(false); +} diff --git a/web/cgi/alpine/2.0/lib/folders.js b/web/cgi/alpine/2.0/lib/folders.js new file mode 100644 index 00000000..4f6b9d24 --- /dev/null +++ b/web/cgi/alpine/2.0/lib/folders.js @@ -0,0 +1,258 @@ +/* $Id: folders.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +function doOpen(){ + var fce = document.getElementById('pickFolderCollection'); + var fc = (fce) ? fce.value : null; + var fpe = document.getElementById('pickFolderPath'); + var fp = (fpe && fpe.value && fpe.value.length) ? '/' + fpe.value + '/' : '/'; + var fne = document.getElementById('pickFolderName'); + var fn = (fne && fne.value && fne.value.length) ? fne.value : null; + if(fc && fp && fn) location.href = 'browse/'+ fc + fp + encodeURIComponent(fn); + else panelAlert('Which folder would you like to View?<p>Click a folder\'s name to select it, then click <b>View Messages</b>.'); + return false; +} + +function doDelete(o){ + var el = document.getElementById('alpineContent'); + newFolderList(el,null,o.c,o.path,{op:'delete',f:o.folder}); + var fne = document.getElementById('pickFolderName'); + if(fne) fne.value = ''; + var base, link; + if((base = document.getElementsByTagName('base')) && base.length) link = base[0].getAttribute('href'); + else link = ''; + link += 'browse/'+o.c+'/'+o.path+encodeURIComponent(o.folder); + for(var i = 0; i < 20 ; i++){// 20 > fldr_cache_max + var target = 'target' + i; + el = document.getElementById(target); + if(!el) break; + if(el.firstChild.href == link){ + YAHOO.util.Dom.setStyle(target,'display','none'); + break; + } + } +} + +function queryDelete(){ + if(YAHOO.alpine.current.incoming){ + showStatusMessage('Cannot delete Incoming Folders yet',5); + return false; + } + + var fc = document.getElementById('pickFolderCollection').value; + var fp = document.getElementById('pickFolderPath').value; + var fn = document.getElementById('pickFolderName').value; + if(fn.length) panelConfirm('Are you sure you want to permanently delete the folder <b>' + fn + '</b> and its contents?<p>Deleted folders are gone forever.',{text:'Delete Forever',fn:doDelete,args:{c:fc,path:fp,folder:fn}}); + else panelAlert('Which folder would you like to Delete?<p>Click a folder\'s name to select it, then click <b>Delete</b>.'); + + return false; +} + +function addFolder(){ + if(YAHOO.alpine.current.incoming){ + showStatusMessage('Cannot add new Incoming Folders yet',5); + return false; + } + + var dom = YAHOO.util.Dom; + var fp = document.getElementById('pickFolderPath').value; + var fc = document.getElementById('pickFolderCollection').value; + if(fc >= 0){ + var dbody = document.createDocumentFragment(); + var div = document.createElement('div'); + dom.addClass(div,'panelExplanation'); + var lc = 'in', l = 'Name of Folder to create. To create the folder within a subdirectory, simply prepend the subdirectory\'s name.'; + var el = document.createTextNode(l); + div.appendChild(el); + dbody.appendChild(div); + + // Folder Name + div = document.createElement('div'); + dom.addClass(div,'panelInput'); + div.innerHTML = 'Folder Name:'; + var input = createInputElement('text',''); + div.appendChild(input); + YAHOO.util.Event.addListener(input,'keyup',panelDialogInputChange); + dbody.appendChild(div); + panelDialog('New Folder', + dbody, + { + label:"New Folder", + disabled: true, + doonreturn: true, + fn: function(){ + if(input.value.length) newFolderList(document.getElementById('alpineContent'),null,fc,fp,{op:'add',f:input.value}); + else showStatusMessage('No folder name provided. No folder added.',5); + var fne = document.getElementById('pickFolderName'); + if(fne) fne.value = ''; + } + }); + input.focus(); + } + + return false; +} + +function renameFolder(){ + if(YAHOO.alpine.current.incoming){ + showStatusMessage('Cannot rename Incoming Folders yet',5); + return false; + } + + var dom = YAHOO.util.Dom; + var fc = document.getElementById('pickFolderCollection').value; + var fp = document.getElementById('pickFolderPath').value; + var fn = document.getElementById('pickFolderName').value; + if(fc >= 0 && fn.length){ + var dbody = document.createDocumentFragment(); + var div = document.createElement('div'); + dom.addClass(div,'panelExplanation'); + var lc = 'in', l = 'Rename folder '; + if(fp.length){ + l += 'in directory ' + fp + ' '; + lc = 'of'; + } + if(YAHOO.alpine.current.collections[fc]) l += lc+' collection ' + YAHOO.alpine.current.collections[fc]; + div.innerHTML = l; + dbody.appendChild(div); + + // Folder Name Input + div = document.createElement('div'); + dom.addClass(div,'panelInput'); + div.innerHTML = 'New Folder Name:'; + + var input = createInputElement('text',''); + var fnt = fn.match(/[\/]?([^\/]*)$/); + input.setAttribute('value',fnt[1]); + div.appendChild(input); + + //YAHOO.util.Event.addListener(el,'keyup',panelDialogInputChange); + dbody.appendChild(div); + + panelDialog('Rename Folder', + dbody, + { + label:"Rename Folder", + doonreturn: true, + fn: function(){ + if(fc >= 0 && fn.length && input.value.length){ + if(fn != input.value){ + var el = document.getElementById('alpineContent'); + newFolderList(el,null,fc,fp,{op:'rename',sf:fn,df:input.value}); + var fne = document.getElementById('pickFolderName'); + if(fne) fne.value = ''; + } + else showStatusMessage('Folder name unchanged.',5); + } + else showStatusMessage('Folder name unchanged.',5); + } + }); + + input.select(); + } + else panelAlert('Which folder would you like to rename?<p>Click a folder\'s name to select it, then click <b>Rename</b>.'); + + return false; +} + +function exportFolder(){ + var dom = YAHOO.util.Dom; + var fc = document.getElementById('pickFolderCollection').value; + var fp = document.getElementById('pickFolderPath').value; + var fn = document.getElementById('pickFolderName').value; + var t; + if(fc >= 0 && fn.length){ + var url = 'conduit/export/' + fc + '/'; + if(fp.length) url += encodeURIFolderPath(fp) + '/'; + url += encodeURIComponent(fn); + window.location.href = document.getElementsByTagName('base')[0].href + url; + t = '<h3>Export Email</h3>Web Alpine is preparing folder <b>'+fn+'</b> for download. '; + t += 'Your browser\'s File Open dialog should appear momentarily.<p>'; + t += 'The exported file will be in a format compatible with many desktop mail programs. '; + t += 'You can also use <i>Import Email</i> to copy the folder back into Web Alpine.<p>'; + t += 'If the download completes without error, you may delete the folder from Web Alpine.<p>'; + } + else + t = 'Which folder would you like to export?<p>Click a folder\'s name to select it, then click <b>Export Email...</b>.' + + panelAlert(t); + return false; +} + +function redrawFolderList(){ + var fc = document.getElementById('pickFolderCollection').value; + var fp = document.getElementById('pickFolderPath').value; + if(fc >= 0){ + var el = document.getElementById('alpineContent'); + newFolderList(el,null,fc,fp,{op:'noop'}); + } +} + +function importFolder(){ + if(YAHOO.alpine.current.incoming){ + showStatusMessage('Cannot import Incoming Folders yet',5); + return false; + } + + var dom = YAHOO.util.Dom; + var event = YAHOO.util.Event; + var fc = document.getElementById('pickFolderCollection').value; + var fp = document.getElementById('pickFolderPath').value; + var form = document.createElement('form'); + form.setAttribute('action','conduit/import/' + fc + '/' + encodeURIFolderPath(fp)); + form.setAttribute('method','POST'); + form.setAttribute('enctype','multipart/form-data'); + form.setAttribute('target','formResponse'); + + var div = document.createElement('div'); + dom.addClass(div,'panelExplanation'); + div.innerHTML = 'Folder Import copies a mail folder, typically created by the <i>Export</i> command, from the computer your browser is running on into a new Web Alpine folder. Successful Import consists of three steps.<p>First, enter the path and filename of the folder below. Use the Browse button to help choose the file.'; + form.appendChild(div); + + div = document.createElement('div'); + dom.addClass(div,'panelInput'); + var input0 = createInputElement('file','file'); + event.addListener(input0,'keypress',panelDialogInputChange); + event.addListener(input0,'change',panelDialogInputChange); + div.appendChild(input0); + form.appendChild(div); + + div = document.createElement('div'); + div.innerHTML = 'Second, provide a <b>unique</b> name to give the uploaded folder'; + if(YAHOO.alpine.current.collections[fc]) div.innerHTML += ' within the '+ YAHOO.alpine.current.collections[fc]+' collection.'; + dom.addClass(div,'panelExplanation'); + form.appendChild(div); + + div = document.createElement('div'); + dom.addClass(div,'panelInput'); + div.innerHTML = 'Name the folder:'; + var input = createInputElement('text','newFolder'); + div.appendChild(input); + form.appendChild(div); + + div = document.createElement('div'); + div.innerHTML = 'Finally, click <b>Import Folder</b> to copy the folder into Web Alpine.'; + dom.addClass(div,'panelExplanation'); + form.appendChild(div); + + + panelDialog('Import Folder', form, + { + label:'Import Folder', + disabled: true, + fn: function(){ showLoading(); form.submit(); } + }); + input0.focus(); + return false; +} diff --git a/web/cgi/alpine/2.0/lib/mailbox.js b/web/cgi/alpine/2.0/lib/mailbox.js new file mode 100644 index 00000000..9879137f --- /dev/null +++ b/web/cgi/alpine/2.0/lib/mailbox.js @@ -0,0 +1,1076 @@ +/* $Id: mailbox.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* + * Scripts common to mailbox viewing: browse and view + */ + +// Globals +YAHOO.alpine.morcButton = []; +YAHOO.alpine.select = { all:false, bannerId:'bannerSelection' }; + + +// BROWSE FUNCTIONS + +/* priority column display is overloaded. Uses el.title to store state. */ +/* changes to link titles in that column MUST be coordinated with this stuff. */ +/* Tricky */ +var gLabelStarred = 'Starred'; +var gLabelPriHi = 'High Priority'; +var gLabelPriHier = 'Highest Priority'; + + +function applyFlag(ctrlObj,flagName,flagState) { + switch (flagName) { // validate + case 'new' : break; // read (New) flag + case 'imp' : break; // important flag + case 'del' : break; // delete flag + default : return false; + } + YAHOO.util.Connect.asyncRequest('GET', + 'conduit/apply.tcl' + encodeURI('?u=all&f=' + flagName + '&s=' + flagState) + urlSalt('&'), + { + customevents: { + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success: function(o) { + // valid response is "<numApplied> <numSelected> <numTotalMsgs>" + var matchResult; + if((matchResult = o.responseText.match(/^(\d+) (\d+) (\d+)$/m)) == null){ + showStatusMessage('Error: ' + o.responseText, 10); + } + else{ + var plural = (matchResult[1] > 1) ? 's' : ''; + if(flagName == 'del'){ + showStatusMessage(matchResult[1] + ' message' + plural + ' deleted', 3); + YAHOO.alpine.current.selected = matchResult[2]; + YAHOO.alpine.current.count = matchResult[3]; + hideSelectAllInfo(); + } + else{ + var chk = document.getElementsByName('uidList'); + var sm; + if(flagName == 'imp'){ + var act = (flagState == 'not') ? 'Cleared' : 'Set'; + sm = act + ' Star on ' + matchResult[1] + ' message' + plural; + } + else{ + sm = 'Marked ' + matchResult[1] + ' message' + plural + ' as '; + if(flagState == 'not'){ + decUnreadCount('Current' ,matchResult[1]); + sm += 'Read'; + } + else{ + incUnreadCount('Current',matchResult[1]); + sm += 'Unread'; + } + } + showStatusMessage(sm, 3); + for(var i = 0; i < chk.length; i++){ + if(chk[i].checked){ + var dom = YAHOO.util.Dom; + if(flagName == 'imp'){ + var offset = 0; + var m = document.getElementById('star'+chk[i].value); + if(m){ + var classAdd = '', classDel = '', newtitle = ''; + if(flagState == 'not'){ + classAdd = 'nostar'; + classDel = 'star'; + if(m.title.substr(0,gLabelStarred.length) == gLabelStarred){ + if(m.title.length > gLabelStarred.length){ + newtitle = m.title.substr(gLabelStarred.length + 5); + if(newtitle == gLabelPriHi){ + classAdd = 'prihi'; + } + else if(newtitle == gLabelPriHier){ + classAdd = 'prihier'; + } + } + else{ + newtitle = 'Set ' + gLabelStarred; + } + } + } + else{ + classAdd = 'star'; + switch (m.title) { + case 'Set ' + gLabelStarred : + newtitle = gLabelStarred; + classDel = 'nostar'; + break; + case gLabelPriHi : + classDel = 'prihi'; + newtitle = gLabelStarred + ' and ' + gLabelPriHi; + break; + case gLabelPriHier : + classDel = 'prihier'; + newtitle = gLabelStarred + ' and ' + gLabelPriHier; + break; + default : + break; + } + } + + if(!dom.hasClass(m.firstChild,classAdd)) dom.addClass(m.firstChild,classAdd); + if(classDel.length && dom.hasClass(m.firstChild,classDel)) dom.removeClass(m.firstChild,classDel); + if(newtitle.length) m.title = newtitle; + } + } + else if(flagName == 'new'){ + var hid = 'h1'+chk[i].value; + var mnode = chk[i].parentNode.parentNode; + if(flagState == 'not'){ + if(dom.hasClass(hid,'unread')) dom.removeClass(hid,'unread'); + if(dom.hasClass(mnode,'unread')) dom.removeClass(mnode,'unread'); + } + else{ + if(!dom.hasClass(hid,'unread')) dom.addClass(hid,'unread'); + if(!dom.hasClass(mnode,'unread')) dom.addClass(mnode,'unread'); + } + } + } + } + showSelectAllInfo(); + } + } + }, + failure: function(o) { showStatusMessage('Request Failure: ' + o.statusText + '. Please report this.', 10)} + }); + + if(ctrlObj) ctrlObj.blur(); + return false; +} + + +// +// SELECTION (e.g. SELECT ALL) +// + +function initSelection() { + var ac = YAHOO.alpine.current; + if (ac.selected > 0) { + if (ac.selected == ac.count) { + showSelectAllInfo(4); + } else if (ac.selected) { + showSelectAllInfo(2); + } + } + else hideSelectAllInfo(); +} + +function hideSelectAllInfo() { + var banner = document.getElementById(YAHOO.alpine.select.bannerId); + if(banner) YAHOO.util.Dom.setStyle(banner,'display','none'); +} + +function showSelectAllInfo(num) { + var banner = document.getElementById(YAHOO.alpine.select.bannerId); + if (banner){ + setSelectAllInfoText(num); + YAHOO.util.Dom.setStyle(banner,'display','block'); + } +} + +function setSelectAllInfoText(state) { + // NOTE: "\u00a0" is the unicode equivalent of no-break space character + var ac = YAHOO.alpine.current; + var banner = document.getElementById(YAHOO.alpine.select.bannerId); + if (!banner) return; + var msg; + var pluralSelected = (ac.selected > 1) ? 's' : ''; + var predSelected = (ac.selected > 1) ? 'are' : 'is'; + var pluralTotal = (ac.count > 1) ? 's' : ''; + var groupName = (ac.focused) ? 'Search Results' : ac.f; + switch (state) { + case 1: + banner.innerHTML = "All <b>" + ac.selected + "<\/b> message" + pluralSelected + " in " + groupName + " " + predSelected + " selected."; + banner.style.backgroundColor = "#ffffa6"; + break; + case 2: + banner.innerHTML = "<b>" + ac.selected + "<\/b> message" + pluralSelected + " in " + groupName + " " + predSelected + " selected. \u00a0\u00a0\u00a0\u00a0\u00a0 [<a href='browse/" + ac.c + "/" + ac.f + "/" + ac.u + "?select=all' onClick='return selectAllInFolder();'>Select All <b>" + ac.count + " <\/b> Message" + pluralTotal + " in " + groupName + "<\/a>] \u00a0\u00a0 [<a href='browse/" + ac.c + "/" + ac.f + "/" + ac.u + "?select=none' onClick='return unSelectAllInFolder();'>Unselect All<\/a>]"; + banner.style.backgroundColor = "#ffffa6"; + break; + case 3: + banner.innerHTML = "All <b>" + ac.selected + "<\/b> message" + pluralSelected + " on this page " + predSelected + " selected. \u00a0\u00a0\u00a0\u00a0\u00a0 [<a href='browse/" + ac.c + "/" + ac.f + "/" + ac.u + "?select=all' onClick='return selectAllInFolder();'>Select All <b>" + ac.count + " <\/b> Message" + pluralTotal + " in " + groupName + "<\/a>]"; + banner.style.backgroundColor = "#ffffa6"; + break; + case 4: + banner.innerHTML = "<b>All <u>" + ac.count + "<\/u> message" + pluralTotal + " in " + groupName + " " + predSelected + " selected.<\/b> \u00a0\u00a0\u00a0\u00a0\u00a0 [<a href='browse/" + ac.c + "/" + ac.f + "/" + ac.u + "?select=none' onClick='return unSelectAllInFolder();'>Unselect All<\/a>]"; + banner.style.backgroundColor = "#ffdebf"; + break; + case 5: + banner.innerHTML = "<b>Selection Cleared - No messages selected in " + groupName + ".<\/b>"; + banner.style.backgroundColor = "#ffdebf"; + break; + } +} + + +function markMessage(msg) { + var ac = YAHOO.alpine.current; + var chk = document.getElementsByName('uidList'); + var selectAll = document.getElementById('selectall'); + var numCheckbox = isNaN(chk.length) ? 1 : chk.length; + msg.parentNode.parentNode.id = msg.checked ? "sd" : ""; + if (YAHOO.alpine.select.all) { + YAHOO.alpine.select.all = false; + } + if (!msg.checked) { + --ac.selected; + if (ac.selected) { + setSelectAllInfoText(2); + } else { + hideSelectAllInfo(); + } + selectAll.checked = false; + } else { + ++ac.selected; + if (ac.count <= numCheckbox) { + setSelectAllInfoText(1); + } else { + setSelectAllInfoText(2); + } + } + updateMessageState(msg.value, msg.checked); +} + +function markAllMessages() { + var ac = YAHOO.alpine.current; + var chk = document.getElementsByName('uidList'); + var isChecked = document.getElementById('selectall').checked; + var numChanged = 0; + var numCheckbox; + var markedUidList = ''; + if (chk) { + hideDisplayDivOrSpan("bannerConfirm"); // remove any confirmation banner from page + numCheckbox = isNaN(chk.length) ? 0 : chk.length; + var selectedClass = isChecked ? "sd" : ""; + for (var i = 0; i < numCheckbox; i++) { + if (chk[i].checked != isChecked) { + ++numChanged; + } + chk[i].checked = isChecked; + chk[i].parentNode.parentNode.id = selectedClass; + markedUidList += ',' + chk[i].value; + } + + if (isChecked) { // if Select all + ac.selected += numChanged; + if (ac.selected > numCheckbox) { + showSelectAllInfo(2); + } else if (ac.count > numCheckbox) { + showSelectAllInfo(3); + } + } else { // if UNselect all + ac.selected -= numChanged; + if (ac.selected) { + showSelectAllInfo(2); + } else { + hideSelectAllInfo(); + } + } + updateMessageState(markedUidList, isChecked); + } +} + +function selectAllInFolder() { + var alp = YAHOO.alpine; + var chk = document.getElementsByName('uidList'); + document.getElementById('selectall').checked = true; + var numCheckbox; + if (chk) { + hideDisplayDivOrSpan("bannerConfirm"); // remove any confirmation banner from page + numCheckbox = isNaN(chk.length) ? 1 : chk.length; + if (numCheckbox == 1) { + chk.checked = true; + chk.parentNode.parentNode.id = "sd"; + } else { + for (var i = 0; i < chk.length; i++) { + chk[i].checked = true; + chk[i].parentNode.parentNode.id = "sd"; + } + } + + var all = (alp.current.focused) ? 'searched' : 'all'; + alp.current.selected = (alp.current.focused) ? alp.current.focused : alp.current.count; + updateMessageState(all,'true'); + } + showSelectAllInfo(4); + YAHOO.alpine.select.all = (alp.current.focused == 0); + return false; +} + +function unSelectAllInFolder() { + var alp = YAHOO.alpine; + var chk = document.getElementsByName('uidList'); + var numCheckbox; + if (chk) { + numCheckbox = isNaN(chk.length) ? 1 : chk.length; + YAHOO.alpine.current.selected = 0; + // setSelectAllInfoText(5); + document.getElementById('selectall').checked = false; + if (numCheckbox == 1) { + chk.checked = false; + chk.parentNode.parentNode.id = ""; + } else { + for (var i = 0; i < chk.length; i++) { + chk[i].checked = false; + chk[i].parentNode.parentNode.id = ""; + } + } + + var all = (alp.current.focused) ? 'searched' : 'all'; + alp.select.all = false; + updateMessageState(all,'false'); + } + hideSelectAllInfo(); + return false; +} + +function numCheckedOnPage() { + var chk = document.getElementsByName('uidList'); + var numCheckbox; + var numChecked=0; + if (chk) { + numCheckbox = isNaN(chk.length) ? 1 : chk.length; + if ((numCheckbox==1) && (chk.checked)) { + numChecked = 1; + } else { + for (var i = 0; i < chk.length; i++) { + if (chk[i].checked) { + ++numChecked; + } + } + } + } + + return numChecked; +} + + +// Communicate state changes to server +function updateMessageState(u,m){ + YAHOO.util.Connect.asyncRequest('GET', + 'conduit/mark.tcl' + encodeURI('?u=' + u + '&mark=' + m) + urlSalt('&'), + { + success: function(o) {}, + failure: function(o) { + newStatusMessage('Request Failure: ' + o.statusText); + } + }); +} + +// Mailbox Search +function mailboxSearch(){ + var elField = document.getElementById('searchField'); + if(elField && elField.value && elField.value.length){ + var elScope = document.getElementById('searchScope'); + var scope = (elScope) ? elScope.options[elScope.selectedIndex].value : 'new'; + newMessageList({parms:{op:'search',type:'any',scope:scope,criteria:elField.value}}); + } +} + +// Confirm Toolbar Actions based on Selection +function confirmDelete() { + var ac = YAHOO.alpine.current; + var plural = (ac.selected > 1) ? 's' : ''; + if (ac.selected != numCheckedOnPage()) + panelConfirm("Move " + ac.selected + " message" + plural + " from " + ac.f + " to the Trash?<p>Some selected messages are on other pages.",{fn:actuallyDelete},'Delete'); + else + actuallyDelete(); + + return(false); +} + +function confirmSpam() { + var ac = YAHOO.alpine.current; + var plural = (ac.selected > 1) ? 's' : ''; + if (ac.selected != numCheckedOnPage()) + panelConfirm("Report " + ac.selected + " message" + plural + " as Spam?<p>Some selected messages are on other pages.",{fn:actuallySpam},'Report Spam'); + else + actuallySpam(); + + return(false); +} + +// Confirm Toolbar Actions based on Selection +function deleteForeverString() { + if (YAHOO.alpine.current.selected != numCheckedOnPage()) { + return confirm( + " forever?\nSome selected messages are on other pages."); + } + + return(YAHOO.alpine.current.selected > 0); +} + +// Complain if no messages are selected for Toolbar Action +function anySelected(act) { + if (YAHOO.alpine.current.selected <= 0){ + panelAlert('No messages selected to ' + act + '.<p>Select one or more messages by checking the box on the line of each desired message.'); + return false; + } + + return true; +} + +function flipStar(el) { + var dom = YAHOO.util.Dom; + var u = el.id.substring(4); + var flagState = '', iClass = '', iTitle = '', iUnClass = ''; + if(el.title.substr(0,7) == gLabelStarred){ + flagState = 'not'; + iUnClass = 'star'; + if(el.title.length > 7){ + switch (el.title.substr(12)){ + case gLabelPriHi : + iClass = 'prihi'; + iTitle = gLabelPriHi; + break; + case gLabelPriHier : + iClass = 'prihier'; + iTitle = gLabelPriHier; + break; + default : + return false; + } + } + else{ + iClass = 'nostar'; + iTitle = 'Set '+ gLabelStarred; + } + } + else{ + flagState = 'ton'; + iClass = 'star'; + switch(el.title){ + case 'Set ' + gLabelStarred : + iUnClass = 'nostar'; + iTitle = gLabelStarred; + break; + case gLabelPriHi : + iUnClass = 'prihi'; + iTitle = gLabelStarred + ' and ' + gLabelPriHi; + break; + case gLabelPriHier : + iUnClass = 'prihier'; + iTitle = gLabelStarred + ' and ' + gLabelPriHier; + break; + default : return false; + } + } + + setStar(u,flagState,function(){ if(iTitle.length) el.title = iTitle; if(iUnClass.length) dom.removeClass(el.firstChild,iUnClass); dom.addClass(el.firstChild,iClass); }); + return false; +} + +function setStar(u,flagState,onDone){ + if(u < 0) u = YAHOO.alpine.current.u; + YAHOO.util.Connect.asyncRequest('GET', + 'conduit/flag.tcl?u=' + u + '&f=imp&s=' + flagState + urlSalt('&'), + { + success: function(o) { if(onDone) onDone(); }, + failure: function(o) { showStatusMessage('Request Failure: ' + o.statusText + '. Please report this.', 10)} + }); + return false; +} + +// replace message list/view text +function updateDivText(div, url){ + YAHOO.util.Connect.asyncRequest('GET', url, + { + customevents:{ + onStart:function(eventType){ showLoading(); }, + onComplete:function(eventType){ hideLoading(); } + }, + success:function(aro){ + div.innerHTML = aro.responseText; + div.scrollTop = 0; + evalScripts(aro.responseText); + }, + failure: function(aro) { showStatusMessage('Request Failure: ' + aro.statusText, 10) }, + argument: [div] + }); + return false; +} + +// Load next message list for viewing relative to current list +function newMessageList(o){ + var div = document.getElementById('alpineContent'); + if(div){ + var url = 'newlist.tcl/' + YAHOO.alpine.current.c + '/' + encodeURIFolderPath(YAHOO.alpine.current.f); + var conj = '?'; + if(o && o.parms){ + for(var prop in o.parms){ + url += conj + prop + '=' + encodeURIComponent(o.parms[prop]); + conj = '&'; + } + } + else{ + url += '?op=noop'; + conj = '&'; + } + + url += urlSalt(conj); + + updateDivText(div, url); + + if(o && o.control && o.control.blur) o.control.blur(); + } + return false; +} + +function actuallyDelete() +{ + if(numCheckedOnPage()) newMessageList({parms:{'op':'delete'}}); + else applyFlag(null,'del','ton'); +} + +function actuallySpam() +{ + newMessageList({parms:{'op':'spam'}}); +} + +function doEmpty(ctrlObj,listOption){ + if(listOption == 'all'){ + newMessageList({control:ctrlObj,parms:{'op':'trashall'}}); + } + else if(listOption == 'message'){ + newMessageText({control:ctrlObj,parms:{op:'trash'}}); + } + else{ + var ac = YAHOO.alpine.current; + if(listOption == 'selected' && anySelected('Delete Forever')){ + var plural = (ac.selected > 1) ? 's' : ''; + var t = "Delete " + ac.selected + " message" + plural + " from " + ac.f + ' forever?'; + if(ac.selected != numCheckedOnPage()) t += '<p>Some selected messages are on other pages.'; + panelConfirm(t, + { + text:'Delete Forever', + fn:function(){ newMessageList({control:ctrlObj,parms:{'op':'trash'}}); } + }); + } + } + + if(ctrlObj) ctrlObj.blur(); + return false; +} + +function doSpam(ctrlObj){ + if(anySelected('Report as Spam')) confirmSpam(); + if(ctrlObj) ctrlObj.blur(); + return false; +} + +// Drag Drop Support +function hiliteDrop(id,on){ + var dom = YAHOO.util.Dom; + if(on){ + if(!dom.hasClass(id,'drop')) + dom.addClass(id, 'drop'); + + if(dom.hasClass(id + 'Icon','splc5')){ + dom.removeClass(id + 'Icon','splc5'); + dom.addClass(id + 'Icon','splc10'); + } + else if(dom.hasClass(id + 'Icon','splc7')){ + dom.removeClass(id + 'Icon','splc7'); + dom.addClass(id + 'Icon','splc11'); + } + } + else{ + if(dom.hasClass(id,'drop')) + dom.removeClass(id, 'drop'); + + if(dom.hasClass(id + 'Icon','splc10')){ + dom.removeClass(id + 'Icon','splc10'); + dom.addClass(id + 'Icon','splc5'); + } + else if(dom.hasClass(id + 'Icon','splc11')){ + dom.removeClass(id + 'Icon','splc11'); + dom.addClass(id + 'Icon','splc7'); + } + } +} + +function dragOntoFolder(uid,o){ + newMessageList({parms:{'op':'movemsg','df':o.c+'/'+o.f,'uid':uid}}); + return false; +} + +function canDragit(id,uid,tt){ + var dom = YAHOO.util.Dom; + var dd = new YAHOO.util.DDProxy(id, + 'message', + { + dragElId:'msgDragProxy', + resizeFrame: false + }); + dd.isTarget = false; + dd.b4MouseDown = function(e){ + var s = '<b>' + this.getEl().innerHTML + '</b>'; + var r = dom.getRegion(this.getEl()); + var w = r.right - r.left; + var el = document.getElementById('ml'+uid); + r = dom.getRegion(el); + w = Math.max(w, (r.right - r.left)); + if(el && el.innerHTML.length) s += '<br>' + el.innerHTML; + el = document.getElementById('msgDragProxyText'); + el.innerHTML = s; + dom.setStyle('msgDragProxy','width',w + 12); + return true; + }; + dd.endDrag = function(){ + dom.setStyle('msgDragProxy','visibility','hidden') + }; + dd.onDragEnter = function(e,id){ hiliteDrop(id,true); }; + dd.onDragOut = function(e,id){ hiliteDrop(id,false); }; + dd.onDragDrop = function(e,id){ + hiliteDrop(id,false); + var o = dom.get(id); + if(o) o.f(uid,o.args); + } + if(tt){ + dd.onMouseDown = function(e){ + tt.hide(); + tt.cfg.setProperty('disabled',true); + }; + dd.onMouseUp = function(e){ + tt.cfg.setProperty('disabled',false); + }; + } +} + +function setDragTarget(id,fHandler,oArgs){ + if(id && id.length){ + var o = document.getElementById(id); + if(o){ + o.ddObj = new YAHOO.util.DDTarget(id,'message'); + o.f = fHandler; + o.args = oArgs; + } + } +} + +function cursor(style){ + document.body.style.cursor = style; +} + + +// VIEW FUNCTIONS + +function newMessageText(o){ + var div = document.getElementById('alpineContent'); + var ac = YAHOO.alpine.current; + if(div){ + var uid = (o.uid) ? o.uid : ac.u; + var url = 'newview.tcl/' + ac.c + '/' + encodeURIFolderPath(ac.f) + '/' + uid; + var conj = '?'; + if(o && o.parms){ + for(var prop in o.parms){ + url += conj + prop + '=' + encodeURIComponent(o.parms[prop]); + conj = '&'; + } + } + + updateDivText(div, url); + + if(o && o.control && o.control.blur) o.control.blur(); + } + return false; +} + +// Move or Copy support + +function initMorcButton(morcButton){ + if(YAHOO.alpine.morcButton[morcButton] == null){ + YAHOO.alpine.morcButton[morcButton] = new YAHOO.widget.Button({ + type:'menu', + label:'Move', + id:morcButton+'Choice', + menu:[{ text:'Copy', value:'morc', onclick:{ fn:morcClick, obj:{morcButton:morcButton}} }], + container:morcButton + }); + } +} + +function morcWhich(morcButton){ + return YAHOO.alpine.morcButton[morcButton].get('label'); +} + +function morcClick(p_sType,p_aArgs,p_oItem){ + var morc, morcOpt; + var button = YAHOO.alpine.morcButton[p_oItem.morcButton]; + if('copy' == YAHOO.util.Event.getTarget(p_aArgs[0]).innerHTML.toLowerCase()){ + morc = 'Copy'; + morcOpt = 'Move'; + } + else{ + morc = 'Move'; + morcOpt = 'Copy'; + } + + button.set('label',morc); + button.getMenu().getItem(0).cfg.setProperty('text',morcOpt); +} + +function saveCacheClick(e,o){ + var event = YAHOO.util.Event; + event.getTarget(e).blur(); + o.onDone(o); + event.preventDefault(e); +} + +function updateSaveCache(p,c,f,dc,od,sca){ + var event = YAHOO.util.Event; + var li = document.getElementById(p+'SaveCache'); + if(li){ + var cn = li.childNodes; + var i, j, node, s = ''; + for(i = 0; i < cn.length && i < sca.length; i++){ + node = cn[i].childNodes[0]; + if(node.tagName.toLowerCase() == 'hr') break; + node.href = p + '/' + c + '/' + f + '?save=' + dc + '/' + sca[i].fv; + node.innerHTML = sca[i].fn.replace(/</g,'<'); + event.removeListener(node,'click'); + event.addListener(node,'click',saveCacheClick,{c:dc,f:sca[i].fv,onDone:od}); + } + for(j = i; j < sca.length; j++){ + var nli = document.createElement('li'); + var a = document.createElement('a'); + a.href = p + '/' + c + '/' + f + '?save=' + dc + '/' + sca[j].fv; + a.innerHTML = sca[j].fn.replace(/</g,'<'); + event.addListener(a,'click',saveCacheClick,{c:dc,f:sca[j].fv,onDone:od}); + nli.appendChild(a); + li.insertBefore(nli,cn[i++]); + } + } +} + + +// Move or Copy in mailbox list browse +function morcInBrowseDone(o){ + if(anySelected('Move or Copy')){ + var mvorcp = morcWhich('listMorcButton').toLowerCase(); + folderExists({c: o.c, + f: o.f, + onDone: function() { newMessageList({parms:{'op':mvorcp,'df':o.c+'/'+o.f}}) }, + cancel: function(){ + addStatusMessage(mvorcp + ' cancelled',4); + displayStatusMessages(); + } + }); + } + + return false; +} + +// Move or Copy in mailbox message view +function morcInViewDone(o){ + var mvorcp = morcWhich('viewMorcButton').toLowerCase(); + folderExists({c: o.c, + f: o.f, + onDone: function() { newMessageText({parms:{'op':mvorcp,'df':o.c+'/'+o.f}}); }, + cancel: function(){ + addStatusMessage(mvorcp + ' cancelled',4); + displayStatusMessages(); + } + }); + + return false; +} + +function takeAddress(){ + var dom = YAHOO.util.Dom; + var dbody = document.createDocumentFragment(); + var div = document.createElement('div'); + dbody.appendChild(div); + dom.addClass(div,'takeInstructions'); + div.innerHTML = 'Choose extracted addresses and save to a new Contact' + + div = document.createElement('div'); + dbody.appendChild(div); + div.setAttribute('id','takeList'); + dom.addClass(div,'takeList'); + div.innerHTML = 'Loading...'; + + panelDialog('Extract Addresses', + dbody, + { + buttonId:'butChoose', + label:'Add to Contacts', + disabled: true, + doonreturn: true, + fn: function(){ + var o = { which:'add', nickname:'', personal:'', email:'', note:'', fcc:'' }; + var l = document.getElementsByName('taList'); + if(l){ + var i, el; + for(i = 0; i < l.length; i++){ + if(l[i].checked){ + if(o.email.length){ + o.email += ',\n'; + o.group = true; + } + el = document.getElementById('taPers'+l[i].value); + if(el){ + var specials = el.innerHTML.match(/[()<>@,;:\\\".\[\]]/); + if(specials) o.email += '"' + el.innerHTML + '"'; + else o.email += el.innerHTML; + } + el = document.getElementById('taEmail'+l[i].value); + if(el) o.email += ' <' + el.innerHTML + '>'; + } + } + + contactEditor(o); + } + } + }); + + setPanelBodyWidth('takeList'); + drawExtractedAddresses(div); + return false; +} + +function drawExtractedAddresses(elContainer){ + var takeDS = new YAHOO.util.DataSource('conduit/take.tcl?op=all&u='); + takeDS.responseType = YAHOO.util.DataSource.TYPE_XML; + takeDS.responseSchema = { + resultNode: 'Result', + fields: ['Type', 'Nickname','Personal','Email','Fcc','Note','Error'] + }; + takeDS.sendRequest(YAHOO.alpine.current.u, + { + success: function(oReq,oResp,oPayload){ + var dom = YAHOO.util.Dom; + if(oResp.results.length == 1 && oResp.Error){ + showStatusMessage('Error Taking Address: ' + oResp.Error, 10); + } + else { + var id, el, elTD, elTR, elTable = document.createElement('table'); + elTable.setAttribute('width','100%'); + elTable.setAttribute('cellSpacing','0'); + elTable.setAttribute('cellPadding','0'); + for(var i = 0; i < oResp.results.length; i++){ + var o = oResp.results[i]; + n = (o.Email) ? o.Email.length : 0; + if(n){ + elTR = elTable.insertRow(elTable.rows.length); + elTD = elTR.insertCell(elTR.cells.length); + + el = createInputElement('checkbox','taList'); + el.setAttribute('value',elTable.rows.length); + id = 'takeAddr' + elTable.rows.length; + el.setAttribute('id',id); + + YAHOO.util.Event.addListener(el,'click',boxClicked); + elTD.appendChild(el); + + elTD = elTR.insertCell(elTR.cells.length); + dom.addClass(elTD,'wap'); + el = createNameValueElement('label','for',id); + elTD.appendChild(el); + el.setAttribute('id','taPers'+elTable.rows.length); + el.innerHTML = (o.Personal) ? o.Personal : ''; + + elTD = elTR.insertCell(elTR.cells.length); + dom.addClass(elTD,'wap'); + el = createNameValueElement('label','for',id); + elTD.appendChild(el); + el.setAttribute('id','taEmail'+elTable.rows.length); + el.innerHTML = o.Email; + } + + //if(oResp.results[i].Nickname) ; + //if(oResp.results[i].Note) ; + //if(oResp.results[i].Fcc) ; + } + + elContainer.replaceChild(elTable, elContainer.firstChild); + } + }, + failure: function(oReq,oResp,oPayload){ + showStatusMessage('Error Taking Address: ' + oResp.responseText, 10); + }, + scope: this, + argument:[elContainer] + }); + return(false); +} + +function boxClicked(e){ + var o = YAHOO.util.Event.getTarget(e); + + if(o) markOne(o); + var el = document.getElementsByName('taList'); + if(el){ + for(var i = 0; i < el.length; i++){ + if(el[i].checked){ + panelDialogEnableButton(true); + return; + } + } + } + + panelDialogEnableButton(false); +} + +function boxClear(){ + var el = document.getElementsByName('taList'); + if(el){ + for(var i = 0; i < el.length; i++) el[i].checked = false; + } + + panelDialogEnableButton(false); +} + +// focus message list on search results +function listSearchResults(){ + newMessageList({parms:{op:'focus',page:'new'}}); + return false; +} + +function fixupUnreadCount(id,n) { + var idObj; + if(n) updateElementHtml('unread' + id, ' (' + n + ')'); + else updateElementHtml('unread' + id, ''); +} + + +// Pagewise Context updaters +function showBrowseMenus(){ + var dom = YAHOO.util.Dom; + dom.setStyle('viewTopMenubar','display','none'); + dom.setStyle('listTopMenubar','display','block'); + dom.setStyle('viewBottomMenubar','display','none'); + dom.setStyle('listBottomMenubar','display','block'); +} + +function updateBrowseLinksAndSuch(o){ + var dom = YAHOO.util.Dom; + var alp = YAHOO.alpine; + if(o.u) alp.current.u = o.u; + alp.current.count = o.count; + alp.current.selected = o.selected; + alp.current.searched = o.searched; + alp.current.focused = o.focused; + if(o.selected != numCheckedOnPage()) showSelectAllInfo(2); + if(!o.page || o.page < 1) o.page = 1; + if(!o.pages || o.pages < 1) o.pages = 1; + document.title = alp.current.f + ', ' + o.page + ' of ' + o.pages + ' (' + o.unread + ') - Web Alpine 2.0'; + fixupUnreadCount('Current',o.unread); + if(o.trashed > 0) incUnreadCount('Trash',o.trashed); + else if(o.trashed < 0) decUnreadCount('Trash',(o.trashed * -1)); + else if(o.cpmv){ + if(o.cpmv.n > 0) incUnreadCount(o.cpmv.f,o.cpmv.n); + else if(o.cpmv.n < 0) decUnreadCount(o.cpmv.f,(o.cpmv.n * -1)); + } + updateElementHtml('listContext', 'Page ' + o.page + ' of ' + o.pages + ' (' + o.count + ' Total Messages) '); + var bUrl = 'browse/' + alp.current.c + '/' + alp.current.f; + updateElementHref('gFolder', bUrl); + updateElementHref('composeLink', 'compose?pop=' + bUrl); + if(o.sort){ + var ea = document.getElementsByTagName('span'); + for(var i = 0; i < ea.length; i++){ + if(dom.hasClass(ea[i],'spfcl3')){ + dom.removeClass(ea[i],'spfcl3'); + break; + } + } + + var el = document.getElementById('sort'+o.sort); + if(el) dom.addClass(el.firstChild,'spfcl3') + } + if(o.searched > 0){ + dom.setStyle('searchResult','display','block'); + dom.setStyle('searchRefine','display','block'); + dom.setStyle('searchClear','display','block'); + if(o.focused > 0){ + updateElementHtml('pageTitle', 'Search Results in ' + quoteHtml(alp.current.f)); + updateElementHtml('searchResultText', 'Search Results (' + o.focused + ')'); + if(!dom.hasClass('searchResult','sel')) dom.addClass('searchResult','sel'); + var el = document.getElementById('gFolder'); + if(el && dom.hasClass(el.parentNode,'sel')) dom.removeClass(el.parentNode,'sel'); + } + else{ + updateElementHtml('pageTitle', quoteHtml(alp.current.f)); + if(dom.hasClass('searchResult','sel')) dom.removeClass('searchResult','sel'); + var el = document.getElementById('gFolder'); + if(el && !dom.hasClass(el.parentNode,'sel')) dom.addClass(el.parentNode,'sel'); + } + } + else{ + updateElementHtml('pageTitle', quoteHtml(alp.current.f)); + dom.setStyle('searchResult','display','none'); + if(dom.hasClass('searchResult','sel')) dom.removeClass('searchResult','sel'); + var el = document.getElementById('gFolder'); + if(el && !dom.hasClass(el.parentNode,'sel')) dom.addClass(el.parentNode,'sel'); + dom.setStyle('searchRefine','display','none'); + dom.setStyle('searchClear','display','none'); + document.getElementById('searchScope').selectedIndex = 2; + } + if(YAHOO.env.ua.gecko > 0){ + sizeVPHeight(); + window.onresize = resizeVPHeight; + } +} + +function showViewMenus(){ + var dom = YAHOO.util.Dom; + dom.setStyle('listTopMenubar','display','none'); + dom.setStyle('viewTopMenubar','display','block'); + dom.setStyle('listBottomMenubar','display','none'); + dom.setStyle('viewBottomMenubar','display','block'); +} + +function updateViewLinksAndSuch(o){ + var alp = YAHOO.alpine; + var ac = alp.current; + if(o.u == 0){ + window.location = alp.app_root + '/browse/' + ac.c + '/' + ac.f; + return; + } + + ac.u = o.u; + ac.count = o.count; + ac.selected = o.selected; + fixupUnreadCount('Current',o.unread); + var thisFldr = '/' + ac.c + '/' + ac.f + '/'; + var thisFldrUrl = '/' + ac.c + '/' + encodeURIComponent(ac.f).replace(/%2F/g,'/'); + var viewUrl = 'view' + thisFldr; + var browseUrl = 'browse' + thisFldrUrl; + var context = 'Message ' + o.n + ' of ' + o.count; + var fullcontext = ac.f + ', ' + context; + document.title = context + ' (' + o.unread + ') - Web Alpine 2.0'; + updateElementHtml('viewContext', context); + updateElementHtml('pageTitle', '<a href="' + viewUrl + '" onClick="return newMessageList({parms:{op:\'noop\',page:\'new\'}});">' + quoteHtml(fullcontext) + ''); + updateElementHref('gFolder', browseUrl); + updateElementHref('gCheck', viewUrl + ac.u); + updateElementHref('gExtract', 'extract/' + ac.c + '/' + ac.f + '/' + ac.u); + updateElementHref('gDelete', viewUrl + o.unext + '?delete=' + ac.u); + updateElementHref('gSpam', viewUrl + o.unext + '?spam=' + ac.u); + updateElementHref('gUnread', viewUrl + o.unext + '?unread=' + ac.u); + updateElementHref('gDecrypt', viewUrl + ac.u); + var compUrl = thisFldrUrl + '/' + ac.u + '?pop=view' + thisFldrUrl + '/' + ac.u; + updateElementHref('gReply', 'reply' + compUrl); + updateElementHref('gReplyAll', 'replyall' + compUrl); + updateElementHref('gForward', 'forward' + compUrl); + updateElementHref('composeLink', 'compose?pop=view' + compUrl); + var oForm = document.getElementById('searchForm'); + oForm.action = oForm.action.replace(/\/[\d]+$/,'/' + ac.u); + if(YAHOO.env.ua.gecko > 0){ + sizeVPHeight(); + window.onresize = resizeVPHeight; + } +} diff --git a/web/cgi/alpine/2.0/lib/settings.js b/web/cgi/alpine/2.0/lib/settings.js new file mode 100644 index 00000000..2df78d3a --- /dev/null +++ b/web/cgi/alpine/2.0/lib/settings.js @@ -0,0 +1,183 @@ +/* $Id: settings.js 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ + * ======================================================================== + * Copyright 2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +function settingsPage(el){ + var dom = YAHOO.util.Dom; + for(var i = 1; i <= 20; i++){ + dom.setStyle('settingsPage' + i,'display','none'); + var elPage = document.getElementById('Page' + i); + if (elPage) dom.removeClass(elPage.parentNode,'sel'); + } + + dom.setStyle('settings' + el.id,'display','block'); + dom.addClass(el.parentNode,'sel'); + el.blur(); + return false; +} + +function toggleAdvance(el){ + var dom = YAHOO.util.Dom; + var s = dom.getStyle('advancedSettings','display'); + if(s && s == 'block'){ + dom.setStyle('advancedSettings','display','none'); + el.firstChild.src = 'img/cbn/f_plus.gif' + } + else{ + dom.setStyle('advancedSettings','display','block'); + el.firstChild.src = 'img/cbn/f_minus.gif' + } + + el.blur(); + return false; +} + +function validFieldName(e){ + var ev = YAHOO.util.Event; + var cc = ev.getCharCode(e); + if((cc >= 32 & cc < 127) && !(cc == 45 || (cc >= 65 && cc <= 90) || (cc >= 97 && cc <= 122))) ev.stopEvent(e); +} + +function customHdrAdd(idTable){ + var frag = document.createDocumentFragment(); + var div = document.createElement('div'); + frag.appendChild(div); + div.setAttribute('align','center'); + div.innerHTML = '<p>Add a new custom header by entering the new header name on the left and an optional value on the left<p>'; + + div = document.createElement('div'); + frag.appendChild(div); + div.setAttribute('align','center'); + + var elName = createInputElement('text','field'); + div.appendChild(elName); + elName.setAttribute('size','12'); + elName.setAttribute('maxlength','36'); + YAHOO.util.Event.addListener(elName,'keypress',validFieldName); + YAHOO.util.Event.addListener(elName,'keyup',panelDialogInputChange); + el = document.createTextNode(' : '); + div.appendChild(el); + var elValue = createInputElement('text','value'); + div.appendChild(elValue); + elValue.setAttribute('size','40'); + + panelDialog('New Custom Field', + frag, + { + label:' Add ', + disabled: true, + fn: function() { + var elTD, elTR, elTable = document.getElementById(idTable); + var el = document.getElementById('customHdrFields'); + var n = (el.value - 0) + 1; + el.value = n; + if(elTable && elName.value.length){ + elTR = elTable.insertRow(elTable.rows.length); + + elTD = elTR.insertCell(elTR.cells.length); + el = document.createTextNode(elName.value +':'); + elTD.appendChild(el); + el = createInputElement('hidden','customHdrField'+n); + elTD.appendChild(el); + el.setAttribute('value',elName.value); + + elTD = elTR.insertCell(elTR.cells.length); + el = createInputElement('text','customHdrData' + n); + elTD.appendChild(el); + el.setAttribute('value',elValue.value); + el.setAttribute('size','45'); + + el = document.createElement('a'); + elTD.appendChild(el); + el.setAttribute('href','#'); + YAHOO.util.Event.addListener(el,'click',removeTableRowEvent); + var img = document.createElement('img'); + img.setAttribute('src','img/cbn/remove.gif'); + YAHOO.util.Dom.addClass(img,'wap'); + el.appendChild(img); + } + } + }); + + elName.focus(); + return false; +} + +function removeTableRow(el){ + if(el){ + var iRow = el.parentNode.parentNode.rowIndex; + el.parentNode.parentNode.parentNode.parentNode.deleteRow(iRow); + } + return false; +} + +function removeTableRowEvent(e){ + var ev = YAHOO.util.Event; + removeTableRow(ev.getTarget(e).parentNode); + ev.stopEvent(e); +} + +function listAdd(idTable,listName){ + var elTD, elTR, elTable = document.getElementById(idTable); + var el = document.getElementById(listName+'s'); + var n = el.value - 0; + el.value = ++n; + if(elTable.rows.length < 12){ + if(elTable){ + elTR = elTable.insertRow(elTable.rows.length); + elTD = elTR.insertCell(elTR.cells.length); + + el = createInputElement('text',listName + n); + elTD.appendChild(el); + el.setAttribute('size','45'); + + el = document.createElement('a'); + elTD.appendChild(el); + el.setAttribute('href','#'); + YAHOO.util.Event.addListener(el,'click',removeTableRowEvent); + var img = document.createElement('img'); + img.setAttribute('src','img/cbn/remove.gif'); + YAHOO.util.Dom.addClass(img,'wap'); + el.appendChild(img); + } + } + + return false; +} + +function saveSettings(){ + showLoading(); + document.getElementById('settingsForm').submit(); + return false; +} + +function restoreDefaultSettings(){ + var el = document.getElementById('restore'); + if(el){ + el.value = 'restore'; + showLoading(); + document.getElementById('settingsForm').submit(); + } + return false; +} + +function settingsSuccess(){ + var alp = YAHOO.alpine; + window.location.href = alp.cgi_base + 'browse/' + alp.current.c + '/' + alp.current.f; +} + +function settingsFailure(m){ + hideLoading(); + addStatusMessage('Settings Failure: ' + m, 10); + displayStatusMessages(); +} diff --git a/web/cgi/alpine/2.0/lib/yui b/web/cgi/alpine/2.0/lib/yui new file mode 120000 index 00000000..7f792d58 --- /dev/null +++ b/web/cgi/alpine/2.0/lib/yui @@ -0,0 +1 @@ +yui-2.7.0
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/mailto b/web/cgi/alpine/2.0/mailto new file mode 120000 index 00000000..872d4cb2 --- /dev/null +++ b/web/cgi/alpine/2.0/mailto @@ -0,0 +1 @@ +compose
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/messagelist.tcl b/web/cgi/alpine/2.0/messagelist.tcl new file mode 100644 index 00000000..9f1306ce --- /dev/null +++ b/web/cgi/alpine/2.0/messagelist.tcl @@ -0,0 +1,622 @@ +# Web Alpine message list painting support +# $Id$ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# messagelist +# +# Purpose: TCL procedure to produce HTML-based message list of given +# folder's contents +# +# Input: +# + +proc sort_class {cursort sort} { + if {[string compare $sort [lindex $cursort 0]]} { + return blank + } else { + return spfcl3 + } +} + +proc navListButtons {c f} { + cgi_table_data class="wap pageBtns" { + cgi_puts [cgi_url [cgi_span "class=sp spmb spmbf" [cgi_span "<<"]] "browse/$c/$f" class=wap title="First Page" "onClick=return newMessageList({control:this,parms:{op:'first'}});"] + } + cgi_table_data class="pageBtns" { + cgi_puts [cgi_url [cgi_span "class=sp spmb spmbp" [cgi_span "<"]] "browse/$c/$f" class=wap title="Previous Page" "onClick=return newMessageList({control:this,parms:{op:'prev'}});"] + } + cgi_table_data class="dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class="pageBtns" { + cgi_puts [cgi_url [cgi_span "class=sp spmb spmbn" [cgi_span ">"]] "browse/$c/$f" class=wap title="Next Page" "onClick=return newMessageList({control:this,parms:{op:'next'}});"] + } + cgi_table_data class="pageBtns" { + cgi_puts [cgi_url [cgi_span "class=sp spmb spmbl" [cgi_span ">>"]] "browse/$c/$f" class=wap title="Last Page" "onClick=return newMessageList({control:this,parms:{op:'last'}});"] + } +} + +proc drawTopListMenuBar {c f} { + global _wp + + set mode [wpFolderMode $c $f] + + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_put "<tbody>" + cgi_table_row { + if {[info exists mode] && [lsearch [list trash junk] $mode] >= 0} { + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb7" "Delete Forever"] "empty/$c/$f" "onClick=return doEmpty(this,'selected');" "title=Permanently remove messages from $f" class=wap] + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb17" "Move to INBOX"] "inbox" "onClick=if(anySelected('Move to INBOX')) newMessageList({control:this,parms:{op:'move',df:'0/INBOX'}}); return false;" class=wap] + } + } else { + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb7" "Delete"] "delete" "onClick= if(anySelected('Delete')) confirmDelete(); this.blur(); return false;" "title=Move message to Trash" class=wap] + } + if {(![info exists mode] || [lsearch [list junk draft sent] $mode] < 0) && [info exists _wp(spamfolder)] && [string compare [string tolower $f] $_wp(spamfolder)]} { + cgi_table_data class=wap { + cgi_puts [cgi_url [cgi_span "class=sp spmbi spmb8" "Report Spam"] "spam" "onClick=return doSpam(this);" class=wap] + } + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=menuHdr>[cgi_url "More Actions [cgi_img "img/cbn/menu.gif" "class=menuDn menuImg"]" "" "onClick=return false;"]<div>" + cgi_bullet_list { + if {![info exists mode] || 0 == [string length $mode]} { + cgi_li [cgi_url "Mark as Read" "read" "onClick=if(anySelected('Mark as Read')) return applyFlag(this,'new','not'); else return false;"] + cgi_li [cgi_url "Mark as Unread" "unread" "onClick=if(anySelected('Mark as Unread')) return applyFlag(this,'new','ton'); else return false;"] + set hr "<hr />" + } else { + set hr "" + } + + cgi_li "${hr}[cgi_url "Set Star" "star" "onClick=if(anySelected('Set Star')) return applyFlag(this,'imp','ton'); else return false;"]" + cgi_li [cgi_url "Clear Star" "unstar" "onClick=if(anySelected('Clear Star')) return applyFlag(this,'imp','not'); else return false;"] + cgi_li "<hr />[cgi_url "Select All" "browse/$c/$f?select=all" "onClick=return selectAllInFolder();"]" + cgi_li [cgi_url "Clear All" "browse/$c/$f?select=none" "onClick=return unSelectAllInFolder();"] + } + cgi_put "</div></li>" + } + } + } + if {![info exists mode] || 0 == [string length $mode]} { + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class=wap { + cgi_bullet_list class="wap menu" { + cgi_put "<li class=menuHdr>[cgi_url "Arrange [cgi_img "img/cbn/menu.gif" "class=menuDn menuImg"]" "" "onClick=return false;"]<div>" + cgi_bullet_list class=sortList { + if {[catch {PEMailbox sort} cursort]} { + set cursort [list Arrival 0] + set rev "" + } elseif {[lindex $cursort 1]} { + set rev Rev + } else { + set rev "" + } + + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort From]" [cgi_span [cgi_nbspace]]]Sort by From" "#" id=sortFrom "onClick=return newMessageList({control:this,parms:{op:'sort${rev}From'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort Subject]" [cgi_span [cgi_nbspace]]]Sort by Subject" "#" id=sortSubject "onClick=return newMessageList({control:this,parms:{op:'sort${rev}Subject'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort Date]" [cgi_span [cgi_nbspace]]]Sort by Date" "#" id=sortDate "onClick=return newMessageList({control:this,parms:{op:'sort${rev}Date'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort siZe]" [cgi_span [cgi_nbspace]]]Sort by Size" "#" id=sortsiZe "onClick=return newMessageList({control:this,parms:{op:'sort${rev}Size'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort Arrival]" [cgi_span [cgi_nbspace]]]Sort by Arrival" "#" id=sortArrival "onClick=return newMessageList({control:this,parms:{op:'sort${rev}Arrival'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort tHread]" [cgi_span [cgi_nbspace]]]Group by Thread" "#" id=sorttHread "onClick=return newMessageList({control:this,parms:{op:'sortThread'}});"] + cgi_li [cgi_url "[cgi_span "class=sp spfcl [sort_class $cursort OrderedSubj]" [cgi_span [cgi_nbspace]]]Group by Subject" "#" id=sortOrderedSubj "onClick=return newMessageList({control:this,parms:{op:'sortOrderedsubj'}});"] + } + cgi_put "</div></li>" + } + } + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + + # move/cp FOLDER LIST + cgi_table_data id=listMorcButton class="wap yui-skin-sam yuimenu" {} + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=menuHdr>[cgi_url "to Folder [cgi_img "img/cbn/menu.gif" "class=menuDn menuImg"]" "" "onClick=return false;"]<div>" + cgi_bullet_list id=browseSaveCache { + cgi_li "<hr />[cgi_url "More Folders..." "save/$c/$f" "onClick=if(anySelected('Move or Copy')){ pickFolder('folderList',morcWhich('listMorcButton'),'[PEFolder defaultcollection]',morcInBrowseDone) }; return false;"]" + } + cgi_put "</div></li>" + } + } + + cgi_table_data width="100%" { + cgi_put [cgi_nbspace] + } + + cgi_puts [navListButtons $c $f] + + cgi_table_data class="tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_put "</tbody>" + } +} + +proc drawBottomListMenuBar {c f pn pt mc} { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_put "<tbody>" + cgi_table_row { + cgi_table_data id=listContext class="wap pageText" { + cgi_put "Page $pn of $pt [cgi_nbspace]($mc Total Messages)[cgi_nbspace]" + } + cgi_table_data width="100%" { + cgi_put [cgi_nbspace] + } + + cgi_puts [navListButtons $c $f] + + cgi_table_data class="tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_put "</tbody>" + } +} + +proc drawMessageList {c f n ppg} { + # remember message number at top of list + if {$n > 0 && [catch {PEMailbox current number $n} cm]} { + set n 1 + } + + if {[catch {PEMailbox nextvector $n $ppg [list indexparts indexcolor status statuslist]} nv]} { + set nv {} + set mv {} + } else { + set mv [lindex $nv 0] + } + + cgi_division id="bannerSelection" {} + + # message list header + # cells below MUST be reconciled with drawMessageList + cgi_table class="listTbl" cellpadding="0" cellspacing="0" { + + set columns 0 + + # index header line + cgi_put "<thead>" + cgi_table_row { + incr columns + cgi_table_head class="wap colHdr" align="left" { + set nchk 0 + foreach x $mv { + if {[lsearch -exact [lindex [lindex $x 2] 3] selected] >= 0} { + incr nchk + } + } + + if {$ppg == $nchk} { + set allchecked checked + } else { + set allchecked "" + } + + cgi_checkbox selectall= "onClick=markAllMessages();" $allchecked id=selectall title="Select/Unselect All Messages on this page" + cgi_put [cgi_nbspace] + } + + if {0 == [catch {PEMailbox sort} sort]} { + set cursort [lindex $sort 0] + set revsort [lindex $sort 1] + } else { + set cursort nonsense + set revsort 0 + } + + set iformat [PEMailbox indexformat] + foreach fmt $iformat { + set iname [lindex $fmt 0] + set iwidth [lindex $fmt 1] + set idname [lindex $fmt 2] + + if {0 == [string compare -nocase $iname priority]} { + continue + } + + # cell defaults + set align "left" + if {[string compare -nocase $iname $cursort]} { + set class "wap colHdr" + if {$revsort} { + set rev "Rev" + } else { + set rev "" + } + set sorturl "browse/$c/[WPPercentQuote $f {/}]?sort=[string tolower $iname]&rev=$revsort" + set onclick "onClick=return newMessageList({control:this,parms:{'op':'sort${rev}[string tolower $iname]'}});" + set sortextra "" + } else { + set class "wap selColHdr" + if {0 == $revsort} { + set rev "Rev" + set revbin 1 + } else { + set rev "" + set revbin 0 + } + set sorturl "browse/$c/[WPPercentQuote $f {/}]?sort=[string tolower $cursort]&rev=$revbin" + set onclick "onClick=return newMessageList({control:this,parms:{'op':'sort${rev}[string tolower $cursort]'}});" + if {$revsort} { + set sortimg "img/cbn/up.gif" + #set sortclass "spml13" + set sortimgt "Descending" + } else { + set sortimg "img/cbn/dn.gif" + #set sortclass "spml12" + set sortimgt "Increasing" + } + + set sortextra "[cgi_nbspace][cgi_nbspace][cgi_nbspace][cgi_img $sortimg class="wap selectedDn" title="$sortimgt"][cgi_nbspace][cgi_nbspace]" + } + + if {[string length $iwidth]} { + set width width="$iwidth" + } else { + set width "" + } + + switch -- [string tolower $iname] { + number { + set cd "#" + } + status { + set align center + #set cd [cgi_img "img/cbn/info.gif" title="Message Information" "alt=Message Information" class=wap] + set cd [cgi_span "class=sp spml spml7" "[cgi_nbspace]"] + } + attachments { + set align center + #set cd [cgi_img "img/cbn/attach_sm.gif" title="Attachments" "alt=Attachments" class=wap] + set cd [cgi_span "class=sp spml spml6" "[cgi_nbspace]"] + } + subject { + if {0 == [string compare $f Drafts]} { + append sortextra "[cgi_nbspace][cgi_nbspace](click to resume composition)" + } + set cd [cgi_url "${iname}[cgi_nbspace]${sortextra}" $sorturl title="Sort by ${iname}" class=wap $onclick] + } + default { + set cd [cgi_url "${iname}[cgi_nbspace]${sortextra}" $sorturl title="Sort by ${iname}" class=wap $onclick] + } + } + + incr columns + cgi_table_head class="$class" align="$align" $width { + cgi_put $cd + } + } + + # fixed priority header + incr columns + cgi_table_head class="colHdr rt" align="center" { + cgi_put [cgi_span "class=sp spml spml8" "[cgi_nbspace]"] + } + } + + cgi_put "</thead><tbody>" + set listaction "view/$c/[WPPercentQuote $f {/}]/" + set viewonclick "onClick=return newMessageText({uid:\$ilu,parms:{page:'new'}});" + if {$c == [PEFolder defaultcollection] && 0 == [string compare $f Drafts]} { + set listaction "resume/" + set viewonclick "" + } + + if {[set mvl [llength $mv]]} { + # write index lines + for {set i 0} {$i < $ppg} {incr i} { + if {$i >= $mvl} { + if {($i % 2) == 0} { + set class "class=ac" + } else { + set class "" + } + + cgi_table_row $class { + cgi_table_data colspan=$columns { + cgi_put [cgi_nbspace] + } + } + + continue + } + + set v [lindex $mv $i] + + set iln [lindex $v 0] + set ilu [lindex $v 1] + set msg [lindex [lindex $v 2] 0] + set linecolor [lindex [lindex $v 2] 1] + set stat [lindex [lindex $v 2] 2] + set statlist [lindex [lindex $v 2] 3] + + # set background/bolding + if {[lsearch -exact $statlist new] < 0} { + set class "" + set unread 0 + } else { + set class "unread" + set unread 1 + } + + # alternating gray lines + if {($i % 2) == 0} { + if {[string length $class]} { + append class " ac" + } else { + set class "ac" + } + } + + if {[string length $class]} { + set rc class="$class" + } else { + set rc "" + } + + if {[lsearch -exact $statlist selected] >= 0} { + set checked checked + set rid "id=sd" + } else { + set checked "" + set rid "id=line$i" + } + + cgi_table_row $rc $rid { + cgi_table_data class=wap { + cgi_checkbox uidList=$ilu $checked "onClick=markMessage(this);" + } + + for {set j 0} {$j < [llength $iformat]} {incr j} { + + set iname [lindex [lindex $iformat $j] 0] + + set class wap + set align left + set cd [cgi_nbspace] + + catch {unset dragit} + catch {unset priority} + + switch -- [string tolower $iname] { + from - + to - + cc - + sender - + recipients - + to { + set fstr [lindex [lindex [lindex $msg $j] 0] 0] + set flen 20 + if {[string length $fstr] > $flen} { + set fstr "[string range $fstr 0 $flen]..." + } + + set cd [cgi_quote_html $fstr] + set dragit $ilu + } + subject { + if {$i == 0} { + cgi_anchor_name messages + } + + set st [lindex $msg $j] + + if {[llength $st]} { + set sstr "" + foreach sts $st { + # do something with type info, [lindex $sts 2], like threadinfo, HERE + append sstr [lindex $sts 0] + } + + set slen 50 + if {[set sl [string length [string trim $sstr]]]} { + + if {$sl > $slen} { + set subtext "[string range $sstr 0 $slen]..." + } else { + set subtext $sstr + } + } else { + set subtext {[Empty Subject]} + } + } else { + set subtext {[Empty Subject]} + } + + if {$unread} { + set h1c "class=\"wap unread\"" + } else { + set h1c "class=wap" + } + + set cd [cgi_buffer {cgi_h1 $h1c id=h1$ilu [cgi_url [cgi_quote_html $subtext] ${listaction}$ilu id=ml$ilu class=wap [subst $viewonclick]]}] + } + status { + set align center + catch {unset statclass} + if {[lsearch -exact $statlist recent] >= 0 && [lsearch -exact $statlist new] >= 0} { + set staticon "new" + set statclass spml1 + set stattitle "New Mail" + set statalt "New Mail" + } elseif {[lsearch -exact $statlist answered] >= 0} { + set staticon "replied" + set statclass spml2 + set stattitle "Replied to Sender" + set statalt "Replied" + } elseif {[lsearch -exact $statlist forwarded] >= 0} { + set staticon "fwd" + set statclass spml3 + set stattitle "Forwarded" + set statalt "Forwarded" + } elseif {[lsearch -exact $statlist to_us] >= 0} { + set staticon "tome" + set statclass spml4 + set stattitle "Addressed to you" + set statalt "Addressed to you" + } elseif {[lsearch -exact $statlist cc_us] >= 0} { + set staticon "ccme" + set statclass spml5 + set stattitle "Cc'd to you" + set statalt "Cc'd to you" + } else { + set staticon "blank" + set stattitle "" + set statalt "" + } + + if {[info exists statclass]} { + set cd [cgi_span "class=sp spml $statclass" "[cgi_nbspace]"] + } else { + set cd [cgi_nbspace] + } + } + attachments { + set align center + if {[regexp {^[0-9]+$} [lindex [lindex [lindex $msg $j] 0] 0]]} { + set cd [cgi_span "class=sp spml spml6" "[cgi_nbspace]"] + } + } + date { + set cd "[lindex [lindex [lindex $msg $j] 0] 0]" + } + size { + set sstr [lindex [lindex [lindex $msg $j] 0] 0] + regsub {^\(([^\)]+)\)$} $sstr {\1} sstr + set cd "[cgi_quote_html $sstr]" + } + number { + set cd [WPcomma $iln] + } + priority { ; # priority combined with "impotant" + set priority [lindex [lindex [lindex $msg $j] 0] 0] + unset cd + } + default { + set cd "[lindex [lindex [lindex $msg $j] 0] 0]" + } + } + + if {[info exists cd]} { + if {[info exists dragit]} { + set ddid dd$ilu + set ddidid id=$ddid + set mouseover "onMouseOver=\"cursor('move');\"" + set mouseout "onMouseOut=\"cursor('default');\"" + } else { + set ddidid "" + set mouseover "" + set mouseout "" + } + + cgi_table_data align="$align" class="$class" { + cgi_division $ddidid $mouseover $mouseout { + cgi_put $cd + } + } + + if {[info exists dragit]} { + lappend ddlist "'$ddid':'$ilu'" + } + } + } + + # fixed right column for combined important/priority + cgi_table_data class="wap rt" { + # WARNING: ititle STORES STATE, KEEP IN SYNC WITH lib/browse.js + set iclass nostar + set ititle "" + + if {[info exists priority]} { + switch -regexp $priority { + ^2$ - + ^high$ { + set iclass prihi + set ititle "High Priority" + } + ^1$ - + ^highest$ { + set iclass prihier + set ititle "Highest Priority" + } + } + } + + if {[lsearch -exact $statlist flagged] >= 0} { + set iclass star + if {[string length $ititle]} { + set ititle "Starred and $ititle" + } else { + set ititle "Starred" + } + } + + if {0 == [string length $ititle]} { + set ititle "Set Starred" + } + + cgi_put [cgi_url [cgi_span "class=sp spml $iclass" ""] "star/$c/$f/$ilu" class=mlstat id=star$ilu "title=$ititle" "onClick=return flipStar(this);"] + } + } + } + } else { + cgi_table_row { + cgi_table_data class=wap colspan=$columns align=center { + if {[catch {PEMailbox state} mbstate]} { + if {[string length $f]} { + set fn "Folder \"[cgi_quote_html $f]\"" + } else { + set fn INBOX + } + + cgi_put [cgi_span "style=font-size: large; font-weight: bold ; background-color: yellow;" "[cgi_nbspace]$fn cannot be opened[cgi_nbspace]"] + } else { + switch -- $mbstate { + closed { + cgi_put [cgi_span "style=font-size: large; font-weight: bold ; background-color: yellow;" "[cgi_nbspace]Folder \"[cgi_quote_html $f]\" is not opened[cgi_nbspace]"] + } + default { + cgi_put [cgi_span "style=font-size: large; font-weight: bold ; margin: 50px" "Folder \"[cgi_quote_html $f]\" contains no messages"] + } + } + } + } + } + } + + cgi_put "</tbody>" + } + if {[info exists ddlist]} { + cgi_puts "<script>" + cgi_puts "function loadDDElements(){" + cgi_puts " var prop, ddList = { [join $ddlist ","] }, ddArray = \[\];" + cgi_puts " for(prop in ddList) ddArray\[ddArray.length\] = prop;" + cgi_puts " var tt = new YAHOO.widget.Tooltip('tipDrag', {context:ddArray, showdelay:500, text:'Drag over folder on left to move, Contacts to add'});" + cgi_puts " for(prop in ddList) canDragit(prop,ddList\[prop\],tt);" + cgi_puts "}" + cgi_puts "</script>" + } +} diff --git a/web/cgi/alpine/2.0/messageview.tcl b/web/cgi/alpine/2.0/messageview.tcl new file mode 100644 index 00000000..13f660a2 --- /dev/null +++ b/web/cgi/alpine/2.0/messageview.tcl @@ -0,0 +1,731 @@ +# Web Alpine message text painting support +# $Id$ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# messageview +# +# Purpose: TCL procedure to produce HTML-based view of a message's +# header/body text +# +# Input: +# + +proc email_addr {pers mailbox} { + if {[string length $pers]} { + return "[cgi_quote_html $pers] [cgi_lt][cgi_quote_html $mailbox][cgi_gt]" + } else { + return "[cgi_quote_html $mailbox]" + } +} + +proc put_quoted {s} { + cgi_put [cgi_quote_html $s] +} + +proc put_quoted_nl {s} { + cgi_put "[cgi_quote_html $s][cgi_nl]" +} + +proc navViewButtons {c f u n} { + cgi_table_data class="wap pageBtns" { + if {[catch {PEMailbox uid [PEMailbox next $n -1]} uprev]} { + set prevurl "#" + } elseif {$u == $uprev} { + set prevurl "javascript:alert('Already viewing first message')" + } else { + set prevurl "view/$c/$f/$uprev" + } + + cgi_put [cgi_url [cgi_span "class=sp spmb spmbu" [cgi_span "Prev"]] $prevurl "title=Previous Message" "onClick=return newMessageText({control:this,parms:{op:'prev'}});"] + } + + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + + cgi_table_data class="wap pageBtns" { + if {[catch {PEMailbox uid [PEMailbox next $n 1]} unext]} { + set nexturl "#" + } elseif {$u == $unext} { + set nexturl "javascript:alert('Already viewing last message')" + } else { + set nexturl "view/$c/$f/$unext" + } + + cgi_put [cgi_url [cgi_span "class=sp spmb spmbd" [cgi_span "Next"]] $nexturl title="Next Message" class=wap "onClick=return newMessageText({control:this,parms:{op:'next'}});"] + } +} + +proc drawTopViewMenuBar {c f u n} { + cgi_table id=toolBar class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + if {[lsearch -exact [list Junk Trash] $f] >= 0} { + cgi_table_data class=wap { + cgi_puts [cgi_url "[cgi_img "img/cbn/delete.gif" class=wap] Delete Forever" "empty/$c/$f/$u" "onClick=return doEmpty(this,'message');" "title=Move message to Trash" class=wap] + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + cgi_table_data class=wap { + cgi_puts [cgi_url "[cgi_img img/cbn/inbox.gif class=wap] Move to INBOX" "move/$c/$f/$u?df=0/INBOX" "onClick=return newMessageText({control:this,parms:{op:'move',df:'0/INBOX'}});" class=wap] + } + } else { + cgi_table_data class=wap { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb4" "Reply"] "reply/$c/$f/$u?pop=view/$c/$f/$u" id=gReply class=wap] + } + cgi_table_data class=wap { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb5" "Reply All"] "replyall/$c/$f/$u?pop=view/$c/$f/$u" id=gReplyAll class=wap] + } + cgi_table_data class=wap { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb6" "Forward"] "forward/$c/$f/$u?pop=view/$c/$f/$u" id=gForward class=wap] + } + cgi_table_data class=wap { + if {[catch {PEMailbox uid [PEMailbox next $n 1]} unext]} { + set delurl "browse/$c/$f?u=$u" + } elseif {$u == $unext} { + set delurl "browse/$c/$f?u=${u}&delete=$u" + } else { + set delurl "view/$c/$f/$unext?delete=$u" + } + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb7" "Delete"] $delurl title="Move message to Trash" class=wap id=gDelete "onClick=return newMessageText({control:this,parms:{op:'delete'}});"] + } + cgi_table_data class=wap { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb8" "Report Spam"] "view/$c/$f/$unext?spam=$u" title="Report as Spam and move message to Junk folder" class=wap id=gSpam "onClick=return newMessageText({control:this,parms:{op:'spam'}});"] + } + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + #cgi_put [cgi_img "img/cbn/div.gif" class=wap] + } + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=menuHdr>[cgi_url "More Actions [cgi_img "img/cbn/menu.gif" class="wap menuDn menuImg"]" "#" class=wap "onClick=return false;"]<div>" + cgi_bullet_list { + cgi_li [cgi_url "Extract Addresses (Take)" "extract/$c/$f/$u" id="gExtract" "onClick=return takeAddress();"] + cgi_li "<hr />[cgi_url "Mark as Unread" "view/$c/$f/$unext?unread=$u" "onClick=return newMessageText({control:this,parms:{op:'unread'}});" id=gUnread]" + cgi_li [cgi_url "Set Star" "view/$c/$f/$u?star=1" "onClick=return setStar(-1,'ton');"] + cgi_li [cgi_url "Clear Star" "view/$c/$f/$u?star=0" "onClick=return setStar(-1,'not');"] + } + cgi_put "</div></li>" + } + } + } + + cgi_table_data class="wap dv1" { + cgi_puts [cgi_span "class=sp spmb spmb3" ""] + } + + # move/cp FOLDER LIST + cgi_table_data id=viewMorcButton class="wap yui-skin-sam yuimenu" {} + cgi_table_data class=wap { + cgi_bullet_list class="menu" { + cgi_put "<li class=menuHdr>[cgi_url "to Folder [cgi_img "img/cbn/menu.gif" class="menuDn menuImg wap"]" "#" "onClick=return false;"]<div>" + cgi_bullet_list id=viewSaveCache { + cgi_li "<hr />[cgi_url "More Folders..." "save/$c/$f" "onClick=pickFolder('folderList',morcWhich('viewMorcButton'),'[WPCmd PEFolder defaultcollection]',morcInViewDone); return false;"]" + } + cgi_put "</div></li>" + } + } + + cgi_table_data class=wap width="100%" { + cgi_put [cgi_nbspace] + } + + cgi_puts [navViewButtons $c $f $u $n] + + cgi_table_data class="wap tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } +} + +proc drawBottomViewMenuBar {c f u n mc} { + cgi_table class="wap toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap pageText" id=viewContext { + cgi_put "Message $n of $mc" + } + cgi_table_data class=wap width="100%" { + cgi_put [cgi_nbspace] + } + + cgi_puts [navViewButtons $c $f $u $n] + + cgi_table_data class="wap tbPad" align="right" { + cgi_put [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } +} + +proc drawMessageText {c f u {showimg ""}} { + # before getting the list, move anything deleted to Trash + if {[catch {PEMailbox trashdeleted current} result]} { + PEInfo statmsg "Trash move Failed: $result" + } + + # remember "current" message + if {$u > 0 && [catch {PEMailbox current uid $u} cm]} { + PEInfo statmsg "Set current failed: $cm" + set u 0 + } + + set wasnew [expr {[lsearch -exact [PEMessage $u status] New] >= 0}] + set html 0 + + catch {unset shownsubtype} + catch {unset bodyleadin} + catch {unset fromaddr} + + # collect message parts + if {[catch {PEMessage $u header} hdrtext]} { + set hdrtext "Message Text Fetch Failure: $hdrtext" + } else { + # fish out From: address + foreach {ht hf hd} [join $hdrtext] { + if {0 == [string compare addr $ht]} { + if {0 == [string compare -nocase from $hf]} { + if {[llength $hd] == 1} { + set df [lindex [lindex $hd 0] 0] + if {0 == [string length $df]} { + set df [lindex [lindex $hd 0] 1] + } + + set fromaddr [list $df [cgi_quote_html [lindex [lindex $hd 0] 0]] [lindex [lindex $hd 0] 1]] + } + + break + } + } + } + } + + set attachments 0 + if {[catch {PEMessage $u attachments} attachmentlist]} { + # STATUS "Cannot get attachments: $attachments" + } else { + foreach att $attachmentlist { + # only an attachment if "shown" in multi/alt AND it has a filename + if {[string compare [lindex $att 1] shown]} { + if {[string length [lindex $att 4]]} { + incr attachments + } + } else { + # only use subtype if a single part is intended to be displayed + if {[info exists shownsubtype]} { + set shownsubtype "" + } else { + set shownsubtype [string tolower [lindex $att 3]] + } + } + } + } + + set bodyopts {} + set showimages "" + + if {[info exists shownsubtype] && 0 == [string compare $shownsubtype html]} { + if {[WPCmd PEInfo feature render-html-internally] == 0} { + set html 1 + lappend bodyopts html + set image_set allow_images + } else { + set image_set allow_cid_images + } + + switch -- $showimg { + 1 { ;# show images this once + lappend bodyopts images + set showimages 1 + } + from { ;# always show images from sender + lappend bodyopts images + set showimages friend + if {[info exists fromaddr] && [string length [lindex $fromaddr 2]]} { + if {[catch {WPSessionState $image_set} friends]} { ;# no image_set yet? + if {[catch {WPSessionState $image_set [list [lindex $fromaddr 2]]} result]} { + catch {PEInfo statmsg "Cannot remember [lindex $fromaddr 2]: $result"} + } + } elseif {[lsearch -exact $friends [lindex $fromaddr 2]] < 0} { + lappend friends [lindex $fromaddr 2] + if {[catch {WPSessionState $image_set $friends} result]} { + catch {PEInfo statmsg "Cannot remember [lindex $fromaddr 2]: $result"} + } + } + } + } + 0 { ;# never show images from sender + if {[info exists fromaddr] && [catch {WPSessionState $image_set} friends] == 0} { + while {[set findex [lsearch -exact $friends [lindex $fromaddr 2]]] >= 0} { + set friends [lreplace $friends $findex $findex] + if {[catch {WPSessionState $image_set $friends} friends]} { + catch {PEInfo statmsg "Cannot forget image sender: $friends"} + break; + } + } + } + } + "" { ;# display if a friend + if {[info exists fromaddr] + && 0 == [catch {WPSessionState $image_set} friends] + && [lsearch -exact $friends [lindex $fromaddr 2]] >= 0} { + lappend bodyopts images + set showimages friend + } + } + } + } + + if {[PEInfo mode full-header-mode] > 0} { + set put_tdata put_quoted + } + + if {[catch {PEMessage $u body $bodyopts} bodytext]} { + set bodytext "Message Text Fetch Failure: $bodytext" + } + + # prescan body for interesting stuff + foreach i $bodytext { + foreach j $i { + switch -exact [lindex $j 0] { + img { ;# digested HTML mode image + if {![info exists bodyleadin] + && [catch {PEMessage $uid cid "<[lindex [lindex $j 1] 0]>"} cidpart] == 0 + && [string length $cidpart] + && [catch {PEMessage $uid attachinfo $cidpart} attachinfo] == 0 + && [string compare [string tolower [lindex $attachinfo 1]] image] == 0} { + if {[string length $showimages]} { + set bodyleadin "\[ Attached images ARE being displayed \]" + if {[info exists fromaddr] && [string length [lindex $fromaddr 2]]} { + if {[string compare $showimages friend]} { + append bodyleadin "[cgi_nl]\[ Never show images from [cgi_url "[lindex $fromaddr 0]" "view/$c/$f/$u?showimg=0"] \]" + } else { + append bodyleadin "[cgi_nl]\[ Always show images from [cgi_url "[lindex $fromaddr 0]" "view/$c/$f/$u?showimg=from"] \]" + } + } + } else { + set bodyleadin "\[ Attached images are NOT being displayed \]" + append bodyleadin "[cgi_nl]\[ Show images [cgi_url "below" "view/$c/$f/$u?showimg=1" "onClick=return newMessageText({control:this,parms:{op:'noop',img:'1'}});"]" + if {[info exists fromaddr] && [string length [lindex $fromaddr 2]]} { + append bodyleadin ", or always show images from [cgi_url "[lindex $fromaddr 0]" "from/$c/$f/$u?showimg=from"] \]" + } else { + append bodyleadin " \]" + } + } + } + } + t { + if {$html && ![info exists bodyleadin] && [regexp {<[Ii][Mm][Gg](| ([^>]+))>} [lindex $j 1] dummy img]} { + set bodyleadin "[cgi_img "img/cbn/infomsg.gif"] Web-based images " + if {![string length $showimages]} { + append bodyleadin "have been blocked to to help protect your privacy and reduce spam.[cgi_nl][cgi_url "Display images below" "view/$c/$f/$u?showimg=1" "onClick=return newMessageText({control:this,parms:{op:'noop',img:'1'}});"]" + if {[info exists fromaddr] && [string length [lindex $fromaddr 2]]} { + append bodyleadin "[cgi_nbspace][cgi_nbspace][cgi_nbspace]-[cgi_nbspace][cgi_nbspace][cgi_nbspace][cgi_url "Display images and always trust email from [lindex $fromaddr 0]" "view/$c/$f/$u?showimg=from" "onClick=return newMessageText({control:this,parms:{op:'noop',img:'from'}});"]" + } + } else { + append bodyleadin "are being displayed below.[cgi_nl]" + if {[info exists fromaddr]} { + if {[string compare friend $showimages]} { + append bodyleadin "[cgi_nbspace][cgi_nbspace][cgi_url "Always display images and trust email from [lindex $fromaddr 0]" "view/$c/$f/$u?showimg=from" "onClick=return newMessageText({control:this,parms:{op:'noop',img:'from'}});"]" + } else { + append bodyleadin "[cgi_url "No longer automatically display images from [lindex $fromaddr 0]" "view/$c/$f/$u?showimg=0" "onClick=return newMessageText({control:this,parms:{op:'noop',img:'0'}});"]" + } + } + } + } + } + default {} + } + } + } + + set infont 0 + set inurl 0 + set fgcolor [set normal_fgcolor [PEInfo foreground]] + set bgcolor [PEInfo background] + + # Toss any informational panels up here + if {[info exists bodyleadin]} { + cgi_division class="wap bannerPrivacy" { + cgi_puts $bodyleadin + } + } + + # put message pieces together + # first the header & attachment list + cgi_table class="wap msgHead" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + + # user headers are selectable, but we control the + # first two: subject, from and + # last two: date, attachments + if {1 == [llength $hdrtext] && 0 == [string compare -nocase raw [lindex [lindex $hdrtext 0] 0]]} { + # raw header + cgi_table_row { + cgi_table_data { + cgi_preformatted { + foreach hdrline [lindex [lindex $hdrtext 0] 2] { + foreach hdrlinepart $hdrline { + switch -- [lindex $hdrlinepart 0] { + t { + cgi_put [cgi_quote_html [lindex $hdrlinepart 1]] + } + default { + } + } + } + + cgi_br + } + } + + cgi_table_data "class=\"wap fullHdrBtn\"" { + if {[WPCmd PEMailbox focus]} { + set retf "Search Result" + } else { + set retf [cgi_quote_html $f] + } + + cgi_put [cgi_url "Return[cgi_nbspace]to[cgi_nbspace]${retf}" "browse/$c/$f" class="wap" "onClick=return newMessageList({contol:this});"] + cgi_br + cgi_put [cgi_url "Show[cgi_nbspace]Filtered[cgi_nbspace]Headers" "view/$c/$f/$u" class="wap" "onClick=return newMessageText({contol:this,parms:{op:'hdroff'}});"] + } + } + } + } else { + set hdrmarkup "" + set datemarkup "" + foreach {ht hf hd} [join $hdrtext] { + switch -exact $ht { + text { + if {0 == [string compare -nocase subject $hf]} { + cgi_table_row { + cgi_table_data colspan=2 class="subText" { + cgi_put [cgi_quote_html $hd] + } + cgi_table_data "class=\"wap fullHdrBtn\"" { + if {[WPCmd PEMailbox focus]} { + set retf "Search Result" + } else { + set retf [cgi_quote_html $f] + } + + cgi_put [cgi_url "Return[cgi_nbspace]to[cgi_nbspace]${retf}[cgi_span "class=sp spmv spmv3" [cgi_span [cgi_nbspace]]]" "browse/$c/$f" class="wap" "onClick=return newMessageList({contol:this,parms:{page:'new'}});"] + } + } + } elseif {0 == [string compare -nocase date $hf]} { + set datemarkup "<td class=\"wap hdrLabel\">$hf:</td><td class=\"wap hdrText\">[cgi_quote_html $hd]</td>" + } else { + append hdrmarkup "<td class=\"wap hdrLabel\">$hf:</td><td colspan=2 class=\"wap hdrText\">[cgi_quote_html $hd]</td>" + } + } + addr { + if {0 == [string compare -nocase from $hf]} { ;# From: always first + set addrs "" + if {0 == [catch {PEAddress books} booklist]} { + set tAFargs "\{books:\[" + set comma "" + foreach b $booklist { + regsub -all {'} [lindex $b 1] {\'} bname + append tAFargs "${comma}\{book:[lindex $b 0],name:'$bname'\}" + set comma "," + } + + append tAFargs "\]\}" + } else { + set tAFargs {{}} + } + + foreach ma $hd { + lappend addrs [cgi_span class=emailAddr "[cgi_span "class=contactAddr" [email_addr [lindex $ma 0] [lindex $ma 1]]] [cgi_url "[cgi_span "class=sp spmv spmv1" ""]Add" "" "class=wap addContact" "onClick=takeAddressFrom('$u',$tAFargs); return false;" "title=Add Sender to Contacts"]"] + } + + set hdrmarkup [linsert $hdrmarkup 0 "<td class=\"wap hdrLabel\">$hf:</td><td colspan=2 class=\"wap hdrText\">[join $addrs ",[cgi_nl]"]</td>"] + } else { + set addrs "" + foreach ma $hd { + lappend addrs [cgi_span class=emailAddr [email_addr [lindex $ma 0] [lindex $ma 1]]] + } + + lappend hdrmarkup "<td class=\"wap hdrLabel\">$hf:</td><td colspan=2 class=\"wap hdrText\">[join $addrs ", "]</td>" + } + } + news - + rawaddr { + lappend hdrmarkup "<td class=\"wap hdrLabel\">$hf:</td><td colspan=2 class=\"wap hdrText\">[cgi_quote_html [join $hd ", "]]</td>" + } + default { + } + } + } + + foreach hm $hdrmarkup { + cgi_table_row { + cgi_puts $hm + } + } + + cgi_table_row { + cgi_puts $datemarkup + cgi_table_data "class=\"wap fullHdrBtn\"" { + cgi_put [cgi_url "Show[cgi_nbspace]Full[cgi_nbspace]Headers" "view/$c/$f/$u?headers=full" class="wap" "onClick=return newMessageText({control:this,parms:{op:'hdron'}});"] + } + } + } + + if {$attachments} { + cgi_table_row { + cgi_table_data class="wap hdrLabel" { + cgi_put "Attachments:" + } + cgi_table_data class="wap hdrText" { + cgi_division "class=attach" { + set tail "" + foreach att $attachmentlist { + # !shown and has supplied file name + if {[string compare [lindex $att 1] shown] && [string length [lindex $att 4]]} { + if {[string length [lindex $att 4]]} { + set attitle [lindex $att 4] + } else { + set attitle "Attachment [lindex $att 0]" + } + + cgi_put [cgi_span "class=attach" "[cgi_span "class=sp spmv spmv2" ""][cgi_url "$attitle" "detach/$c/$f/$u/[lindex $att 0]?download=1" title="Download $attitle"]"] + } + + set tail ":[cgi_nbspace]" + } + } + } + } + } + cgi_table_row { + cgi_table_data colspan="3" class="hdrLabel" { + cgi_put [cgi_span "class=trans" "style=height:5px;width:2px;" [cgi_span " "]] + } + } + + cgi_puts "</tbody>" + } + + # start writing body + if {$html} { + set class "" + set class "class=\"contentBodyHTML\"" + if {![info exists put_tdata]} { + set put_tdata cgi_put + } + } else { + set class "class=\"contentBody messageText\"" + if {![info exists put_tdata]} { + set put_tdata put_quoted + } + } + + cgi_division $class { + foreach i $bodytext { + foreach j $i { + set ttype [lindex $j 0] + set tdata [lindex $j 1] + + # write anchors by hand + switch -- $ttype { + urlstart { + set href [lindex $tdata 0] + set name [lindex $tdata 1] + + # build links by hand since we don't know where + # they'll terminate + set linktext "<a " + switch -- [lindex [split $href :] 0] { + mailto { + regsub {[?]} [lindex [split $href :] 1] {\&} maito + append linktext "href=mailto?to=[WPPercentQuote $maito {&=}]&pop=view/$c/[WPPercentQuote $f {/}]/$u" + } + default { + # no relative links, no javascript + if {[regexp -- "^(\[a-zA-Z\]+):" $href dummy scheme] + && [string compare -nocase $scheme javascript]} { + append linktext "href=\"$href\" target=\"_blank\" " + } + + if {[string length $name]} { + append linktext "name=\"$name\"" + } + } + } + + cgi_put "${linktext}>" + set inurl 1 + } + urlend { + if {$inurl} { + cgi_put "</a>" + } + } + attach { + set attachuid [lindex $tdata 0] + set part [lindex $tdata 1] + set mimetype [lindex $tdata 2] + set mimesubtype [lindex $tdata 3] + if {[string length [lindex $tdata 4]]} { + set file [lindex $tdata 4] + } else { + if {[string length [lindex $tdata 5]]} { + set file "attachment.[lindex $tdata 5]" + } else { + set file "unknown.txt" + } + } + + set attachurl "detach.tcl?uid=${attachuid}&part=${part}" + set saveurl "${attachurl}&download=1" + if {0 == [string compare -nocase $mimetype "text"] + && 0 == [string compare -nocase $mimesubtype "html"]} { + set attachurl [append $attachurl "&download=1"] + } + + set attachexp "View ${mimetype}/${mimesubtype} Attachment" + + if {0 == [string compare message [string tolower ${mimetype}]] + && 0 == [string compare rfc822 [string tolower ${mimesubtype}]]} { + set attmsgurl "/$c/$f/$u/$part" + cgi_put [cgi_url [cgi_font size=-1 Fwd] "forward${attmsgurl}" target=_top] + cgi_put "|[cgi_url [cgi_font size=-1 Reply] "reply${attmsgurl}?reptext=1&repall=1" target=_top]" + + } else { + cgi_put [cgi_url [cgi_font size=-1 View] $attachurl target="_blank"] + cgi_put "|[cgi_url [cgi_font size=-1 Save] $saveurl]" + } + + if {[info exists attachurl]} { + set attachtext [WPurl $attachurl {} $hacktoken $attachexp target="_blank"] + } + } + img { + if {[info exists showimages] && [string length $showimages] + && [catch {PEMessage $uid cid "<[lindex [lindex $j 1] 0]>"} cidpart] == 0 + && [string length $cidpart] + && [catch {PEMessage $uid attachinfo $cidpart} attachinfo] == 0 + && [string compare [string tolower [lindex $attachinfo 1]] image] == 0} { + cgi_put [cgi_img detach/$c/$f/$u/${cidpart} "alt=\[[lindex $tdata 1]\]"] + } else { + cgi_put "\[[lindex $tdata 1]\]" + } + } + fgcolor { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare $tdata $fgcolor]} { + set fgcolor $tdata + if {[string compare $fgcolor $normal_fgcolor]} { + cgi_put "<font color=#${tdata}>" + set infont 1 + } + } + } + bgcolor { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare $tdata $bgcolor]} { + cgi_put "<font style=\"background: #${tdata}\">" + set bgcolor $tdata + set infont 1 + } + } + color { + if {$infont} { + cgi_put "</font>" + set infont 0 + } + + if {[string compare [lindex $tdata 0] $fgcolor] || [string compare [lindex $tdata 1] $bgcolor]} { + cgi_put "<font color=#[lindex $tdata 0] style=\"background: #[lindex $tdata 1]\">" + set bgcolor $tdata + set infont 1 + } + } + italic { + switch $tdata { + on { cgi_put "<i>" } + off { cgi_put "</i>" } + } + } + bold { + switch $tdata { + on { cgi_put "<b>" } + off { cgi_put "</b>" } + } + } + underline { + switch $tdata { + on { cgi_put "<u>" } + off { cgi_put "</u>" } + } + } + strikethru { + switch $tdata { + on { cgi_put "<s>" } + off { cgi_put "</s>" } + } + } + bigfont { + switch $tdata { + on { cgi_put "<font size=\"+1\">" } + off { cgi_put "</font>" } + } + } + smallfont { + switch $tdata { + on { cgi_put "<font size=\"-1\">" } + off { cgi_put "</font>" } + } + } + default { + if {[info exists attachtext] && [set ht [string first $hacktoken $attachtext]] >= 0} { + set firstbit [string range $attachtext 0 [expr {$ht - 1}]] + set lastbit [string range $attachtext [expr {$ht + [string length $hacktoken]}] end] + cgi_put " $firstbit[cgi_quote_html [string trimleft $tdata]]$lastbit" + unset attachtext + } elseif {$html} { + $put_tdata "$tdata " + } else { + $put_tdata $tdata + } + } + } + } + + if {!$html} { + cgi_br + } + } + } + + cgi_division id="skip" { + cgi_put [cgi_url "Skip to Toolbar" "#toolbar"] + } + + if {$wasnew} { + cgi_put "<script>decUnreadCount(1);</script>" + } +} diff --git a/web/cgi/alpine/2.0/newlist.tcl b/web/cgi/alpine/2.0/newlist.tcl new file mode 100755 index 00000000..725a418b --- /dev/null +++ b/web/cgi/alpine/2.0/newlist.tcl @@ -0,0 +1,477 @@ +#!./tclsh +# $Id: newlist.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# newlist.tcl +# +# Purpose: CGI script that generates a page displaying a message +# list of the indicated folder. +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_first_msg> +# along with possible search parameters: +set newlist_args { + {op {} ""} + {df {} ""} + {uid {} ""} + {type {} ""} + {zoom {} ""} + {page {} ""} + {criteria {} ""} + {scope {} "new"} +} + +# inherit global config +source ./alpine.tcl +source ./common.tcl +source ./foldercache.tcl + +# default newlist state +set c 0 +set f "INBOX" + +# TEST +proc cgi_suffix {args} { + return "" +} + +set dmsgs "" +proc dm {s} { + global dmsgs + + lappend dmsgs $s +} + +proc focusOnResult {_focused} { + upvar 1 $_focused focused + + if {[catch {WPCmd PEMailbox focus 1} focused]} { + WPCmd PEInfo statmsg "Cannot focus: $focused" + set focused 0 + } else { + WPCmd PEInfo statmsg "Displaying $focused search results" + } +} + +# grok PATH_INFO for collection, 'c', and folder 'f' +if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {[regexp {^/([0-9]+)/(.*)$} $env(PATH_INFO) dummy c f]} { + # Import data validate it and get session id + if {[catch {WPGetInputAndID sessid} result]} { + set harderr "Session Invalid: $result" + set deadsession 1 + } else { + # grok parameters + foreach item $newlist_args { + if {[catch {eval WPImport $item} result]} { + set harderr "Cannot Read Input: $result" + break; + } + } + + if {[catch {WPCmd PEMailbox messagecount} mc]} { + set harderr $mc + if {[regexp {[Ii]nactive [Ss]ession$} $mc]} { + set deadsession 1 + } + } + + } + } else { + set harderr "Invalid Folder: $env(PATH_INFO)" + } +} else { + set harderr "No folder specified" +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" + +if {[info exists harderr]} { + if {[info exists deadsession]} { + cgi_division class=contentDeadSession { + cgi_puts "This Web Alpine session is no longer active.<p>Click [cgi_url "here to restart your session." "$_wp(serverpath)/"] </div>" + } + + exit + } else { + catch { WPCmd PEInfo statmsg "$harderr" } + set c 0 + set f INBOX + } +} + +set defc [WPCmd PEFolder defaultcollection] +set focused [WPCmd PEMailbox focus] + +# set uid to "current" message? +if {0 == [catch {WPCmd PEMailbox current} cm]} { + set n [lindex $cm 0] + set u [lindex $cm 1] +} else { + if {$mc > 0} { + WPCmd PEInfo statmsg "BOTCH: No current message" + } + + # non given, set to first message in folder + set n 1 + if {[catch { + set n [WPCmd PEMailbox first] + set u [WPCmd PEMailbox uid $n] + } result]} { + if {$mc > 0} { + WPCmd PEInfo statmsg "No first message: $result" + } + + set n 0 + set u 0 + } +} + +# lines per page +if {[catch {WPCmd PEInfo indexlines} ppg] || $ppg <= 0} { + set ppg $_wp(indexlines) +} elseif {$ppg > $_wp(indexlinesmax)} { + set ppg $_wp(indexlinesmax) +} + +# deal with page change +if {$mc > 0} { + switch -regexp -- $op { + ^next$ { + set n [WPCmd PEMailbox next $n $ppg] + + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n [WPCmd PEMailbox first] + set u [WPCmd PEMailbox uid $n] + } + } + ^prev$ { + if {$ppg >= $n} { + set n [WPCmd PEMailbox first] + } else { + set n [WPCmd PEMailbox next $n -$ppg] + } + + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n [WPCmd PEMailbox first] + set u 0 + } + } + ^first$ { + set n [WPCmd PEMailbox first] + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n 1 + set u 0 + } + } + ^last$ { + set n [WPCmd PEMailbox last] + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n 1 + set u 0 + } + } + ^delete$ { + if {[catch {WPCmd PEMailbox apply count new} trashed_new]} { + set trashed_new 0 + } + + if {[catch {WPCmd PEMailbox apply flag ton del} result]} { + WPCmd PEInfo statmsg "Delete failed: $result" + } else { + WPCmd PEInfo statmsg "$result message[WPplural $result] moved to Trash" + if {$trashed_new > 0} { + set trashed $trashed_new + } + } + } + ^trash$ { + if {[catch {WPCmd PEFolder empty $c [wpLiteralFolder $c $f] selected} result]} { + WPCmd PEInfo statmsg "Cannot Remove: $result" + } else { + WPCmd PEInfo statmsg "$result message[WPplural $result] deleted forever" + if {0 == [WPCmd PEMailbox messagecount]} { + set n 0 + set u 0 + } + set trashed [expr {$result * -1}] + } + } + ^trashall$ { + if {[catch {WPCmd PEFolder empty $c [wpLiteralFolder $c $f] all} result]} { + WPCmd PEInfo statmsg "Cannot Remove: $result" + } else { + WPCmd PEInfo statmsg "$result message[WPplural $result] deleted forever" + set n 0 + set u 0 + set trashed [expr {$result * -1}] + } + } + ^spam$ { + set numspam [WPCmd PEMailbox selected] + if {$numspam > 0} { + # aggregate save + if {[info exists _wp(spamsubj)] && [string length $_wp(spamsubj)]} { + set spamsubj $_wp(spamsubj) + } else { + set spamsubj "Spam Report" + } + + # aggregate delete + if {[info exists _wp(spamfolder)] && [string length $_wp(spamfolder)] + && [catch { + if {[WPCmd PEFolder exists $defc $_wp(spamfolder)] == 0} { + WPCmd PEFolder create $defc $_wp(spamfolder) + } + + WPCmd PEMailbox apply save $defc $_wp(spamfolder) + } result]} { + WPCmd PEInfo statmsg "Error Reporting Spam: $result" + } elseif {[info exists _wp(spamaddr)] && [string length $_wp(spamaddr)] + && [catch {WPCmd PEMailbox apply spam $_wp(spamaddr) $spamsubj} reason]} { + WPCmd PEInfo statmsg "Error Sending Spam Notice: $reason" + } elseif {[catch {WPCmd PEMailbox apply delete} reason]} { + WPCmd PEInfo statmsg "Error marking Spam Deleted: $reason" + } else { + WPCmd PEInfo statmsg "$numspam spam message[WPplural $numspam] reported" + } + } + } + ^copy$ { + if {[string length $df] && [regexp {^([0-9]+)/(.*)$} $df dummy dfc dfn] && [string length $dfn]} { + if {[catch {WPCmd PEMailbox apply count new} cpmv_new]} { + set cpmv_new 0 + } + + if {[catch {WPCmd PEMailbox apply copy $dfc $dfn} result]} { + WPCmd PEInfo statmsg "Cannot copy messages: $result" + } else { + if {$dfc == $defc + && !(([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || 0 == [string compare $f Trash])} { + addSaveCache $dfn + set savecachechange $dfn + set cpmvdest [cgi_quote_html $dfn] + if {$result > 0 && $cpmv_new > 0} { + set cpmv $cpmv_new + } + } + + WPCmd PEInfo statmsg "Copied $result message[WPplural $result] to $dfn" + } + } else { + WPCmd PEInfo statmsg "Cannot copy to $df" + } + } + ^move$ { + if {[string length $df] && [regexp {^([0-9]+)/(.*)$} $df dummy dfc dfn] && [string length $dfn]} { + if {[catch {WPCmd PEMailbox apply count new} cpmv_new]} { + set cpmv_new 0 + } + + if {[catch {WPCmd PEMailbox apply move $dfc $dfn} result]} { + WPCmd PEInfo statmsg "Move Failure: $result" + } else { + # if needed, empty what was moved + if {$c == [WPCmd PEFolder defaultcollection] + && (([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || 0 == [string compare $f Trash]) + && [catch {WPCmd PEFolder empty $c $f selected} result]} { + WPCmd PEInfo statmsg "Move Failure: $result" + } else { + if {$dfc == $defc + && !(([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || 0 == [string compare $f Trash])} { + addSaveCache $dfn + set savecachechange $dfn + set cpmvdest [cgi_quote_html $dfn] + if {$result > 0 && $cpmv_new > 0} { + set cpmv $cpmv_new + } + } + + # clean up moved messages so they don't get tossed in Trash as well + if {[catch {WPCmd PEMailbox expunge} blasted] || [string length $blasted]} { + WPCmd PEInfo statmsg "Move Failure: $blasted" + } else { + WPCmd PEInfo statmsg "Moved $result message[WPplural $result] to $dfn" + } + } + } + } else { + WPCmd PEInfo statmsg "Cannot move: to $df" + } + } + ^movemsg$ { + if {[regexp {^[0-9]+$} $uid] && $uid > 0 && [string length $df] && [regexp {^([0-9]+)/(.*)$} $df dummy dfc dfn] && [string length $dfn]} { + if {[catch { + # destination Trash? just delete and let regular delete process move it + if {$dfc == $defc && 0 == [string compare Trash $dfn]} { + WPCmd PEMessage $uid flag deleted 1 + } else { + WPCmd PEMessage $uid move $dfc $dfn + } + + # source is trash/junk, remove explicitly + if {$c == $defc + && (([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || 0 == [string compare $f Trash])} { + WPCmd PEFolder empty $c $f $uid + } + + WPCmd PEInfo statmsg "Moved message to $dfn" + set cpmvdest [cgi_quote_html $dfn] + if {0 != [WPCmd PEMessage $uid flag new]} { + set cpmv 1 + } + } result]} { + WPCmd PEInfo statmsg "Move Failure: $result" + } + } else { + WPCmd PEInfo statmsg "Cannot move: to $df" + } + } + ^sort[A-Za-z]+$ { + if {[regexp {^sort([[Rr]ev|)(.*)$} $op dummy rev sname]} { + set sort [string tolower $sname] + set rval [expr {[string length $rev] > 0}] + if {[catch {WPCmd PEMailbox sort $sort $rval} cursort]} { + WPCmd PEInfo statmsg "Cannot set sort: $cursor" + set cursort [list nonsense 0] + } else { + # store result + WPCmd set sort [list $sort $rval] + } + } else { + WPCmd PEInfo statmsg "Unrecognized Sort: $op" + } + } + ^search$ { + if {![regexp {broad|narrow} $scope]} { + WPCmd PEMailbox focus 0 + WPCmd PEMailbox search none + set scope broad + } + + switch -- $type { + none { + WPCmd PEMailbox focus 0 + WPCmd PEMailbox search none + } + any { + if {![string length $criteria]} { + WPCmd PEInfo statmsg "No search criteria provided" + } elseif {[catch {WPCmd PEMailbox search $scope text ton any $criteria} result]} { + WPCmd PEInfo statmsg "Search failed: $result" + } else { + if {$result == 0} { + WPCmd PEInfo statmsg "No messages matched your search" + cgi_html_comment "SCOPE: $scope" + if {0 == [string compare new $scope]} { + WPCmd PEMailbox focus 0 + WPCmd PEMailbox search none + } + } else { + set n [WPCmd PEMailbox first] + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n 1 + set u 0 + } + + focusOnResult focused + } + } + } + compound { + if {![string length $criteria]} { + WPCmd PEInfo statmsg "No search criteria provided" + } elseif {[catch {WPCmd PEMailbox search $scope compound $criteria} result]} { + WPCmd PEInfo statmsg "Search failed: $result" + } else { + if {$result == 0} { + WPCmd PEInfo statmsg "No messages matched your search" + if {0 == [string compare new $scope]} { + WPCmd PEMailbox focus 0 + WPCmd PEMailbox search none + } + } else { + set n [WPCmd PEMailbox first] + if {[catch {WPCmd PEMailbox uid $n} u]} { + set n 1 + set u 0 + } + + focusOnResult focused + } + } + } + default { + WPCmd PEInfo statmsg "Unrecognized search: $type" + } + } + } + ^focus$ { + focusOnResult focused + } + ^unfocus$ { + if {[catch {WPCmd PEMailbox focus 0} result]} { + WPCmd PEInfo statmsg "Cannot unfocus: $result" + } elseif {$focused > 0} { + WPCmd PEInfo statmsg "All messages displayed" + set focused 0 + } + } + noop - + ^$ { + } + default { + } + } +} + +if {$focused} { + set mc $focused +} + +# page framing (note maybe changed by actions above) +wpInitPageFraming u n mc ppg pn pt + +cgi_puts [WPCmd cgi_buffer "drawMessageList $c {$f} $n $ppg"] + +cgi_puts "<script>" +cgi_put "updateBrowseLinksAndSuch(\{" +cgi_put "u:$u,selected:[WPCmd PEMailbox selected]," +cgi_put "unread:[WPCmd PEMailbox flagcount [list unseen undeleted]]," +cgi_put "page:$pn,pages:$pt,count:$mc," +cgi_put "searched:[WPCmd PEMailbox searched],focused:$focused," +cgi_put "sort:'[lindex [WPCmd PEMailbox sort] 0]'" +if {[info exists trashed] && $trashed != 0} { + cgi_put ",trashed:$trashed" +} +if {[info exists cpmv] && $cpmv != 0} { + cgi_put ",cpmv:{f:'$cpmvdest',n:$cpmv}" +} +cgi_puts "\});" +if {0 == [string compare $page new]} { + cgi_puts "showBrowseMenus();" + cgi_puts "initMenus();" + cgi_puts "initMorcButton('listMorcButton');" + cgi_puts "initSelection();" + wpSaveMenuJavascript "browse" $c $f [WPCmd PEFolder defaultcollection] morcInBrowseDone + wpSetMessageListNewMailCheck + cgi_puts "if(self.loadDDElements) loadDDElements();" +} +if {[info exists savecachechange]} { + wpSaveMenuJavascript browse $c $f $defc morcInBrowseDone $savecachechange +} +wpStatusAndNewmailJavascript +cgi_puts "if(self.loadDDElements) loadDDElements();" +cgi_puts "</script>" diff --git a/web/cgi/alpine/2.0/newview.tcl b/web/cgi/alpine/2.0/newview.tcl new file mode 100755 index 00000000..afcc2f0b --- /dev/null +++ b/web/cgi/alpine/2.0/newview.tcl @@ -0,0 +1,306 @@ +#!./tclsh +# $Id: newview.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# newview.tcl +# +# Purpose: CGI script that generates a page displaying a message +# list of the indicated folder. +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_first_msg> +# along with possible search parameters: +set newview_args { + {op {} ""} + {df {} ""} + {img {} 0} + {page {} ""} +} + +# inherit global config +source ./alpine.tcl +source ./common.tcl +source ./foldercache.tcl + +# default newview state +set showimg "" + +# TEST +proc cgi_suffix {args} { + return "" +} + +proc next_message {_n _u {i 1}} { + upvar 1 $_n n + upvar 1 $_u u + + if {[catch {WPCmd PEMailbox next $n $i} nnext]} { + WPCmd PEInfo statmsg "Cannot get next message: $nnext" + } else { + set n $nnext + if {[catch {WPCmd PEMailbox uid $n} u]} { + WPCmd PEInfo statmsg "Message $nnext has no UID: $u" + set n 0 + set u 0 + } + } +} + +# grok PATH_INFO for collection 'c' and folder 'f' +if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {[regexp {^/([0-9]+)/(.*)/([0-9]+)$} $env(PATH_INFO) dummy c f u]} { + # Import data validate it and get session id + if {[catch {WPGetInputAndID sessid} result]} { + set harderr "Invalid Session: $result" + set deadsession 1 + } else { + # grok parameters + foreach item $newview_args { + if {[catch {eval WPImport $item} result]} { + set harderr "Cannot read input: $result" + break; + } + } + + if {[catch {WPCmd PEMessage $u number} n]} { + set harderr "Message no longer exists in $f" + } + } + } else { + set harderr "Invalid path: $env(PATH_INFO)" + set nofolder 1 + } +} else { + set harderr "No Folder Specified!" + set nofolder 1 +} + +if {[info exists harderr]} { + if {[info exists deadsession]} { + cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" + cgi_puts "Your Web Alpine Session has been closed." + } else { + catch { WPCmd PEInfo statmsg "$harderr" } + unset harderr + + if {[info exists nofolder]} { + set env(PATH_INFO) "/0/INBOX" + } else { + set env(PATH_INFO) "/${c}/${f}" + } + + source newlist.tcl + } + + exit +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" + +if {[catch {WPCmd PEMessage $u number} n]} { + WPCmd PEInfo statmsg "Message access error: $n" + set n 0 +} else { + switch -regexp -- $op { + ^next$ { + next_message n u + } + ^prev$ { + next_message n u -1 + } + ^hdron$ { + WPCmd PEInfo mode full-header-mode 2 + } + ^hdroff$ { + WPCmd PEInfo mode full-header-mode 0 + } + ^unread$ { + if {[catch {WPCmd PEMessage $u flag new 1} result]} { + WPCmd PEInfo statmsg "Delete of $u failed: $result" + } else { + next_message n u + } + } + ^delete$ { + if {[catch {WPCmd PEMessage $u flag deleted 1} result]} { + WPCmd PEInfo statmsg "Delete of $u failed: $result" + } else { + WPCmd PEInfo statmsg "Message moved to Trash" + if {$n == 1} { + next_message n u + set n 1 + } elseif {$n == [WPCmd PEMailbox messagecount]} { + next_message n u -1 + } else { + set nnext $n + next_message n u + set n $nnext + } + } + } + ^trash$ { + if {[catch {WPCmd PEFolder empty $c [wpLiteralFolder $c $f] $u} result]} { + WPCmd PEInfo statmsg "Cannot delete forever: $result" + } else { + WPCmd PEInfo statmsg "Message deleted forever" + set mc [WPCmd PEMailbox messagecount] + if {$mc == 0} { + set n 0 + set u 0 + } else { + if {$n > $mc} { + set n $mc + } + + if {[catch {WPCmd PEMailbox uid $n} u]} { + WPCmd PEInfo statmsg "Cannot get UID of $n: $u" + set n 0 + set u 0 + } + } + } + } + ^move$ - + ^copy$ { + if {[string length $df] && [regexp {^([0-9]+)/(.*)$} $df dummy dfc dfn] && [string length $dfn]} { + if {[catch {WPCmd PEMessage $u $op $dfc [wpLiteralFolder $dfc $dfn]} result]} { + WPCmd PEInfo statmsg "Cannot $op message $n: $result" + } else { + if {0 == [string compare $op move]} { + if {$c == [WPCmd PEFolder defaultcollection] + && (([info exists _wp(spamfolder)] && 0 == [string compare $f $_wp(spamfolder)]) + || 0 == [string compare $f Trash])} { + if {[catch {WPCmd PEFolder empty $c $f $u} result]} { + WPCmd PEInfo statmsg "Cannot empty Trash: $result" + } else { + set mc [WPCmd PEMailbox messagecount] + if {$mc == 0} { + set n 0 + set u 0 + } else { + if {$n > $mc} { + set n $mc + } + + if {[catch {WPCmd PEMailbox uid $n} u]} { + WPCmd PEInfo statmsg "Cannot get UID of $n: $u" + set n 0 + set u 0 + } + } + } + } else { + if {[catch {WPCmd PEMailbox expunge} blasted] || [string length $blasted]} { + WPCmd PEInfo statmsg "Move Problem: $blasted" + } + + next_message n u + } + } + + # feedback from alpined + if {[string compare -nocase inbox $dfn]} { + addSaveCache $dfn + set savecachechange $dfn + } + } + } else { + WPCmd PEInfo statmsg "Cannot $op to $df" + } + } + ^spam$ { + if {[info exists _wp(spamsubj)]} { + set spamsubj $_wp(spamsubj) + } else { + set spamsubj "Spam Report" + } + + if {[info exists _wp(spamfolder)] && [string length $_wp(spamfolder)] + && [catch { + set defc [WPCmd PEFolder defaultcollection] + if {[WPCmd PEFolder exists $defc $_wp(spamfolder)] == 0} { + WPCmd PEFolder create $defc $_wp(spamfolder) + } + + WPCmd PEMessage $u save $defc $_wp(spamfolder) + } result]} { + WPCmd PEInfo statmsg "Error spamifying message $message: $result" + + } elseif {[info exists _wp(spamaddr)] && [string length $_wp(spamaddr)] + && [catch {WPCmd PEMessage $u spam $_wp(spamaddr) $spamsubj} result]} { + WPCmd PEInfo statmsg "Can't Report Spam: $result" + } elseif {[catch {WPCmd PEMessage $u flag deleted 1} result]} { + WPCmd PEInfo statmsg "Error spamifying message $message: $result" + } else { + WPCmd PEInfo statmsg "Message $n reported as Spam and flagged for deletion" + if {$n == 1} { + next_message n u + set n 1 + } elseif {$n == [WPCmd PEMailbox messagecount]} { + next_message n u -1 + } else { + set nnext $n + next_message n u + set n $nnext + } + } + } + ^$ - + ^noop$ { + # $img == 0 : remove current from from allow_cid_images list + # $img == 1 : allow images for this message this once + # $img == "from" : always allow images from this address + if {[regexp {0|1|from} $img]} { + set showimg $img + } + } + default { + WPCmd PEInfo statmsg "Unrecognized option: $op" + } + } +} + +if {$n > 0} { + cgi_puts [WPCmd cgi_buffer "drawMessageText $c {$f} $u $showimg"] + cgi_puts "<script>" + if {0 == [catch {WPCmd PEMessage $u needpasswd}]} { + cgi_put "getSmimePassphrase({sessid:'$_wp(sessid)',control:this,parms:{op:'noop',page:'new'}});" + } + if {[catch {WPCmd PEMailbox next $n 1} nnext]} { + WPCmd PEInfo statmsg "Cannot get next message: $nnext" + } else { + if {[catch {WPCmd PEMailbox uid $nnext} unext]} { + WPCmd PEInfo statmsg "Message $nnext has no UID: $unext" + set unext 0 + } + } + cgi_puts "updateViewLinksAndSuch(\{u:$u,n:$n,unext:$unext,unread:[WPCmd PEMailbox flagcount [list unseen undeleted]],count:[WPCmd PEMailbox messagecount],selected:[WPCmd PEMailbox selected]\});" + if {0 == [string compare new $page]} { + cgi_puts "showViewMenus();" + cgi_puts "initMenus();" + cgi_puts "initMorcButton('viewMorcButton');" + wpSaveMenuJavascript "view" $c $f [WPCmd PEFolder defaultcollection] morcInViewDone + } + if {[info exists savecachechange]} { + wpSaveMenuJavascript "view" $c $f [WPCmd PEFolder defaultcollection] morcInViewDone $savecachechange + } + + cgi_puts "document.getElementById('alpineContent').scrollTop = 0;" + wpStatusAndNewmailJavascript + cgi_puts "setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts "setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + cgi_puts "</script>" +} else { + cgi_puts "<script>" + cgi_puts "updateViewLinksAndSuch({});" + wpStatusAndNewmailJavascript + cgi_puts "</script>" +} diff --git a/web/cgi/alpine/2.0/reply b/web/cgi/alpine/2.0/reply new file mode 120000 index 00000000..872d4cb2 --- /dev/null +++ b/web/cgi/alpine/2.0/reply @@ -0,0 +1 @@ +compose
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/replyall b/web/cgi/alpine/2.0/replyall new file mode 120000 index 00000000..872d4cb2 --- /dev/null +++ b/web/cgi/alpine/2.0/replyall @@ -0,0 +1 @@ +compose
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/resume b/web/cgi/alpine/2.0/resume new file mode 120000 index 00000000..872d4cb2 --- /dev/null +++ b/web/cgi/alpine/2.0/resume @@ -0,0 +1 @@ +compose
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/settings b/web/cgi/alpine/2.0/settings new file mode 100755 index 00000000..dc69487d --- /dev/null +++ b/web/cgi/alpine/2.0/settings @@ -0,0 +1,734 @@ +#!./tclsh +# $Id: settings 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# view.tcl +# +# Purpose: CGI script settings for Web Alpine 2.0 settings page +# +# Input: +# +set settings_args { +} + +# inherit global config +source ./alpine.tcl +source ./foldercache.tcl +source ./common.tcl + +set script_base "$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + +# TEST +proc cgi_suffix {args} { + return "" +} + +set labels 0 +proc set_feature {feature desc} { + global labels + cgi_checkbox $feature=1 [set_checked [WPCmd PEInfo feature $feature]] id="label_[incr labels]" + cgi_put " <label for=\"label_${labels}\">$desc</label>" +} + +proc set_checked {checked {token checked}} { + if {$checked > 0} { + return $token + } + + return "" +} + +proc set_variable {var {desc ""}} { + global labels + if {[string length $desc]} { + cgi_put "<label for=\"label_[incr labels]\">${desc}</label>" + } + cgi_text ${var}=[var_value $var] id="label_${labels}" +} + + +WPEval $settings_args { + + if {0 == [catch {WPCmd PEFolder current} curfold]} { + set c [lindex $curfold 0] + set f [lindex $curfold 1] + } else { + set c 0 + set f inbox + } + + set charset "UTF-8" + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + cgi_html { + cgi_head { + cgi_content_type "text/html; charset=$charset" + cgi_title [wpPageTitle "Settings"] + cgi_base "href=$script_base" + cgi_stylesheet css/cbn/screen.css + # Yahoo Styles + cgi_stylesheet $_wp(yui)/build/container/assets/container-core.css + cgi_stylesheet $_wp(yui)/build/menu/assets/skins/sam/menu.css + cgi_stylesheet $_wp(yui)/build/button/assets/skins/sam/button.css + # YahooUI libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/menu/menu-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + # local libraries + cgi_script language="JavaScript" src="lib/common.js" {} + cgi_script language="JavaScript" src="lib/settings.js" {} + cgi_javascript { + cgi_puts "YAHOO.alpine.cgi_root = '$_wp(serverpath)';" + cgi_puts "YAHOO.alpine.cgi_base = '$script_base';" + cgi_puts "YAHOO.alpine.current.incoming = [WPCmd PEFolder isincoming $c];" + cgi_puts "YAHOO.alpine.current.c = $c;" + cgi_puts "YAHOO.alpine.current.f = \"$f\";" + cgi_puts "function bodyOnLoad() {" + cgi_puts " if(YAHOO.env.ua.gecko > 0){ sizeVPHeight(); window.onresize = resizeVPHeight; }" + cgi_puts " setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + cgi_puts "}" + cgi_puts "browserDetect();" + } + } + + cgi_body class=wap "onLoad=bodyOnLoad()" { + cgi_puts {<iframe name="formResponse" id="formResponse" src="img/cbn/spritelib.gif"></iframe>} + wpCommonPageLayout {settings { + cgi_hr + cgi_division { + cgi_put [cgi_url [cgi_span "class=sp splci tbi5" "Back to $f"] browse/$c/$f class=wap title="Return to $f without saving changes"] + } + cgi_hr + cgi_division class="ftitle bld" { + cgi_put "Basic Settings" + } + cgi_division "class=\"bld sel\"" { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "General Preferences"] # class=wap id=Page1 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Personal Preferences"] # class=wap id=Page2 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "News and Weather"] # class=wap id=Page3 "onClick=return settingsPage(this);"] + } + cgi_division class="ftitle bld" "style=\"margin-top: 2em;\"" { + cgi_put [cgi_url "[cgi_img img/cbn/f_plus.gif class=wap] Advanced Settings" # class=wap "onClick=return toggleAdvance(this);"] + } + cgi_division id=advancedSettings { + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Message List"] # class=wap id=Page4 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Message View"] # class=wap id=Page5 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Folders"] # class=wap id=Page8 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Compose"] # class=wap id=Page6 "onClick=return settingsPage(this);"] + } + cgi_division class="ftitle bld" "style=\"margin-top: 2em;\"" { + cgi_put "Server Settings" + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Mail Servers"] # class=wap id=Page10 "onClick=return settingsPage(this);"] + } + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Directory Servers"] # class=wap id=Page9 "onClick=return settingsPage(this);"] + } + } + if {[info exists _wp(filter_link)] || [info exists _wp(vacation_link)]} { + cgi_division class="ftitle bld" "style=\"margin-top: 2em;\"" { + cgi_put "External Settings" + } + } + if {[info exists _wp(filter_link)]} { + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Message Filtering"] $_wp(filter_link) class=wap target=_blank] + } + } + if {[info exists _wp(vacation_link)]} { + cgi_division class=bld { + cgi_put [cgi_url [cgi_span "class=sp splcs splc12" "Vacation Auto-Reply"] $_wp(vacation_link) class=wap target=_blank] + } + } + }} "$c" "$f" 0 Settings \ + [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/browse/${c}/${f}"] Settings 0 searchContent('settings','alpineContent')] "" { + # CONTEXT COMMANDS + cgi_division class=hdrBtns { + cgi_javascript { + cgi_put "if(window.print) document.write('[cgi_buffer {cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"]}]');" + } + + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" "javascript:openHelpWindow('settings.html');" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"] + } + } { + # TOP MENUBAR + cgi_anchor_name "toolbar" + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data { + cgi_table class="toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_table_row { + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb10" "Save Settings"] "#" title="Save Settings Changes" "onClick=return saveSettings();"] + } + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb21" "Reset to Default Settings"] "#" "onClick=panelConfirm('Restoring default settings will erase all custom settings.<p>Are you sure you want to restore default settings?',{text:'Restore Defaults',fn:restoreDefaultSettings}); return false;" title="Reset to Default Settings"] + } + cgi_table_data class="wap" { + cgi_put [cgi_url [cgi_span "class=sp spmbi spmb12" "Cancel"] "browse/$c/$f" title="Cancel Settings Changes"] + } + cgi_table_data width="100%" { + cgi_puts [cgi_nbspace] + } + } + cgi_puts "</tbody>" + } + } + } + cgi_puts "</tbody>" + } + } { + cgi_form $_wp(appdir)/$_wp(ui2dir)/conduit/settings.tcl "enctype=multipart/form-data" id=settingsForm target=formResponse { + cgi_text "restore=false" id=restore type=hidden notab + cgi_table id=settingsPage1 "class=\"fields settings\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>General Preferences</h2></td></tr>" + cgi_table_row { + cgi_table_data class="title" { + cgi_puts "Message Display" + #[cgi_br]<a href="#" title="more info..." onClick="help_popup1.showPopup('anchor1');return false;" name="anchor1" id="anchor1"><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + if {[info exists _wp(themes)]} { + cgi_put "Theme: " + cgi_select theme { + foreach theme $_wp(themes) { + cgi_option [lindex $theme 0] value=[lindex $theme 1] + } + } + cgi_br + } + cgi_put "Display " + set n [var_value wp-indexlines] + cgi_select wp-indexlines { + for {set i 10} {$i <= $_wp(indexlinesmax)} {incr i 5} { + cgi_option $i value=$i [set_checked [expr {$i == $n}] selected] + } + } + cgi_put " messages per page" + cgi_br + cgi_put "Wrap Plain Text message at " + set n [WPCmd PEConfig columns] + cgi_select wrapColumn { + for {set i 20} {$i < 130} {incr i 4} { + cgi_option $i value=$i [set_checked [expr {$i == $n}] selected] + } + } + cgi_put " characters" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Folders" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + cgi_put "Display " + if {[catch {WPSessionState left_column_folders} n]} { + set n $_wp(fldr_cache_def) + } + + cgi_select folderCache { + for {set i 5} {$i <= $_wp(fldr_cache_max)} {incr i} { + cgi_option $i value=$i [set_checked [expr {$i == $n}] selected] + } + } + cgi_put " recent folders in left column" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Reply[cgi_nbspace]Options" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_feature include-header-in-reply "Include headers in replies" + cgi_br + set_feature include-attachments-in-reply "Include attachments in replies" + cgi_br + set_feature signature-at-bottom "Append signature below reply text" + cgi_br + set_feature strip-from-sigdashes-on-reply "Strip signatures when replying" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Forwarding[cgi_nbspace]Options" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set as_attach [WPCmd PEInfo feature forward-as-attachment] + cgi_radio_button forwardAs=inline id="forward_inline" [set_checked [expr {$as_attach == 0}]] + cgi_put " <label for=forward_inline>Forward messsages inline</label>" + cgi_br + cgi_radio_button forwardAs=attached id="forward_attachment" [set_checked $as_attach] + cgi_put " <label for=forward_attachment>Forward messsages as attachments</label>" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Sent[cgi_nbspace]Message[cgi_nbspace]Options" + cgi_put "<p><span class=tips><strong>Tip:</strong> Set folder blank to prevent saving of Sent messages</span>" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + + } + cgi_table_data class="body" { + set_variable default-fcc "Name of your Sent mail folder (also called \"Fcc\"): " + cgi_br + set_feature fcc-without-attachments "Save sent messages to Sent folder without attachments" + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage2 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Personal[cgi_nbspace]Information</h2></td></tr>" + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Display[cgi_nbspace]Name" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable personal-name + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "User[cgi_nbspace]Domain" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable user-domain + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Email[cgi_nbspace]Signature" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + #<input name="signature" id="no_sig" type="radio" checked /> + #<label for="no_sig">No Signature</label><br> + #<input name="signature" id="use_sig" type="radio" /> + #<label for="use_sig">Append Signature when composing messages</label><br> + cgi_textarea signature=[join [WPCmd PEInfo rawsig] "\n"] cols="72" rows="5" title=Signature + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Alternate[cgi_nbspace]Addresses" + cgi_put "<p><span class=tips><b>Tip:</b> List alternate email addresses " + cgi_put "you use. Reply All will not include" + cgi_put "these email addresses when replying.</span>" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + cgi_put "Add/Remove Addresses: <input type=button name=addCH value=Add onClick=\"return listAdd('altAddrTable','altAddr');\"/>" + set varval [WPCmd PEConfig varget alt-addresses] + cgi_text "altAddrs=[llength [lindex $varval 0]]" id=altAddrs type=hidden notab + cgi_table id=altAddrTable { + set n 0 + foreach svr [lindex $varval 0] { + incr n + cgi_table_row { + cgi_table_data { + cgi_text altAddr${n}=[string trim $svr] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage3 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>News[cgi_nbspace]and[cgi_nbspace]Weather</h2></td></tr>" + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Headline[cgi_nbspace]News" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + cgi_put "RSS URL: " + cgi_text rss-news=[var_value rss-news] size="45" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Weather[cgi_nbspace]Bar" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + cgi_put "RSS URL: " + cgi_text rss-weather=[var_value rss-weather] size="45" + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage4 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Message[cgi_nbspace]List</h2></td></tr>" + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Message List" + } + cgi_table_data class="body" { + cgi_table { + cgi_put "<tbody>" + cgi_table_row { + cgi_table_data { + cgi_put "Sort Order (default): " + } + cgi_table_data { + set val [WPCmd PEConfig varget sort-key] + cgi_select sort-key { + foreach k [lindex $val 2] { + cgi_option $k value=$k [set_checked [expr {0 == [string compare -nocase $k [lindex $val 0]]}] selected] + } + } + } + } + cgi_table_row { + cgi_table_data { + cgi_put "Start display at:" + } + cgi_table_data { + set val [WPCmd PEConfig varget incoming-startup-rule] + cgi_select incoming-startup-rule { + foreach k [lindex $val 2] { + cgi_option $k value=$k [set_checked [expr {0 == [string compare -nocase $k [lindex $val 0]]}] selected] + } + } + } + } + cgi_put "</tbody>" + } + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Message[cgi_nbspace]Handling" + } + cgi_table_data class="body" { + set_variable read-message-folder "Name of the folder to hold your read messages: " + cgi_br + set_feature auto-move-read-msgs "Automatically Move Read Messages" + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage5 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Message View</h2></td></tr>" + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Display[cgi_nbspace]Headers" + } + cgi_table_data class="body" { + cgi_put "Add/Remove Header Names: <input type=button name=addCH value=Add onClick=\"return listAdd('viewerHdrsTable','viewerHdr');\"/>" + set varval [WPCmd PEConfig varget viewer-hdrs] + cgi_text "viewerHdrs=[llength [lindex $varval 0]]" id=viewerHdrs type=hidden notab + cgi_table id=viewerHdrsTable { + set n 0 + foreach svr [lindex $varval 0] { + incr n + cgi_table_row { + cgi_table_data { + cgi_text viewerHdr${n}=[string trim $svr] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Display[cgi_nbspace]Links[cgi_nbspace]in[cgi_nbspace]Messages" + cgi_put "<p><span class=tips><b>Tip:</b> Applies only to plain text messages.</span>" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + cgi_table { + cgi_put "<tbody>" + cgi_table_row { + cgi_table_data { + set_feature enable-msg-view-urls "Display complete URLs as links" + } + } + cgi_table_row { + cgi_table_data { + set_feature enable-msg-view-web-hostnames "Display hostnames and incomplete URLs as links" + } + } + cgi_table_row { + cgi_table_data { + set_feature enable-msg-view-addresses "Display Email addresses as links" + } + } + cgi_put "</tbody>" + } + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Rich[cgi_nbspace]Text[cgi_nbspace]Display" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_feature render-html-internally "Show rich text messages as plain text" + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Anti-phishing" + cgi_put "<p><span class=tips><b>Tip:</b> This feature aids in identifying fake links. Applies only when rich text shown as plain text.</span>" + #<br><a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_feature quell-server-after-link-in-html "Hide appended real hostname after links" + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage6 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Compose</h2></td></tr>" + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Compose[cgi_nbspace]Headers" + cgi_put "<p><span class=tips><b>Tip:</b> Default header fields displayed in Compose</span>" + } + cgi_table_data class="body" { + cgi_put "Add/Remove Header Names: <input type=button name=addCH value=Add onClick=\"return listAdd('composeHdrsTable','composeHdr');\"/>" + set varval [WPCmd PEConfig varget default-composer-hdrs] + cgi_text "composeHdrs=[llength [lindex $varval 0]]" id=composeHdrs type=hidden notab + cgi_table id=composeHdrsTable { + set n 0 + foreach svr [lindex $varval 0] { + incr n + cgi_table_row { + cgi_table_data { + cgi_text composeHdr${n}=[string trim $svr] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Custom[cgi_nbspace]Headers" + } + cgi_table_data class="body" { + cgi_put "Add/Remove Headers: <input type=button name=addhdr value=Add onClick=\"return customHdrAdd('customHdrTbl');\"/>" + set varval [WPCmd PEConfig varget customized-hdrs] + cgi_text "customHdrFields=[llength [lindex $varval 0]]" id=customHdrFields type=hidden notab + cgi_table id=customHdrTbl { + set nh 0 + foreach hdr [lindex $varval 0] { + incr nh + cgi_table_row { + set n [string first {:} $hdr] + switch -- $n { + -1 - + 0 - + 1 { + cgi_table_data colspan=2 { + cgi_text "customHdrField${nh}=[cgi_quote_html $hdr]" type=hidden notab + cgi_put "$hdr" + } + } + default { + cgi_table_data { + set field_name [string range $hdr 0 [expr {$n - 1}]] + cgi_put $field_name + cgi_text "customHdrField${nh}=[cgi_quote_html $field_name]" type=hidden notab + } + cgi_table_data { + cgi_text customHdrData${nh}=[string trim [string range $hdr [incr n] end]] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Message[cgi_nbspace]Encoding" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable posting-character-set "Send messages using character encoding: " + } + } + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Reply[cgi_nbspace]Options" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable reply-leadin "Reply intro string: " + cgi_br + set_variable reply-indent-string "Reply prefix: " + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Flowed[cgi_nbspace]Text[cgi_nbspace]Handling" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_feature quell-flowed-text "Do not send text as Flowed Text" + } + } + cgi_puts "</tbody>" + } + cgi_table id=settingsPage7 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Filters</h2></td></tr>" + + cgi_puts "</tbody>" + } + cgi_table id=settingsPage8 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Folders</h2></td></tr>" + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Draft[cgi_nbspace]Folder" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable postponed-folder + } + } + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Trash[cgi_nbspace]Folder" + #[cgi_br]<a href="#" title="more info..."><img src="img/cbn/help_sm.gif"></a> + } + cgi_table_data class="body" { + set_variable trash-folder + } + } + cgi_puts "</tbody>" + } + if {0 == [catch {WPCmd PEConfig varget ldap-servers} varval]} { + cgi_table id=settingsPage9 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Directory[cgi_nbspace]Servers</h2></td></tr>" + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "LDAP[cgi_nbspace]Server" + } + cgi_table_data class="body" { + cgi_put "Add/Remove Servers: <input type=button name=addldap value=Add onClick=\"return listAdd('ldapServerTable','ldapServer');\"/>" + cgi_text "ldapServers=[llength [lindex $varval 0]]" id=ldapServers type=hidden notab + cgi_table id=ldapServerTable { + set n 0 + foreach svr [lindex $varval 0] { + incr n + cgi_table_row { + cgi_table_data { + cgi_text ldapServer${n}=[string trim $svr] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + + cgi_puts "</tbody>" + } + } + cgi_table id=settingsPage10 "class=\"fields settings\"" "style=\"display: none;\"" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody>" + cgi_puts "<tr><td class=title colspan=2><h2>Mail[cgi_nbspace]Servers</h2></td></tr>" + cgi_table_row { + cgi_table_data class="title" { + cgi_put "Inbox[cgi_nbspace]Server" + cgi_put "<p><span class=tips><b>Tip:</b> Server name inside brackets, folder name after</span>" + } + cgi_table_data class="body" { + cgi_text inbox-path=[var_value inbox-path] size="45" + } + } + + cgi_table_row { + cgi_table_data class="title" { + cgi_put "SMTP[cgi_nbspace]Server" + } + cgi_table_data class="body" { + cgi_put "Add/Remove Servers: <input type=button name=addsmtp value=Add onClick=\"return listAdd('smtpServerTable','smtpServer');\"/>" + set varval [WPCmd PEConfig varget smtp-server] + cgi_text "smtpServers=[llength [lindex $varval 0]]" id=smtpServers type=hidden notab + cgi_table id=smtpServerTable { + set n 0 + foreach svr [lindex $varval 0] { + incr n + cgi_table_row { + cgi_table_data { + cgi_text smtpServer${n}=[string trim $svr] size="45" + cgi_put [cgi_url [cgi_img img/cbn/remove.gif class=wap] # "onClick=return removeTableRow(this);"] + } + } + } + } + } + } + + cgi_puts "</tbody>" + } + } + } { + # BOTTOM MENUBAR + cgi_table class="wap toolbarTbl" cellpadding="0" cellspacing="0" { + cgi_puts "<tbody><tr><td> </td></tr></tbody>" + } + } + } + } +} diff --git a/web/cgi/alpine/2.0/tclsh b/web/cgi/alpine/2.0/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/alpine/2.0/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/alpine/2.0/view b/web/cgi/alpine/2.0/view new file mode 100755 index 00000000..0466c2e2 --- /dev/null +++ b/web/cgi/alpine/2.0/view @@ -0,0 +1,237 @@ +#!./tclsh +# $Id: view 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# view.tcl +# +# Purpose: CGI script generating page to display text of requested +# message +# +# Input: PATH_INFO: [/<col_number>]/<folder_name>[/<uid_of_viewed_msg> +# along with possible search parameters: +set view_args { + {delete {} 0} + {spam {} 0} + {unread {} 0} + {star {} {}} + {showimg {} {}} + {hideimg {} {}} + {searchText {} {}} +} + + +# On input failure, redirect to home page "browse" +proc view_redirect {} { + global _wp + + cgi_http_head { + cgi_redirect "[cgi_root]/$_wp(appdir)/$_wp(ui2dir)/browse" + } +} + +# inherit global config +source ./alpine.tcl +source ./common.tcl +source ./foldercache.tcl +source ./messageview.tcl + +# TEST +proc cgi_suffix {args} { + return "" +} + +# for inserting debug comments at end of page +set dmsgs "" +proc dm {s} { + global dmsgs + lappend dmsgs $s +} + + +WPEval $view_args { + # grok PATH_INFO for collection 'c' and folder 'f' + if {[info exists env(PATH_INFO)] && [string length $env(PATH_INFO)]} { + if {0 == [regexp {^/([0-9]+)/(.*)/([0-9]+)$} $env(PATH_INFO) dummy c f u]} { + WPCmd PEInfo statmsg "Cannot open invalid path: $env(PATH_INFO)" + error [list _redirect "[cgi_root]/$_wp(appdir)/$_wp(ui2dir)/browse/0/INBOX"] + } + } else { + WPCmd PEInfo statmsg "Cannot view unspecified folder" + error [list _redirect "[cgi_root]/$_wp(appdir)/$_wp(ui2dir)/browse/0/INBOX"] + } + + # verify or visit specified collection/folder + if {[catch {setCurrentFolder c f u} result]} { + set authlist [wpHandleAuthException $result [list $c "folders in collection"] $f] + if {0 == [llength $authlist]} { + WPCmd PEInfo statmsg "$result" + error [list _redirect "$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/browse/$c/$f"] + } + } + + # load message drawing routine for this session + # save per-message source, proc overhead + # to reinstall on the fly: + #catch {WPCmd rename drawMessageText {}} + if {0 == [llength [WPCmd info commands drawMessageText]]} { + set cgidir [file join $_wp(cgipath) $_wp(appdir) $_wp(ui2dir)] + if {[catch { + WPCmd source "${cgidir}/messageview.tcl" + WPCmd source "${cgidir}/messagelist.tcl" + } result]} { + error [list _action browse "cannot load message viewer: $result"] + } + } + + # process any actions specified by view_args + if {$delete > 0} { + if {0 == [catch [WPCmd PEMessage $delete number] dnum]} { + + } + # ELSE already deleted, don't worry about it + } elseif {$spam > 0} { + if {0 == [catch [WPCmd PEMessage $spam number] snum]} { + + } + # ELSE already reported, don't worry about it + } elseif {$unread > 0} { + if {[catch {WPCmd PEMessage $unread flag new 1} result]} { + # ERROR: Cannot set $u unread + } + } elseif {[string length $star]} { + switch -- $star { + 0 { + if {[catch {WPCmd PEMessage $u flag important 0} result]} { + # ERROR: Cannot set Star on message $u + } + } + 1 { + if {[catch {WPCmd PEMessage $u flag important 1} result]} { + # ERROR: Cannot set Star on message $u + } + } + default {} + } + } + + if {[catch {WPCmd PEMessage $u charset} charset] + || [string length $charset] == 0 + || [string compare us-ascii [string tolower $charset]] == 0} { + set charset "ISO-8859-1" + } + + if {[catch {WPCmd PEMessage $u number} n]} { + WPCmd PEInfo statmsg "$n" + error [list _redirect "$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/browse/$c/$f"] + } + + cgi_http_head { + WPStdHttpHdrs "text/html; charset=$charset" + } + + # counts and so forth + set mc [WPCmd PEMailbox messagecount] + + set unext [WPCmd PEMailbox uid [WPCmd PEMailbox next $n 1]] + set delim [WPCmd PEFolder delimiter $c] + + + cgi_html { + cgi_head { + cgi_content_type "text/html; charset=$charset" + cgi_title [wpPageTitle "Message $n of $mc in $f"] + cgi_base "href=$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/" + cgi_stylesheet css/menu.css + cgi_stylesheet css/cbn/screen.css + cgi_stylesheet css/cbn/folderdialog.css + cgi_stylesheet $_wp(yui)/build/container/assets/container-core.css + cgi_stylesheet $_wp(yui)/build/menu/assets/skins/sam/menu.css + cgi_stylesheet $_wp(yui)/build/button/assets/skins/sam/button.css + # Yahoo UI libraries + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/utilities/utilities.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/container/container-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/datasource/datasource-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/menu/menu-min.js" {} + cgi_script type=text/javascript language="JavaScript" src="$_wp(yui)/build/button/button-min.js" {} + # local libraries + cgi_script type=text/javascript language="JavaScript" src="lib/common.js" {} + cgi_script type=text/javascript language="JavaScript" src="lib/mailbox.js" {} + # page specfic JS + cgi_javascript { + cgi_puts "YAHOO.alpine.cgi_root = '$_wp(serverpath)';" + cgi_puts "YAHOO.alpine.app_root = '$_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)';" + cgi_puts "YAHOO.alpine.current.c = $c;" + cgi_puts "YAHOO.alpine.current.f = \"$f\";" + cgi_puts "YAHOO.alpine.current.u = $u;" + cgi_puts "YAHOO.alpine.current.count = $mc;" + cgi_puts "YAHOO.alpine.current.selected = [WPCmd PEMailbox selected];" + cgi_puts "YAHOO.alpine.current.searched = [WPCmd PEMailbox searched];" + cgi_puts "YAHOO.alpine.current.focused = [WPCmd PEMailbox focus];" + cgi_puts "function bodyOnLoad() {" + cgi_puts " initMenus();" + cgi_puts " initMorcButton('viewMorcButton');" + cgi_puts " if(YAHOO.env.ua.gecko > 0){ sizeVPHeight(); window.onresize = resizeVPHeight; }" + cgi_puts " setCheckMailFunction('gCheck', newMailCheck);" + cgi_puts " setNewMailCheckInterval([WPCmd PEInfo inputtimeout]);" + wpStatusAndNewmailJavascript + wpSaveMenuJavascript "view" $c $f [WPCmd PEFolder defaultcollection] morcInViewDone + cgi_puts "}" + + cgi_puts "browserDetect();" + } + } + + cgi_body class=wap "onLoad=bodyOnLoad()" { + cgi_division id="skip" { + cgi_put [cgi_url "Skip to Next Message" "#" "onClick=return newMessageText({control:this,parms:{op:'next'}});"] + cgi_put [cgi_url "Skip to Message List" "browse"] + cgi_put [cgi_url "Skip to Folders" "folders"] + cgi_put [cgi_url "Skip to Compose" "compose"] + } + + wpCommonPageLayout view $c $f $u [cgi_url "[cgi_quote_html $f], Message $n of $mc" browse/$c/[WPPercentQuote $f $delim] id=gBigContext] [list [cgi_cgi "$_wp(appdir)/$_wp(ui2dir)/browse/${c}/${f}?u=${u}"] "$f" 1 mailboxSearch()] {} { + # CONTEXT COMMANDS + cgi_division class=hdrBtns { + cgi_javascript { + cgi_put "if(window.print) document.write('[cgi_buffer {cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi1" ""][cgi_span "class=hdrBtnText" Print]" "print" "onClick=return printContent()"]}]');" + } + + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi2" ""][cgi_span "class=hdrBtnText" Settings]" "settings"] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi3" ""][cgi_span "class=hdrBtnText" Help]" # "onClick=return openMailboxHelp();" class=wap] + cgi_put [cgi_url "[cgi_span "class=sp hdrBtnImg hbi4" ""][cgi_span "class=hdrBtnText" "Sign out"]" "../../session/logout.tcl?cid=[WPCmd PEInfo key]&sessid=${sessid}"] + } + } { + cgi_division id=listTopMenubar "style=\"display: none;\"" { + cgi_puts [WPCmd cgi_buffer "drawTopListMenuBar $c {$f}"] + } + cgi_division id=viewTopMenubar { + cgi_puts [WPCmd cgi_buffer "drawTopViewMenuBar $c {$f} $u $n"] + } + } { + cgi_puts [WPCmd cgi_buffer "drawMessageText $c {$f} $u $showimg"] + } { + cgi_division id=listBottomMenubar "style=\"display: none;\"" { + cgi_puts [WPCmd cgi_buffer "drawBottomListMenuBar $c {$f} 0 0 $mc"] + } + cgi_division id=viewBottomMenubar { + cgi_puts [WPCmd cgi_buffer "drawBottomViewMenuBar $c {$f} $u $n $mc"] + } + } + + # any debugging info to insert? + foreach dmsg $dmsgs { + cgi_html_comment "DEBUG: $dmsg" + cgi_puts "" + } + } + } +} diff --git a/web/cgi/alpine/alpine.tcl b/web/cgi/alpine/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/alpine/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/alpine/farewell.tcl b/web/cgi/alpine/farewell.tcl new file mode 100755 index 00000000..e9157bde --- /dev/null +++ b/web/cgi/alpine/farewell.tcl @@ -0,0 +1,40 @@ +#!./tclsh +# $Id: farewell.tcl 764 2007-10-23 23:44:49Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +# Input: +set fw_vars { + {serverid {} 0} + {verdir {} "/"} +} + +# Output: +# + +# global config +source ./alpine.tcl + +WPEval $fw_vars { + if {[catch {cgi_import logerr}] == 0} { + set parms "?logerr=$logerr" + } else { + set parms "" + } + + cgi_http_head { + # clear cookies + cgi_cookie_set sessid=0 expires=now path=[file join / $verdir] + + cgi_redirect $_wp(serverpath)/session/logout/logout.tcl${parms} + } +} diff --git a/web/cgi/alpine/tclsh b/web/cgi/alpine/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/alpine/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/alpine/whackatch.tcl b/web/cgi/alpine/whackatch.tcl new file mode 100755 index 00000000..cca94724 --- /dev/null +++ b/web/cgi/alpine/whackatch.tcl @@ -0,0 +1,46 @@ +#!./tclsh +# $Id: whackatch.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# whackatch.tcl +# +# Purpose: CGI script to cleanup requested attachment + +# Input: +# ext - attachment file extension + +# Output: +# + +# inherit global config +source ./alpine.tcl + +# seconds to pause before rechecking for abandanded attachment files +set abandoned 300 + +# no dots allowed +if {[gets stdin ext] >= 0 && [regexp {^[A-Za-z0-9\-]+$} $ext ext] == 1} { + + set towhack [file join $_wp(fileroot) $_wp(detachpath) detach.${ext}] + + while {1} { + set timein [clock seconds] + + after [expr {$abandoned * 1000}] + + if {[catch {file atime $towhack} atime] || ($timein - $atime) > $abandoned} { + break + } + } + + catch {exec /bin/rm -f $towhack} +} diff --git a/web/cgi/detach b/web/cgi/detach new file mode 120000 index 00000000..d1373a3e --- /dev/null +++ b/web/cgi/detach @@ -0,0 +1 @@ +/tmp/webpine
\ No newline at end of file diff --git a/web/cgi/favicon.ico b/web/cgi/favicon.ico Binary files differnew file mode 100755 index 00000000..2ed8ef56 --- /dev/null +++ b/web/cgi/favicon.ico diff --git a/web/cgi/greeting.tcl b/web/cgi/greeting.tcl new file mode 100755 index 00000000..c24a65a5 --- /dev/null +++ b/web/cgi/greeting.tcl @@ -0,0 +1,21 @@ +#!./tclsh + +# ======================================================================== +# Copyright 2006-2007 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +source ./alpine.tcl + +cgi_eval { + + cgi_http_head { + cgi_redirect [cgi_root]/session/greeting.tcl + } +} diff --git a/web/cgi/images/Lavender_Chiffon.gif b/web/cgi/images/Lavender_Chiffon.gif Binary files differnew file mode 100644 index 00000000..19e4d468 --- /dev/null +++ b/web/cgi/images/Lavender_Chiffon.gif diff --git a/web/cgi/images/b_minus.gif b/web/cgi/images/b_minus.gif Binary files differnew file mode 100644 index 00000000..7b54f750 --- /dev/null +++ b/web/cgi/images/b_minus.gif diff --git a/web/cgi/images/b_plus.gif b/web/cgi/images/b_plus.gif Binary files differnew file mode 100644 index 00000000..f39a3c01 --- /dev/null +++ b/web/cgi/images/b_plus.gif diff --git a/web/cgi/images/barblank.gif b/web/cgi/images/barblank.gif Binary files differnew file mode 100644 index 00000000..d98b7b2e --- /dev/null +++ b/web/cgi/images/barblank.gif diff --git a/web/cgi/images/barclose.gif b/web/cgi/images/barclose.gif Binary files differnew file mode 100644 index 00000000..f1616283 --- /dev/null +++ b/web/cgi/images/barclose.gif diff --git a/web/cgi/images/barclose_mid.gif b/web/cgi/images/barclose_mid.gif Binary files differnew file mode 100644 index 00000000..41981b68 --- /dev/null +++ b/web/cgi/images/barclose_mid.gif diff --git a/web/cgi/images/barmsg.gif b/web/cgi/images/barmsg.gif Binary files differnew file mode 100644 index 00000000..b5d17e1f --- /dev/null +++ b/web/cgi/images/barmsg.gif diff --git a/web/cgi/images/baropen.gif b/web/cgi/images/baropen.gif Binary files differnew file mode 100644 index 00000000..49cb3a9b --- /dev/null +++ b/web/cgi/images/baropen.gif diff --git a/web/cgi/images/baropen_mid.gif b/web/cgi/images/baropen_mid.gif Binary files differnew file mode 100644 index 00000000..5c02ec12 --- /dev/null +++ b/web/cgi/images/baropen_mid.gif diff --git a/web/cgi/images/barvert.gif b/web/cgi/images/barvert.gif Binary files differnew file mode 100644 index 00000000..1eed6694 --- /dev/null +++ b/web/cgi/images/barvert.gif diff --git a/web/cgi/images/barvertmsg.gif b/web/cgi/images/barvertmsg.gif Binary files differnew file mode 100644 index 00000000..243b38b6 --- /dev/null +++ b/web/cgi/images/barvertmsg.gif diff --git a/web/cgi/images/bg_index.gif b/web/cgi/images/bg_index.gif Binary files differnew file mode 100644 index 00000000..5d0dfeab --- /dev/null +++ b/web/cgi/images/bg_index.gif diff --git a/web/cgi/images/blackdot.gif b/web/cgi/images/blackdot.gif Binary files differnew file mode 100644 index 00000000..9e25328f --- /dev/null +++ b/web/cgi/images/blackdot.gif diff --git a/web/cgi/images/book.gif b/web/cgi/images/book.gif Binary files differnew file mode 100644 index 00000000..70ce6d5c --- /dev/null +++ b/web/cgi/images/book.gif diff --git a/web/cgi/images/but_abook.gif b/web/cgi/images/but_abook.gif Binary files differnew file mode 100644 index 00000000..5155f338 --- /dev/null +++ b/web/cgi/images/but_abook.gif diff --git a/web/cgi/images/but_cancel.gif b/web/cgi/images/but_cancel.gif Binary files differnew file mode 100644 index 00000000..6a4f7806 --- /dev/null +++ b/web/cgi/images/but_cancel.gif diff --git a/web/cgi/images/but_create.gif b/web/cgi/images/but_create.gif Binary files differnew file mode 100644 index 00000000..4bea057b --- /dev/null +++ b/web/cgi/images/but_create.gif diff --git a/web/cgi/images/but_folddel.gif b/web/cgi/images/but_folddel.gif Binary files differnew file mode 100644 index 00000000..c44e23e7 --- /dev/null +++ b/web/cgi/images/but_folddel.gif diff --git a/web/cgi/images/but_foldexp.gif b/web/cgi/images/but_foldexp.gif Binary files differnew file mode 100644 index 00000000..64e8842c --- /dev/null +++ b/web/cgi/images/but_foldexp.gif diff --git a/web/cgi/images/but_foldren.gif b/web/cgi/images/but_foldren.gif Binary files differnew file mode 100644 index 00000000..5374e9a2 --- /dev/null +++ b/web/cgi/images/but_foldren.gif diff --git a/web/cgi/images/but_remove.gif b/web/cgi/images/but_remove.gif Binary files differnew file mode 100644 index 00000000..d08ac475 --- /dev/null +++ b/web/cgi/images/but_remove.gif diff --git a/web/cgi/images/but_resume.gif b/web/cgi/images/but_resume.gif Binary files differnew file mode 100644 index 00000000..8b7df00c --- /dev/null +++ b/web/cgi/images/but_resume.gif diff --git a/web/cgi/images/but_rnd_block.gif b/web/cgi/images/but_rnd_block.gif Binary files differnew file mode 100644 index 00000000..dae0aa9f --- /dev/null +++ b/web/cgi/images/but_rnd_block.gif diff --git a/web/cgi/images/but_rnd_first3.gif b/web/cgi/images/but_rnd_first3.gif Binary files differnew file mode 100644 index 00000000..cf2e8bf6 --- /dev/null +++ b/web/cgi/images/but_rnd_first3.gif diff --git a/web/cgi/images/but_rnd_last3.gif b/web/cgi/images/but_rnd_last3.gif Binary files differnew file mode 100644 index 00000000..f21a5e14 --- /dev/null +++ b/web/cgi/images/but_rnd_last3.gif diff --git a/web/cgi/images/but_rnd_next3.gif b/web/cgi/images/but_rnd_next3.gif Binary files differnew file mode 100644 index 00000000..bb303abf --- /dev/null +++ b/web/cgi/images/but_rnd_next3.gif diff --git a/web/cgi/images/but_rnd_prev3.gif b/web/cgi/images/but_rnd_prev3.gif Binary files differnew file mode 100644 index 00000000..54c5c5a8 --- /dev/null +++ b/web/cgi/images/but_rnd_prev3.gif diff --git a/web/cgi/images/but_s_do.gif b/web/cgi/images/but_s_do.gif Binary files differnew file mode 100644 index 00000000..5bfb78d9 --- /dev/null +++ b/web/cgi/images/but_s_do.gif diff --git a/web/cgi/images/but_save.gif b/web/cgi/images/but_save.gif Binary files differnew file mode 100644 index 00000000..ef80c73a --- /dev/null +++ b/web/cgi/images/but_save.gif diff --git a/web/cgi/images/buttons/silver/allmsgs.gif b/web/cgi/images/buttons/silver/allmsgs.gif Binary files differnew file mode 100644 index 00000000..6a8f6ecb --- /dev/null +++ b/web/cgi/images/buttons/silver/allmsgs.gif diff --git a/web/cgi/images/buttons/silver/attach.gif b/web/cgi/images/buttons/silver/attach.gif Binary files differnew file mode 100644 index 00000000..a99063e7 --- /dev/null +++ b/web/cgi/images/buttons/silver/attach.gif diff --git a/web/cgi/images/buttons/silver/cancel.gif b/web/cgi/images/buttons/silver/cancel.gif Binary files differnew file mode 100644 index 00000000..80680cbc --- /dev/null +++ b/web/cgi/images/buttons/silver/cancel.gif diff --git a/web/cgi/images/buttons/silver/compose.gif b/web/cgi/images/buttons/silver/compose.gif Binary files differnew file mode 100644 index 00000000..98795bce --- /dev/null +++ b/web/cgi/images/buttons/silver/compose.gif diff --git a/web/cgi/images/buttons/silver/compose8.gif b/web/cgi/images/buttons/silver/compose8.gif Binary files differnew file mode 100644 index 00000000..99b3e233 --- /dev/null +++ b/web/cgi/images/buttons/silver/compose8.gif diff --git a/web/cgi/images/buttons/silver/config.gif b/web/cgi/images/buttons/silver/config.gif Binary files differnew file mode 100644 index 00000000..3f2373fb --- /dev/null +++ b/web/cgi/images/buttons/silver/config.gif diff --git a/web/cgi/images/buttons/silver/delete.gif b/web/cgi/images/buttons/silver/delete.gif Binary files differnew file mode 100644 index 00000000..e7c87799 --- /dev/null +++ b/web/cgi/images/buttons/silver/delete.gif diff --git a/web/cgi/images/buttons/silver/delete2.gif b/web/cgi/images/buttons/silver/delete2.gif Binary files differnew file mode 100644 index 00000000..a88a5443 --- /dev/null +++ b/web/cgi/images/buttons/silver/delete2.gif diff --git a/web/cgi/images/buttons/silver/done.gif b/web/cgi/images/buttons/silver/done.gif Binary files differnew file mode 100644 index 00000000..fad888f7 --- /dev/null +++ b/web/cgi/images/buttons/silver/done.gif diff --git a/web/cgi/images/buttons/silver/exit.gif b/web/cgi/images/buttons/silver/exit.gif Binary files differnew file mode 100644 index 00000000..31f406fb --- /dev/null +++ b/web/cgi/images/buttons/silver/exit.gif diff --git a/web/cgi/images/buttons/silver/expunge.gif b/web/cgi/images/buttons/silver/expunge.gif Binary files differnew file mode 100644 index 00000000..33c52f02 --- /dev/null +++ b/web/cgi/images/buttons/silver/expunge.gif diff --git a/web/cgi/images/buttons/silver/firstpage.gif b/web/cgi/images/buttons/silver/firstpage.gif Binary files differnew file mode 100644 index 00000000..775203b0 --- /dev/null +++ b/web/cgi/images/buttons/silver/firstpage.gif diff --git a/web/cgi/images/buttons/silver/firstpage2.gif b/web/cgi/images/buttons/silver/firstpage2.gif Binary files differnew file mode 100644 index 00000000..6f8e0b5b --- /dev/null +++ b/web/cgi/images/buttons/silver/firstpage2.gif diff --git a/web/cgi/images/buttons/silver/firstpage4.gif b/web/cgi/images/buttons/silver/firstpage4.gif Binary files differnew file mode 100644 index 00000000..6ea0c89a --- /dev/null +++ b/web/cgi/images/buttons/silver/firstpage4.gif diff --git a/web/cgi/images/buttons/silver/folders.gif b/web/cgi/images/buttons/silver/folders.gif Binary files differnew file mode 100644 index 00000000..abaeaac7 --- /dev/null +++ b/web/cgi/images/buttons/silver/folders.gif diff --git a/web/cgi/images/buttons/silver/forward.gif b/web/cgi/images/buttons/silver/forward.gif Binary files differnew file mode 100644 index 00000000..c2196e6b --- /dev/null +++ b/web/cgi/images/buttons/silver/forward.gif diff --git a/web/cgi/images/buttons/silver/lastpage.gif b/web/cgi/images/buttons/silver/lastpage.gif Binary files differnew file mode 100644 index 00000000..23811d8b --- /dev/null +++ b/web/cgi/images/buttons/silver/lastpage.gif diff --git a/web/cgi/images/buttons/silver/lastpage2.gif b/web/cgi/images/buttons/silver/lastpage2.gif Binary files differnew file mode 100644 index 00000000..39d8a733 --- /dev/null +++ b/web/cgi/images/buttons/silver/lastpage2.gif diff --git a/web/cgi/images/buttons/silver/lastpage4.gif b/web/cgi/images/buttons/silver/lastpage4.gif Binary files differnew file mode 100644 index 00000000..3f69c059 --- /dev/null +++ b/web/cgi/images/buttons/silver/lastpage4.gif diff --git a/web/cgi/images/buttons/silver/logout.gif b/web/cgi/images/buttons/silver/logout.gif Binary files differnew file mode 100644 index 00000000..8a1fb6fd --- /dev/null +++ b/web/cgi/images/buttons/silver/logout.gif diff --git a/web/cgi/images/buttons/silver/messages.gif b/web/cgi/images/buttons/silver/messages.gif Binary files differnew file mode 100644 index 00000000..0e3543f2 --- /dev/null +++ b/web/cgi/images/buttons/silver/messages.gif diff --git a/web/cgi/images/buttons/silver/nextpage.gif b/web/cgi/images/buttons/silver/nextpage.gif Binary files differnew file mode 100644 index 00000000..370aafc9 --- /dev/null +++ b/web/cgi/images/buttons/silver/nextpage.gif diff --git a/web/cgi/images/buttons/silver/nextpage2.gif b/web/cgi/images/buttons/silver/nextpage2.gif Binary files differnew file mode 100644 index 00000000..971ba494 --- /dev/null +++ b/web/cgi/images/buttons/silver/nextpage2.gif diff --git a/web/cgi/images/buttons/silver/ok.gif b/web/cgi/images/buttons/silver/ok.gif Binary files differnew file mode 100644 index 00000000..470db959 --- /dev/null +++ b/web/cgi/images/buttons/silver/ok.gif diff --git a/web/cgi/images/buttons/silver/prevpage.gif b/web/cgi/images/buttons/silver/prevpage.gif Binary files differnew file mode 100644 index 00000000..2e312c3c --- /dev/null +++ b/web/cgi/images/buttons/silver/prevpage.gif diff --git a/web/cgi/images/buttons/silver/prevpage2.gif b/web/cgi/images/buttons/silver/prevpage2.gif Binary files differnew file mode 100644 index 00000000..2b8a1116 --- /dev/null +++ b/web/cgi/images/buttons/silver/prevpage2.gif diff --git a/web/cgi/images/buttons/silver/quit.gif b/web/cgi/images/buttons/silver/quit.gif Binary files differnew file mode 100644 index 00000000..7add5b38 --- /dev/null +++ b/web/cgi/images/buttons/silver/quit.gif diff --git a/web/cgi/images/buttons/silver/reply.gif b/web/cgi/images/buttons/silver/reply.gif Binary files differnew file mode 100644 index 00000000..2b8de31c --- /dev/null +++ b/web/cgi/images/buttons/silver/reply.gif diff --git a/web/cgi/images/buttons/silver/replyall.gif b/web/cgi/images/buttons/silver/replyall.gif Binary files differnew file mode 100644 index 00000000..16a352db --- /dev/null +++ b/web/cgi/images/buttons/silver/replyall.gif diff --git a/web/cgi/images/buttons/silver/save.gif b/web/cgi/images/buttons/silver/save.gif Binary files differnew file mode 100644 index 00000000..b09e5c0d --- /dev/null +++ b/web/cgi/images/buttons/silver/save.gif diff --git a/web/cgi/images/buttons/silver/send.gif b/web/cgi/images/buttons/silver/send.gif Binary files differnew file mode 100644 index 00000000..b4ccfb33 --- /dev/null +++ b/web/cgi/images/buttons/silver/send.gif diff --git a/web/cgi/images/buttons/silver/undelete.gif b/web/cgi/images/buttons/silver/undelete.gif Binary files differnew file mode 100644 index 00000000..0c585b63 --- /dev/null +++ b/web/cgi/images/buttons/silver/undelete.gif diff --git a/web/cgi/images/caution.gif b/web/cgi/images/caution.gif Binary files differnew file mode 100644 index 00000000..9d55a384 --- /dev/null +++ b/web/cgi/images/caution.gif diff --git a/web/cgi/images/cf_add.gif b/web/cgi/images/cf_add.gif Binary files differnew file mode 100644 index 00000000..c3c228a6 --- /dev/null +++ b/web/cgi/images/cf_add.gif diff --git a/web/cgi/images/cf_delete.gif b/web/cgi/images/cf_delete.gif Binary files differnew file mode 100644 index 00000000..7b3c9a39 --- /dev/null +++ b/web/cgi/images/cf_delete.gif diff --git a/web/cgi/images/cf_edit.gif b/web/cgi/images/cf_edit.gif Binary files differnew file mode 100644 index 00000000..094c4109 --- /dev/null +++ b/web/cgi/images/cf_edit.gif diff --git a/web/cgi/images/cf_help.gif b/web/cgi/images/cf_help.gif Binary files differnew file mode 100644 index 00000000..678d6d64 --- /dev/null +++ b/web/cgi/images/cf_help.gif diff --git a/web/cgi/images/cf_shdown.gif b/web/cgi/images/cf_shdown.gif Binary files differnew file mode 100644 index 00000000..162e93c9 --- /dev/null +++ b/web/cgi/images/cf_shdown.gif diff --git a/web/cgi/images/cf_shup.gif b/web/cgi/images/cf_shup.gif Binary files differnew file mode 100644 index 00000000..a2acbbd5 --- /dev/null +++ b/web/cgi/images/cf_shup.gif diff --git a/web/cgi/images/decreas4.gif b/web/cgi/images/decreas4.gif Binary files differnew file mode 100644 index 00000000..9ac0fedb --- /dev/null +++ b/web/cgi/images/decreas4.gif diff --git a/web/cgi/images/dot.gif b/web/cgi/images/dot.gif Binary files differnew file mode 100644 index 00000000..a4f37d7e --- /dev/null +++ b/web/cgi/images/dot.gif diff --git a/web/cgi/images/dot2.gif b/web/cgi/images/dot2.gif Binary files differnew file mode 100644 index 00000000..e565824a --- /dev/null +++ b/web/cgi/images/dot2.gif diff --git a/web/cgi/images/dotblink.gif b/web/cgi/images/dotblink.gif Binary files differnew file mode 100644 index 00000000..500f0bc0 --- /dev/null +++ b/web/cgi/images/dotblink.gif diff --git a/web/cgi/images/dstripe.gif b/web/cgi/images/dstripe.gif Binary files differnew file mode 100644 index 00000000..6adf1bcb --- /dev/null +++ b/web/cgi/images/dstripe.gif diff --git a/web/cgi/images/env/d_new.gif b/web/cgi/images/env/d_new.gif Binary files differnew file mode 100644 index 00000000..f9766a80 --- /dev/null +++ b/web/cgi/images/env/d_new.gif diff --git a/web/cgi/images/env/d_newans.gif b/web/cgi/images/env/d_newans.gif Binary files differnew file mode 100644 index 00000000..d90c8509 --- /dev/null +++ b/web/cgi/images/env/d_newans.gif diff --git a/web/cgi/images/env/d_newansdel.gif b/web/cgi/images/env/d_newansdel.gif Binary files differnew file mode 100644 index 00000000..d735bb14 --- /dev/null +++ b/web/cgi/images/env/d_newansdel.gif diff --git a/web/cgi/images/env/d_newdel.gif b/web/cgi/images/env/d_newdel.gif Binary files differnew file mode 100644 index 00000000..2f758bd5 --- /dev/null +++ b/web/cgi/images/env/d_newdel.gif diff --git a/web/cgi/images/env/d_newimp.gif b/web/cgi/images/env/d_newimp.gif Binary files differnew file mode 100644 index 00000000..10510595 --- /dev/null +++ b/web/cgi/images/env/d_newimp.gif diff --git a/web/cgi/images/env/d_newimpans.gif b/web/cgi/images/env/d_newimpans.gif Binary files differnew file mode 100644 index 00000000..0fa8b0c0 --- /dev/null +++ b/web/cgi/images/env/d_newimpans.gif diff --git a/web/cgi/images/env/d_newimpansdel.gif b/web/cgi/images/env/d_newimpansdel.gif Binary files differnew file mode 100644 index 00000000..872a80d9 --- /dev/null +++ b/web/cgi/images/env/d_newimpansdel.gif diff --git a/web/cgi/images/env/d_newimpdel.gif b/web/cgi/images/env/d_newimpdel.gif Binary files differnew file mode 100644 index 00000000..dd92dc26 --- /dev/null +++ b/web/cgi/images/env/d_newimpdel.gif diff --git a/web/cgi/images/env/d_newyou.gif b/web/cgi/images/env/d_newyou.gif Binary files differnew file mode 100644 index 00000000..c227e684 --- /dev/null +++ b/web/cgi/images/env/d_newyou.gif diff --git a/web/cgi/images/env/d_newyouans.gif b/web/cgi/images/env/d_newyouans.gif Binary files differnew file mode 100644 index 00000000..9f8c24c1 --- /dev/null +++ b/web/cgi/images/env/d_newyouans.gif diff --git a/web/cgi/images/env/d_newyouansdel.gif b/web/cgi/images/env/d_newyouansdel.gif Binary files differnew file mode 100644 index 00000000..d922a6a3 --- /dev/null +++ b/web/cgi/images/env/d_newyouansdel.gif diff --git a/web/cgi/images/env/d_newyoudel.gif b/web/cgi/images/env/d_newyoudel.gif Binary files differnew file mode 100644 index 00000000..8ac883c2 --- /dev/null +++ b/web/cgi/images/env/d_newyoudel.gif diff --git a/web/cgi/images/env/d_read.gif b/web/cgi/images/env/d_read.gif Binary files differnew file mode 100644 index 00000000..2b9aa56e --- /dev/null +++ b/web/cgi/images/env/d_read.gif diff --git a/web/cgi/images/env/d_readans.gif b/web/cgi/images/env/d_readans.gif Binary files differnew file mode 100644 index 00000000..dd9b80ae --- /dev/null +++ b/web/cgi/images/env/d_readans.gif diff --git a/web/cgi/images/env/d_readansdel.gif b/web/cgi/images/env/d_readansdel.gif Binary files differnew file mode 100644 index 00000000..c98d2395 --- /dev/null +++ b/web/cgi/images/env/d_readansdel.gif diff --git a/web/cgi/images/env/d_readdel.gif b/web/cgi/images/env/d_readdel.gif Binary files differnew file mode 100644 index 00000000..a922f923 --- /dev/null +++ b/web/cgi/images/env/d_readdel.gif diff --git a/web/cgi/images/env/d_readimp.gif b/web/cgi/images/env/d_readimp.gif Binary files differnew file mode 100644 index 00000000..81015d7b --- /dev/null +++ b/web/cgi/images/env/d_readimp.gif diff --git a/web/cgi/images/env/d_readimpans.gif b/web/cgi/images/env/d_readimpans.gif Binary files differnew file mode 100644 index 00000000..d8bfcb89 --- /dev/null +++ b/web/cgi/images/env/d_readimpans.gif diff --git a/web/cgi/images/env/d_readimpansdel.gif b/web/cgi/images/env/d_readimpansdel.gif Binary files differnew file mode 100644 index 00000000..02342edd --- /dev/null +++ b/web/cgi/images/env/d_readimpansdel.gif diff --git a/web/cgi/images/env/d_readimpdel.gif b/web/cgi/images/env/d_readimpdel.gif Binary files differnew file mode 100644 index 00000000..0d66fcbd --- /dev/null +++ b/web/cgi/images/env/d_readimpdel.gif diff --git a/web/cgi/images/env/d_readyou.gif b/web/cgi/images/env/d_readyou.gif Binary files differnew file mode 100644 index 00000000..8dc32802 --- /dev/null +++ b/web/cgi/images/env/d_readyou.gif diff --git a/web/cgi/images/env/d_readyouans.gif b/web/cgi/images/env/d_readyouans.gif Binary files differnew file mode 100644 index 00000000..dab41d34 --- /dev/null +++ b/web/cgi/images/env/d_readyouans.gif diff --git a/web/cgi/images/env/d_readyouansdel.gif b/web/cgi/images/env/d_readyouansdel.gif Binary files differnew file mode 100644 index 00000000..98a9b4ae --- /dev/null +++ b/web/cgi/images/env/d_readyouansdel.gif diff --git a/web/cgi/images/env/d_readyoudel.gif b/web/cgi/images/env/d_readyoudel.gif Binary files differnew file mode 100644 index 00000000..646c2b4f --- /dev/null +++ b/web/cgi/images/env/d_readyoudel.gif diff --git a/web/cgi/images/env/new.gif b/web/cgi/images/env/new.gif Binary files differnew file mode 100644 index 00000000..a34257ed --- /dev/null +++ b/web/cgi/images/env/new.gif diff --git a/web/cgi/images/env/newans.gif b/web/cgi/images/env/newans.gif Binary files differnew file mode 100644 index 00000000..e43c377b --- /dev/null +++ b/web/cgi/images/env/newans.gif diff --git a/web/cgi/images/env/newansdel.gif b/web/cgi/images/env/newansdel.gif Binary files differnew file mode 100644 index 00000000..ecfbaa83 --- /dev/null +++ b/web/cgi/images/env/newansdel.gif diff --git a/web/cgi/images/env/newdel.gif b/web/cgi/images/env/newdel.gif Binary files differnew file mode 100644 index 00000000..c1c2f02c --- /dev/null +++ b/web/cgi/images/env/newdel.gif diff --git a/web/cgi/images/env/newimp.gif b/web/cgi/images/env/newimp.gif Binary files differnew file mode 100644 index 00000000..12aaf644 --- /dev/null +++ b/web/cgi/images/env/newimp.gif diff --git a/web/cgi/images/env/newimpans.gif b/web/cgi/images/env/newimpans.gif Binary files differnew file mode 100644 index 00000000..1ae6db2e --- /dev/null +++ b/web/cgi/images/env/newimpans.gif diff --git a/web/cgi/images/env/newimpansdel.gif b/web/cgi/images/env/newimpansdel.gif Binary files differnew file mode 100644 index 00000000..df986427 --- /dev/null +++ b/web/cgi/images/env/newimpansdel.gif diff --git a/web/cgi/images/env/newimpdel.gif b/web/cgi/images/env/newimpdel.gif Binary files differnew file mode 100644 index 00000000..8eff245f --- /dev/null +++ b/web/cgi/images/env/newimpdel.gif diff --git a/web/cgi/images/env/newyou.gif b/web/cgi/images/env/newyou.gif Binary files differnew file mode 100644 index 00000000..d376ece8 --- /dev/null +++ b/web/cgi/images/env/newyou.gif diff --git a/web/cgi/images/env/newyouans.gif b/web/cgi/images/env/newyouans.gif Binary files differnew file mode 100644 index 00000000..f9afe98a --- /dev/null +++ b/web/cgi/images/env/newyouans.gif diff --git a/web/cgi/images/env/newyouansdel.gif b/web/cgi/images/env/newyouansdel.gif Binary files differnew file mode 100644 index 00000000..bca5ab7e --- /dev/null +++ b/web/cgi/images/env/newyouansdel.gif diff --git a/web/cgi/images/env/newyoudel.gif b/web/cgi/images/env/newyoudel.gif Binary files differnew file mode 100644 index 00000000..5f3305ff --- /dev/null +++ b/web/cgi/images/env/newyoudel.gif diff --git a/web/cgi/images/env/read.gif b/web/cgi/images/env/read.gif Binary files differnew file mode 100644 index 00000000..b5325e06 --- /dev/null +++ b/web/cgi/images/env/read.gif diff --git a/web/cgi/images/env/readans.gif b/web/cgi/images/env/readans.gif Binary files differnew file mode 100644 index 00000000..29e08915 --- /dev/null +++ b/web/cgi/images/env/readans.gif diff --git a/web/cgi/images/env/readansdel.gif b/web/cgi/images/env/readansdel.gif Binary files differnew file mode 100644 index 00000000..d74cac4c --- /dev/null +++ b/web/cgi/images/env/readansdel.gif diff --git a/web/cgi/images/env/readdel.gif b/web/cgi/images/env/readdel.gif Binary files differnew file mode 100644 index 00000000..9fa3f1d3 --- /dev/null +++ b/web/cgi/images/env/readdel.gif diff --git a/web/cgi/images/env/readimp.gif b/web/cgi/images/env/readimp.gif Binary files differnew file mode 100644 index 00000000..c202ce57 --- /dev/null +++ b/web/cgi/images/env/readimp.gif diff --git a/web/cgi/images/env/readimpans.gif b/web/cgi/images/env/readimpans.gif Binary files differnew file mode 100644 index 00000000..8658dbe5 --- /dev/null +++ b/web/cgi/images/env/readimpans.gif diff --git a/web/cgi/images/env/readimpansdel.gif b/web/cgi/images/env/readimpansdel.gif Binary files differnew file mode 100644 index 00000000..c0adfd9d --- /dev/null +++ b/web/cgi/images/env/readimpansdel.gif diff --git a/web/cgi/images/env/readimpdel.gif b/web/cgi/images/env/readimpdel.gif Binary files differnew file mode 100644 index 00000000..16e97f72 --- /dev/null +++ b/web/cgi/images/env/readimpdel.gif diff --git a/web/cgi/images/env/readyou.border.gif b/web/cgi/images/env/readyou.border.gif Binary files differnew file mode 100644 index 00000000..7f0f4a7c --- /dev/null +++ b/web/cgi/images/env/readyou.border.gif diff --git a/web/cgi/images/env/readyou.gif b/web/cgi/images/env/readyou.gif Binary files differnew file mode 100644 index 00000000..e1587077 --- /dev/null +++ b/web/cgi/images/env/readyou.gif diff --git a/web/cgi/images/env/readyouans.gif b/web/cgi/images/env/readyouans.gif Binary files differnew file mode 100644 index 00000000..8a71bf4a --- /dev/null +++ b/web/cgi/images/env/readyouans.gif diff --git a/web/cgi/images/env/readyouansdel.gif b/web/cgi/images/env/readyouansdel.gif Binary files differnew file mode 100644 index 00000000..d59d4a6a --- /dev/null +++ b/web/cgi/images/env/readyouansdel.gif diff --git a/web/cgi/images/env/readyoudel.gif b/web/cgi/images/env/readyoudel.gif Binary files differnew file mode 100644 index 00000000..c1718d1d --- /dev/null +++ b/web/cgi/images/env/readyoudel.gif diff --git a/web/cgi/images/hdr.gif b/web/cgi/images/hdr.gif Binary files differnew file mode 100644 index 00000000..25432375 --- /dev/null +++ b/web/cgi/images/hdr.gif diff --git a/web/cgi/images/hdrless.gif b/web/cgi/images/hdrless.gif Binary files differnew file mode 100644 index 00000000..dc6f1279 --- /dev/null +++ b/web/cgi/images/hdrless.gif diff --git a/web/cgi/images/hdrmore.gif b/web/cgi/images/hdrmore.gif Binary files differnew file mode 100644 index 00000000..ce451397 --- /dev/null +++ b/web/cgi/images/hdrmore.gif diff --git a/web/cgi/images/hdrnon.gif b/web/cgi/images/hdrnon.gif Binary files differnew file mode 100644 index 00000000..26d60632 --- /dev/null +++ b/web/cgi/images/hdrnon.gif diff --git a/web/cgi/images/help_trans.gif b/web/cgi/images/help_trans.gif Binary files differnew file mode 100644 index 00000000..d2043df4 --- /dev/null +++ b/web/cgi/images/help_trans.gif diff --git a/web/cgi/images/ibarmsg.gif b/web/cgi/images/ibarmsg.gif Binary files differnew file mode 100644 index 00000000..ba5a25f9 --- /dev/null +++ b/web/cgi/images/ibarmsg.gif diff --git a/web/cgi/images/ibarvertmsg.gif b/web/cgi/images/ibarvertmsg.gif Binary files differnew file mode 100644 index 00000000..4cf3fb4d --- /dev/null +++ b/web/cgi/images/ibarvertmsg.gif diff --git a/web/cgi/images/if_blank.gif b/web/cgi/images/if_blank.gif Binary files differnew file mode 100644 index 00000000..54a6a152 --- /dev/null +++ b/web/cgi/images/if_blank.gif diff --git a/web/cgi/images/if_left.gif b/web/cgi/images/if_left.gif Binary files differnew file mode 100644 index 00000000..7d750037 --- /dev/null +++ b/web/cgi/images/if_left.gif diff --git a/web/cgi/images/if_narrow.gif b/web/cgi/images/if_narrow.gif Binary files differnew file mode 100644 index 00000000..e0ef6ec7 --- /dev/null +++ b/web/cgi/images/if_narrow.gif diff --git a/web/cgi/images/if_narrow2.gif b/web/cgi/images/if_narrow2.gif Binary files differnew file mode 100644 index 00000000..141e7946 --- /dev/null +++ b/web/cgi/images/if_narrow2.gif diff --git a/web/cgi/images/if_remove.gif b/web/cgi/images/if_remove.gif Binary files differnew file mode 100644 index 00000000..f4f74548 --- /dev/null +++ b/web/cgi/images/if_remove.gif diff --git a/web/cgi/images/if_right.gif b/web/cgi/images/if_right.gif Binary files differnew file mode 100644 index 00000000..d2490ff6 --- /dev/null +++ b/web/cgi/images/if_right.gif diff --git a/web/cgi/images/if_widen.gif b/web/cgi/images/if_widen.gif Binary files differnew file mode 100644 index 00000000..5cc84849 --- /dev/null +++ b/web/cgi/images/if_widen.gif diff --git a/web/cgi/images/if_wider.gif b/web/cgi/images/if_wider.gif Binary files differnew file mode 100644 index 00000000..dc39da1a --- /dev/null +++ b/web/cgi/images/if_wider.gif diff --git a/web/cgi/images/increas4.gif b/web/cgi/images/increas4.gif Binary files differnew file mode 100644 index 00000000..8cb8e232 --- /dev/null +++ b/web/cgi/images/increas4.gif diff --git a/web/cgi/images/indexhdr.gif b/web/cgi/images/indexhdr.gif Binary files differnew file mode 100644 index 00000000..0463a80d --- /dev/null +++ b/web/cgi/images/indexhdr.gif diff --git a/web/cgi/images/logo/alpine/back.gif b/web/cgi/images/logo/alpine/back.gif Binary files differnew file mode 100644 index 00000000..cab310df --- /dev/null +++ b/web/cgi/images/logo/alpine/back.gif diff --git a/web/cgi/images/logo/alpine/big.gif b/web/cgi/images/logo/alpine/big.gif Binary files differnew file mode 100644 index 00000000..6d4862ee --- /dev/null +++ b/web/cgi/images/logo/alpine/big.gif diff --git a/web/cgi/images/logo/alpine/small-blank.gif b/web/cgi/images/logo/alpine/small-blank.gif Binary files differnew file mode 100644 index 00000000..41868d0a --- /dev/null +++ b/web/cgi/images/logo/alpine/small-blank.gif diff --git a/web/cgi/images/logo/alpine/small.gif b/web/cgi/images/logo/alpine/small.gif Binary files differnew file mode 100644 index 00000000..af845545 --- /dev/null +++ b/web/cgi/images/logo/alpine/small.gif diff --git a/web/cgi/images/markall3.gif b/web/cgi/images/markall3.gif Binary files differnew file mode 100644 index 00000000..15b2b82d --- /dev/null +++ b/web/cgi/images/markall3.gif diff --git a/web/cgi/images/marknone3.gif b/web/cgi/images/marknone3.gif Binary files differnew file mode 100644 index 00000000..b8845863 --- /dev/null +++ b/web/cgi/images/marknone3.gif diff --git a/web/cgi/images/minus2.gif b/web/cgi/images/minus2.gif Binary files differnew file mode 100644 index 00000000..928ec8f5 --- /dev/null +++ b/web/cgi/images/minus2.gif diff --git a/web/cgi/images/nondither10x10.gif b/web/cgi/images/nondither10x10.gif Binary files differnew file mode 100644 index 00000000..cea4b5cf --- /dev/null +++ b/web/cgi/images/nondither10x10.gif diff --git a/web/cgi/images/plus2.gif b/web/cgi/images/plus2.gif Binary files differnew file mode 100644 index 00000000..be20fa4b --- /dev/null +++ b/web/cgi/images/plus2.gif diff --git a/web/cgi/images/postmark.gif b/web/cgi/images/postmark.gif Binary files differnew file mode 100644 index 00000000..dd384564 --- /dev/null +++ b/web/cgi/images/postmark.gif diff --git a/web/cgi/images/printer2.gif b/web/cgi/images/printer2.gif Binary files differnew file mode 100644 index 00000000..d752ed33 --- /dev/null +++ b/web/cgi/images/printer2.gif diff --git a/web/cgi/images/slidein.gif b/web/cgi/images/slidein.gif Binary files differnew file mode 100644 index 00000000..7f5ceefa --- /dev/null +++ b/web/cgi/images/slidein.gif diff --git a/web/cgi/images/slideout.gif b/web/cgi/images/slideout.gif Binary files differnew file mode 100644 index 00000000..1ccd330f --- /dev/null +++ b/web/cgi/images/slideout.gif diff --git a/web/cgi/images/tabless.gif b/web/cgi/images/tabless.gif Binary files differnew file mode 100644 index 00000000..9f923935 --- /dev/null +++ b/web/cgi/images/tabless.gif diff --git a/web/cgi/images/tabmore.gif b/web/cgi/images/tabmore.gif Binary files differnew file mode 100644 index 00000000..97f21212 --- /dev/null +++ b/web/cgi/images/tabmore.gif diff --git a/web/cgi/images/tabs/abdtab.gif b/web/cgi/images/tabs/abdtab.gif Binary files differnew file mode 100644 index 00000000..1e464fc2 --- /dev/null +++ b/web/cgi/images/tabs/abdtab.gif diff --git a/web/cgi/images/tabs/abtab.gif b/web/cgi/images/tabs/abtab.gif Binary files differnew file mode 100644 index 00000000..b60728a0 --- /dev/null +++ b/web/cgi/images/tabs/abtab.gif diff --git a/web/cgi/images/tabs/blank.gif b/web/cgi/images/tabs/blank.gif Binary files differnew file mode 100644 index 00000000..8079c962 --- /dev/null +++ b/web/cgi/images/tabs/blank.gif diff --git a/web/cgi/images/tabs/cdtab.gif b/web/cgi/images/tabs/cdtab.gif Binary files differnew file mode 100644 index 00000000..d55eb0ae --- /dev/null +++ b/web/cgi/images/tabs/cdtab.gif diff --git a/web/cgi/images/tabs/ctab.gif b/web/cgi/images/tabs/ctab.gif Binary files differnew file mode 100644 index 00000000..53a1b1f3 --- /dev/null +++ b/web/cgi/images/tabs/ctab.gif diff --git a/web/cgi/images/tabs/fdtab.gif b/web/cgi/images/tabs/fdtab.gif Binary files differnew file mode 100644 index 00000000..bcbaf36c --- /dev/null +++ b/web/cgi/images/tabs/fdtab.gif diff --git a/web/cgi/images/tabs/ftab.gif b/web/cgi/images/tabs/ftab.gif Binary files differnew file mode 100644 index 00000000..163c9f39 --- /dev/null +++ b/web/cgi/images/tabs/ftab.gif diff --git a/web/cgi/images/tabs/gdtab.gif b/web/cgi/images/tabs/gdtab.gif Binary files differnew file mode 100644 index 00000000..f4651a54 --- /dev/null +++ b/web/cgi/images/tabs/gdtab.gif diff --git a/web/cgi/images/tabs/gtab.gif b/web/cgi/images/tabs/gtab.gif Binary files differnew file mode 100644 index 00000000..152280cd --- /dev/null +++ b/web/cgi/images/tabs/gtab.gif diff --git a/web/cgi/images/tabs/mldtab.gif b/web/cgi/images/tabs/mldtab.gif Binary files differnew file mode 100644 index 00000000..ad10bafb --- /dev/null +++ b/web/cgi/images/tabs/mldtab.gif diff --git a/web/cgi/images/tabs/mltab.gif b/web/cgi/images/tabs/mltab.gif Binary files differnew file mode 100644 index 00000000..c2a6833f --- /dev/null +++ b/web/cgi/images/tabs/mltab.gif diff --git a/web/cgi/images/tabs/mvdtab.gif b/web/cgi/images/tabs/mvdtab.gif Binary files differnew file mode 100644 index 00000000..2051a898 --- /dev/null +++ b/web/cgi/images/tabs/mvdtab.gif diff --git a/web/cgi/images/tabs/mvtab.gif b/web/cgi/images/tabs/mvtab.gif Binary files differnew file mode 100644 index 00000000..01b66066 --- /dev/null +++ b/web/cgi/images/tabs/mvtab.gif diff --git a/web/cgi/images/tabs/rdtab.gif b/web/cgi/images/tabs/rdtab.gif Binary files differnew file mode 100644 index 00000000..c97628bc --- /dev/null +++ b/web/cgi/images/tabs/rdtab.gif diff --git a/web/cgi/images/tabs/rtab.gif b/web/cgi/images/tabs/rtab.gif Binary files differnew file mode 100644 index 00000000..06519f2a --- /dev/null +++ b/web/cgi/images/tabs/rtab.gif diff --git a/web/cgi/images/tabs/tabbg.gif b/web/cgi/images/tabs/tabbg.gif Binary files differnew file mode 100644 index 00000000..f0382851 --- /dev/null +++ b/web/cgi/images/tabs/tabbg.gif diff --git a/web/cgi/images/tabs/tabmid.gif b/web/cgi/images/tabs/tabmid.gif Binary files differnew file mode 100644 index 00000000..7d9bd22c --- /dev/null +++ b/web/cgi/images/tabs/tabmid.gif diff --git a/web/cgi/motd.sample b/web/cgi/motd.sample new file mode 100644 index 00000000..d3525a3f --- /dev/null +++ b/web/cgi/motd.sample @@ -0,0 +1,5 @@ +<b>Note:</b><br> +We're always looking to improve Web Alpine! Please send your comments and suggestions to to alpine-info@cac.washington.edu. +<br> +Thanks! + diff --git a/web/cgi/pub/alpine.tcl b/web/cgi/pub/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/pub/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/pub/getach.tcl b/web/cgi/pub/getach.tcl new file mode 100755 index 00000000..dce5047c --- /dev/null +++ b/web/cgi/pub/getach.tcl @@ -0,0 +1,87 @@ +#!./tclsh + +# ======================================================================== +# Copyright 2006-2007 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# getach.tcl +# +# Purpose: CGI script to retrieve requested attachment +# +# Input: +# +# h : handle referring to temp file holding attachment particulars + +# inherit global config +source ./alpine.tcl + +cgi_eval { + + # verify that the format of the request is correct. Mainly it's + # to reasonably handle relative urls in viewed html attachments. Ugh. + if {[regexp {^h=[A-Za-z0-9]*$} $env(QUERY_STRING)]} { + + cgi_input + + WPImport h + + if {[regexp {^[A-Za-z0-9]+$} $h] != 1} { + WPInfoPage "Web Alpine Error" [font size=+2 "Bogus Attachment Handle: $h"] "Please close this window." + exit + } + + set cmdfile [file join $_wp(detachpath) detach.${h}-control] + + if {[file exists $cmdfile] == 0} { + WPInfoPage "Webpine Error" [font size=+2 "Stale Handle Reference"] "Please click the attachment link to view this attachment." + } elseif {[catch { + set cid [open $cmdfile r] + + while {1} { + if {[gets $cid line] == 0} { + if {[gets $cid tmpfile] != 0} { + puts stdout "" + + set fp [open $tmpfile r] + + fconfigure $fp -translation binary + fconfigure stdout -translation binary + + fcopy $fp stdout + + close $fp + } + + break + } else { + puts stdout $line + } + } + } errstr]} { + WPInfoPage "Webpine Error" [font size=+2 $errstr] "Please close this window." + } + + # + # Don't delete the temp files immediately because *some* browsers + # <cough>IE<cough> will download the attachment, then hand the + # URL of the downloaded attachment to the viewer <cough>WMP<cough> + # so the viewer can then *REFETCH* the data for display. No, + # they don't pay attention to the redirect code. + # + # The script that created them is responsible for having set in motion + # a process to delete them at some point in the future. + # + # catch {file delete -force $cmdfile} + # catch {file delete -force $tmpfile} + } else { + WPInfoPage "Invalid Attachment Reference" "[font size=+2 "Invalid Attachment Reference"]" \ + "This page is the result of clicking a link in an attached HTML document. It's author likely used an incomplete hypertext link which resulted in a bogus link to the WebPine server.<p>Clicking your browser's Back button should restore the attachment's display." + } +} diff --git a/web/cgi/pub/standard.css b/web/cgi/pub/standard.css new file mode 100644 index 00000000..e2b0fd21 --- /dev/null +++ b/web/cgi/pub/standard.css @@ -0,0 +1,45 @@ +TD.nosize { font-size: 16px } +DIV.fname { font-family: arial, sans-serif; font-size: 10pt } +.prog { font-family: arial, sans-serif ; font-weight: bold ; font-size: 16px ; color: #50056E } +.title { font-family: arial, sans-serif ; color: white } +.flymenu { visibility: hidden; position: absolute; left: 0; top: 0 } +.flydata { font-family: arial, sans-serif ; font-size: 10pt } +.flydata:hover { color: #ff0066 } +TABLE.flydata { background-color: #fefac9 ; border: #006400 2px solid } +TH.flydata { text-align: center ; color: white ; background-color: #006400 } +HR.flydata { color: #006400 } +A.flydata { font-size: 10pt ; text-decoration: none ; color: black } +.menubar { color: white; font-family: arial, sans-serif; font-size: 8pt } +.menubar:hover { color:yellow } +DIV.menubar { position: absolute; visibility: visible; top: 62px; left: 2px; } +A.menubar { color:black; text-decoration:none; font-weight:bold ; height: 16px ; width: 100px ; vertical-align: middle } +HR.menubar { border-top: solid; color: black } +.body { background-color: white } +input.body { color: white; } +.indexhdr { font-family: geneva, arial, sans-serif ; font-size: 8pt ; color: black } +.indexsort { font-family: geneva, arial, sans-serif ; background-color: #999999 ; font-size: 8pt ; color: white } +.auth { font-family: Arial, Sans-Serif ; font-size: 10pt ; font-weight: bold } +.extrahdrs { background-color: white; display: none } +.navtext { font-family: geneva, arial, sans-serif ; font-size: 9pt } +.navbar { color: white ; font-family: geneva, arial, sans-serif ; font-size: 9pt ; letter-spacing: 0pt } +FORM { margin-bottom: 0px ; margin-top: 0px } +.statustext { color: black ; font-family: geneva, arial, sans-serif ; font-size: 8pt } +.morestatus { color: #ff3333 ; font-size: 10pt ; font-weight : bold } +.ifakebar { visibility: hidden; position: absolute; left: 0; top: 0 } +.ithumb { position: relative } +.iflags { font-family: sans-serif ; color: red } +.isize { font-size: 9pt } +.notice { color: red ; font-weight: bold } +A.notice { color: red } +.attach { visibility: hidden; position: absolute; left: 0; top: 0 } +.mispell { background: #ffcccc ; color: #000000; text-decoration: none } +.spelltext { position: relative } +.dialog { background-color: #fefac9 ; font-family: arial, sans-serif ; font-size: 12pt } +.context { background-color: #999999 ; color: black ; font-family: Helvetica, sans-serif ; font-size: 9pt } +.ops { background-color: #666666 ; color: white ; font-family: Helvetica, sans-serif } +.i0 { background-color: #eeeeee } +.i1 { background-color: #ffffff } +.cfntc { color: red; font-size: 8pt } +.cfval { font-size: 9pt } +.cfvn { font-weight: bold; font-size: 10pt } +.foldpic { background-color: #eeeeee } diff --git a/web/cgi/pub/standard.js b/web/cgi/pub/standard.js new file mode 100644 index 00000000..89157e1f --- /dev/null +++ b/web/cgi/pub/standard.js @@ -0,0 +1,414 @@ +var child = new Object(); +child.win = null; +var reloadtimer = null +var resizer = null; +var resized = null; +var resizex = 0; +var resizey = 0; + +if (navigator.appName.indexOf('Netscape') >= 0) { + if (navigator.appVersion.substr(0,1) < 5) { + isW3C = false; + isIE = false; + sEvent='e'; + sKey='.which'; + yRef='.top'; + xRef='.left'; + xOff='.clip.width'; + yOff='.clip.height'; + xEvent='.pageX'; + yEvent='.pageY'; + dS='document.'; + sD=''; + sHideV="'hide'"; + sShowV="'show'"; + dRef='self'; + hRef='.innerHeight'; + wRef='.innerWidth'; + xSRef='.screenX'; + ySRef='.screenY'; + xPos=dRef+'.pageXOffset'; + yPos=dRef+'.pageYOffset'; + eSrc='.target'; + } else { + isW3C = true; + isIE = false; + sEvent='e'; + sKey='.which'; + yRef='.top'; + xRef='.left'; + xOff='.offsetWidth'; + yOff='.offsetHeight'; + xEvent='.pageX'; + yEvent='.pageY'; + dS='document.'; + sD='.style'; + sHideV="'hidden'"; + sShowV="'visible'"; + dRef='self'; + hRef='.innerHeight'; + wRef='.innerWidth'; + xSRef='.screenX'; + ySRef='.screenY'; + xPos=dRef+'.pageXOffset'; + yPos=dRef+'.pageYOffset'; + eSrc='.target'; + } +} +else { + isIE = true; + isW3C = 0; + sEvent='window.event'; + sKey='.keyCode'; + yRef='.pixelTop'; + xRef='.pixelLeft'; + xOff='.offsetWidth'; + yOff='.offsetHeight'; + xEvent='.clientX'; + yEvent='.clientY'; + dS=''; + sD='.style'; + sHideV="'hidden'"; + sShowV="'visible'"; + dRef='document.body'; + hRef='.clientHeight'; + wRef='.clientWidth'; + xPos=dRef+'.scrollLeft'; + yPos=dRef+'.scrollTop'; + xSRef='.screenLeft'; + ySRef='.screenTop'; + eSrc='.srcElement'; +} + +function setLayout() { + updateLayout(); +} + +function updateLayout() { + var yy = eval(yPos); + yy += Math.max(64 - yy, 0); + moveLayerY(getLayer('tasks'),yy); + setTimeout('updateLayout()',100); +} + +function setResize(f,w) { + document.resized = (f) ? f : doResize; + + document.resizex = getDisplayWidth(); + document.resizey = getDisplayHeight(); + + if (isIE){ + document.resizer = (w) ? w : null; + window.onresize = armResize; + } + else{ + window.onresize = document.resized; + } +} + +function armResize(e) { + if(document.resizer) document.resizer(e); + document.onmouseover = document.resized; +} + +function doResize(e) { + if(!(document.resizex == getDisplayWidth() && document.resizey == getDisplayHeight())){ + var newurl = window.location.href.replace(/\?.*$/, ''); + document.onmouseover = null; + window.location.replace(newurl+'?ppg='+getResizedLines(e)); + } +} + +function getResizedLines(e) { + var h = (isW3C || document.all) ? eval(dRef+hRef) : e.height; + return Math.max(Math.floor((h - 66) / getIndexHeight()) - 1, 2); +} + +function getDisplayWidth() { + return eval(dRef+wRef); +} + +function getDisplayHeight() { + return eval(dRef+hRef); +} + +function getWindowX() { + return eval('window'+xSRef); +} + +function getWindowY() { + return eval('window'+ySRef); +} + +function showElement(o) { + eval('o'+sD+'.visibility = '+sShowV); +} + +function hideElement(o) { + eval('o'+sD+'.visibility = '+sHideV); +} + +function isElementDisplayed(o) { + var d = eval('o'+sD+'.display'); + return (d == 'block'); +} + +function displayElement(o) { + eval('o'+sD+'.display = "block"'); +} + +function concealElement(o) { + eval('o'+sD+'.display = "none"'); +} + +function getScrollAbove() { + return(eval(yPos)); +} + +function getScrollLeft() { + return(eval(xPos)); +} + +function layerWalk(l,t) { + var o; + for(var i = 0; i < l.length; i++){ + o = eval('l[i]'+t); + if(o) return o; + o = layerWalk(l[i].document.layers,t); + if(o) return o; + } + + return null; +} + +function getImage(id) { + if(isW3C) + return document.getElementById(id); + else if(isIE) + return document.all[id]; + else if(window.document.images[id]) + return window.document.images[id]; + else + return layerWalk(window.document.layers,'.document.images.'+id); +} + +function getImageX(o) { + if(isIE || isW3C){ + var x = o.offsetLeft; + for(var p = o.offsetParent; p != null; p = p.offsetParent) + x += p.offsetLeft; + + return x; + } + else + return o.x; +} + +function getImageY(o) { + if(isIE || isW3C){ + var y = o.offsetTop; + for(var p = o.offsetParent; p != null; p = p.offsetParent) + y += p.offsetTop; + + return y; + } + else + return o.y; +} + +function getLayer(id) { + if(isW3C) + return document.getElementById(id); + else if(isIE) + return document.all[id]; + else if(window.document.layers[id]) + return window.document.layers[id]; + else + return layerWalk(window.document.layers,'.document.layers.'+id); +} + +function getElementWidth(l){ + return l.width; +} + +function getLayerHeight(l){ + return eval('l'+yOff); +} + +function getLayerWidth(l){ + return eval('l'+xOff); +} + +function getLayerX(l) { + return eval('l'+sD+xRef); +} + +function getLayerY(l) { + return eval('l'+sD+yRef); +} + +function moveLayerX(l,left) { + eval ('l'+sD+xRef+'='+left); +} + +function moveLayerY(l,top) { + eval ('l'+sD+yRef+'='+top); +} + +function moveLayer(l,left,top) { + moveLayerX(l,left); + moveLayerY(l,top); +} + +function setLayerText(l,t) { + if(isIE || isW3C){ + l.innerHTML = t; + } + else{ + l.document.open(); + l.document.write(t); + l.document.close(); + } +} + +function getEvent(e) { + return eval(sEvent); +} + +function getEventElement(e) { + return eval('getEvent(e)'+eSrc); +} + +function getEventX(e) { + return eval('getEvent(e)'+xEvent); +} + +function getEventY(e) { + return eval('getEvent(e)'+yEvent); +} + +function getKeyCode(e) { + return eval('getEvent(e)'+sKey); +} + +function getControlKey(e) { + if(isW3C || isIE){ + return getEvent(e).ctrlKey; + } + else{ + return (e.modifiers & Event.CONTROL_MASK) != 0; + } +} + +function getKeyStr(e) { + return String.fromCharCode(getKeyCode(e)).toLowerCase(); +} + +function focuschild() { + var rv = false; + var ourif = 'child.win.focus(); rv = true;'; + var ourelse = 'child.win = null; window.onfocus = null;'; + + if(isIE && js_version >= 1.3){ + eval('try {'+ourif+'} catch (all) {'+ourelse+'}'); + } + else{ + eval('if((child.win == null) || (child.win.closed)){'+ourelse+'}else{'+ourif+'}'); + } + + return rv; +} + +function cOpen(u,n,a,w,h) { + if(!focuschild()){ + var xWin = getWindowX(), yWin = getWindowY(); + var wPage = getDisplayWidth(), hPage = getDisplayHeight();; + var x = Math.min(window.screen.width - wPage, Math.max(0, xWin + ((wPage - w)/2))); + var y = Math.min(window.screen.height - hPage, Math.max(0, yWin + ((hPage - h)/2))); + var f = a ? a+',' : ''; + var now = new Date(); + + child.win = window.open(u,n+now.getTime(),f+'width='+w+',height='+h+',screenX='+x+',screenY='+y+',top='+y+',left='+x); + window.onfocus = focuschild; + } + + return child.win; +} + +function cnOpen(u,n,a,w,h) { + var xOffset = (window.screen.width - w)/2, yOffset = (window.screen.height - h)/2; + window.open(u,n,a+',width='+w+',height='+h+',screenX='+xOffset+',screenY='+yOffset+',top='+yOffset+',left='+xOffset); +} + +function composeMsg(f,d,k) { + var s = 'compose.tcl', replace = 0; + switch(f) { + //case 'reply' : if(confirm('Include all recipients in Reply') == true) c = '?style=ReplyAll&uid='+d ; else c = '?style=Reply&uid='+d ; break; + case 'reply' : s='reply.tcl'; c = '?style=ReplyAll&uid='+d+'&cid='+k ; break; + case 'fwd' : c = '?style=Forward&uid='+d+'&cid='+k ; break; + case 'mailto' : c = '?to='+d+'&cid='+k ; break; + case 'nickto' : c = '?nickto='+d+'&cid='+k ; replace = 1; break; + default : c = '?cid='+k ; break; + } + if(!replace) + cOpen(s+c, 'compose', 'scrollbars=yes,resizable=yes', 800, 560); + else + window.location.href = s + c; + return false; +} + +function isanum(s) { + if(s.length == 0) + return false; + + for(var i = 0; i < s.length; i++) + if(s.charCodeAt(i) < 48 || s.charCodeAt(i) > 57) + return false; + + return true; +} + +function confOpen(s) {cOpen(s,'config','scrollbars=yes',800,560); return false;} +function abookOpen(s) {cOpen(s,'addrbook','scrollbars=yes,resizable=yes',800,560); return false;} +function helpOpen(s) {cOpen(s,'help','scrollbars=yes,resizable=yes',600,600); return false;} +function aeOpen(s) {cOpen(s, 'addredit', 'scrollbars=yes,resizable=yes', 700, 500); return false} +function taOpen(s) {cOpen(s, 'takeaddr', 'scrollbars=yes,resizable=yes', 700, 500); return false} +function quitOpen(s) {cOpen(s, 'quit', '', 420, 200); return false} + +function doReload(ival) { + if((child.win == null) || (child.win.closed)){ + var newurl = window.location.href.replace(/\?.*$/, ''); + window.location.replace(newurl+'?reload=1'); + } + else{ + var i = getImage('logo'); + if(i){ + var now = new Date(); + var t = new String(); + + t += now.getYear(); + t += now.getMonth(); + t += now.getDate(); + t += now.getHours(); + t += now.getMinutes(); + t += now.getSeconds(); + i.src = location.href.replace(/(.*)\/[^\/]*\.tcl.*/,'$1/ping.tcl/'+t+'/'+ival+'/'+(t - (t % ival))+'.gif'); + } + } +} + +function reloadTimer(s) { + reloadtimer = window.setInterval('doReload('+s+')', s * 1000); +} + +function wp_escape(s) { + var t = escape(s); + t = t.replace(/\+/, '%2b'); + return t; +} + +function flipCheck(eid){ + var cb = window.document.getElementById(eid); + if(cb) cb.checked = !cb.checked; + return false; +} diff --git a/web/cgi/pub/tclsh b/web/cgi/pub/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/pub/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/session/.htaccess b/web/cgi/session/.htaccess new file mode 100644 index 00000000..a4f615c2 --- /dev/null +++ b/web/cgi/session/.htaccess @@ -0,0 +1,28 @@ + +DirectoryIndex greeting.tcl + +# +# mod_rewrite rules to coerce secure (https) access to underlying pages +# + +RewriteEngine on + +# +# If the server's connecting port isn't secure (https), then +# redirect request to same location but such that the communication +# is secure. NOTE: this isn't as secure as turning off the unsecure +# port because any confidential information in the request is exposed +# in the unsuspecting request on the unsecure port. Shouldn't really +# be a problem since the secure content should only contain secure +# references and the likelihood that a client mucks with the url into +# a reference to secure content is pretty darn small. +# + +RewriteCond %{SERVER_PORT} !=443 + +# +# Include SCRIPT_URL incase webpine package isn't in the +# root of the server's data +# +RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=permanent,L] + diff --git a/web/cgi/session/_htaccess b/web/cgi/session/_htaccess new file mode 100644 index 00000000..a4f615c2 --- /dev/null +++ b/web/cgi/session/_htaccess @@ -0,0 +1,28 @@ + +DirectoryIndex greeting.tcl + +# +# mod_rewrite rules to coerce secure (https) access to underlying pages +# + +RewriteEngine on + +# +# If the server's connecting port isn't secure (https), then +# redirect request to same location but such that the communication +# is secure. NOTE: this isn't as secure as turning off the unsecure +# port because any confidential information in the request is exposed +# in the unsuspecting request on the unsecure port. Shouldn't really +# be a problem since the secure content should only contain secure +# references and the likelihood that a client mucks with the url into +# a reference to secure content is pretty darn small. +# + +RewriteCond %{SERVER_PORT} !=443 + +# +# Include SCRIPT_URL incase webpine package isn't in the +# root of the server's data +# +RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=permanent,L] + diff --git a/web/cgi/session/alpine.tcl b/web/cgi/session/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/session/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/session/greeting.tcl b/web/cgi/session/greeting.tcl new file mode 100755 index 00000000..a6acc1e5 --- /dev/null +++ b/web/cgi/session/greeting.tcl @@ -0,0 +1,395 @@ +#!./tclsh +# $Id: greeting.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# suck in any global config +source ./alpine.tcl + +# figure out SSL defaults +if {[info exists _wp(ssl_default)] && $_wp(ssl_default) == 0} { + set ssl 0 +} else { + set ssl 1 + if {[info exists _wp(ssl_safe_domains)]} { + if {[info exists env(REMOTE_HOST)]} { + foreach d $_wp(ssl_safe_domains) { + regsub -all {\.} $d {\.} d + if {[regexp -nocase "$d\$" $env(REMOTE_HOST)]} { + set ssl 0 + break + } + } + } + + if {$ssl && [info exists env(REMOTE_ADDR)]} { + regexp {([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)} $env(REMOTE_ADDR) dummy a b c d + set h "$d.$c.$b.$a.in-addr.arpa" + if {[catch {exec nslookup -q=PTR $h "2&>1"} pr] == 0} { + foreach l [split $pr \n] { + if {[regexp -nocase "^$h\[ \]*name = (.*)\$" $l dummy inaddr]} { + break + } + } + } + + if {[info exists inaddr]} { + foreach d $_wp(ssl_safe_domains) { + if {[set n [expr {[string length $inaddr] - [string length $d] - 1}]] > 1 + && [string compare [string tolower [string range $inaddr $n end]] [string tolower ".$d"]] == 0} { + set ssl 0 + break + } + } + } + } + } + + if {$ssl && [info exists _wp(ssl_safe_addrs)]} { + set ra [split $env(REMOTE_ADDR) .] + foreach a $_wp(ssl_safe_addrs) { + if {[llength $a] == 2} { + set low [split [lindex $a 0] .] + set hi [split [lindex $a 1] .] + + foreach a $ra b $low c $hi { + if {$b == $c} { + if {$a != $b} { + break + } + } else { + if {$a >= $b && $a <= $c} { + set ssl 0 + break + } + } + } + } else { + foreach a [split $a .] b $ra { + if {[string length $a]} { + if {$a != $b} { + break + } + } else { + set $ssl 0 + break + } + } + } + + if {!$ssl} { + break + } + } + } +} + +cgi_eval { + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + + cgi_head { + WPStdHtmlHdr Logon + WPStdScripts $_wp(indexheight) + + if {$_wp(flexserver)} { + cgi_javascript { + cgi_put "function bogus(f,o) {" + cgi_put " if(o.value.length == 0){" + cgi_put " alert('What '+f+' will you be using to log in to your IMAP server?\\nPlease fill in the '+f+' field.');" + cgi_put " o.focus();" + cgi_put " return true;" + cgi_put " }" + cgi_put " return false;" + cgi_puts "}" + cgi_put "function doSubmit() {" + cgi_put " var f = document.Login;" + cgi_put " var l = f.Server;" + cgi_put " var o = l.options\[l.selectedIndex\];" + cgi_put " if(bogus('Username',f.User) || bogus('Password',f.Pass)) return false;" + cgi_put " if(o.value < 0){" + cgi_put " o.value = alien_server;" + cgi_put " }" + cgi_put " return true;" + cgi_puts "}" + cgi_put "function customServer() {" + cgi_put " var f = document.Login;" + cgi_put " var l = f.Server;" + cgi_put " var o = l.options\[l.selectedIndex\];" + if {[info exists env(REMOTE_USER)]} { + cgi_put " f.User.value = (o.value < 0) ? alien_user : def_user;" + cgi_put " f.Pass.value = (o.value < 0) ? alien_pass : def_pass;" + } + cgi_put " if(o.value < 0){" + cgi_put " if(s = prompt('IMAP Server Name (append \"/ssl\" for secure link)',o.s ? o.s : '')){" + cgi_put " alien_server = s;" + cgi_put " o.text = 'Your Server: '+alien_server;" + cgi_put " f.User.onfocus = null;" + cgi_put " f.Pass.onfocus = null;" + cgi_put " f.User.focus();" + cgi_put " }" + cgi_put " else if(alien_server.length == 0){" + if {[info exists env(REMOTE_USER)]} { + cgi_put " f.User.onfocus = f.User.blur;" + cgi_put " f.Pass.onfocus = f.Pass.blur;" + cgi_put " f.User.value = def_user;" + cgi_put " f.Pass.value = def_pass;" + } + cgi_put " l.selectedIndex = 0;" + cgi_put " }" + cgi_put " }" + if {[info exists env(REMOTE_USER)]} { + cgi_put " else {" + cgi_put " f.User.onfocus = f.User.blur;" + cgi_put " f.Pass.onfocus = f.Pass.blur;" + cgi_put " }" + } + cgi_puts "}" + if {[info exists env(REMOTE_USER)]} { + cgi_put "var def_user = new Array('$env(REMOTE_USER)');" + cgi_put "var def_pass = new Array('x');" + cgi_put "var alien_server = '';" + cgi_put "var alien_user = '';" + cgi_put "var alien_pass = '';" + cgi_put "function customSave() {" + cgi_put " var f = document.Login;" + cgi_put " var s = f.Server.options\[f.Server.selectedIndex\];" + cgi_put " if(s.value < 0){" + cgi_put " alien_user = f.User.value;" + cgi_put " alien_pass = f.Pass.value;" + cgi_put " }" + cgi_puts "}" + } + } + } + } + + if {[info exists env(REMOTE_USER)]} { + set onload "" + } else { + set onload "onLoad=document.Login.User.focus()" + } + + cgi_body $onload { + if {$_wp(flexserver)} { + set onsubmit "onSubmit=return doSubmit()" + } else { + set onsubmit "" + } + + cgi_form session/init method=post enctype=multipart/form-data name=Login $onsubmit { + cgi_javascript { + cgi_puts "document.write('<input name=\"hPx\" value='+window.getDisplayHeight()+' type=hidden notab>');" + } + + cgi_table height=100% width=100% align=center { + + cgi_table_row { + cgi_table_data align=center valign=bottom height=18% colspan=8 { + set intro "Welcome to $_wp(appname)" + if {[info exists env(REMOTE_USER)]} { + set conf [subst [lindex [lindex $_wp(hosts) 0] 2]] + set pldap [file join $_wp(bin) $_wp(pldap)] + if {[catch {exec $pldap -p $conf -u $env(REMOTE_USER)} pname] == 0} { + append intro ", $pname" + } + } + + cgi_put [font size=+2 face=Helvetica [bold $intro]] + } + } + + cgi_table_row { + cgi_table_data width=36% height=35% align=right valign=middle { + cgi_put [cgi_imglink logo] + } + + cgi_table_data width=5% { + cgi_puts [cgi_nbspace] + } + + cgi_table_data { + cgi_table border=0 cellspacing=8 { + cgi_table_row { + cgi_table_data align=right valign=bottom { + cgi_puts [font size=+1 face=Helvetica "Username:"] + } + + cgi_table_data align=left valign=bottom { + if {[info exists env(REMOTE_USER)]} { + set user "User=$env(REMOTE_USER)" + set rdonly "onFocus=this.blur();" + } else { + set user "User=" + set rdonly "" + } + + if {$_wp(flexserver) && [info exists env(REMOTE_USER)]} { + set onblur onBlur=customSave() + } else { + set onblur "" + } + + cgi_text $user type=text maxlength=30 tableindex=1 $rdonly $onblur + } + } + + cgi_table_row { + cgi_table_data align=right valign=middle { + cgi_puts [font size=+1 face=Helvetica "Password:"] + } + + cgi_table_data align=left valign=middle { + if {[info exists env(REMOTE_USER)]} { + set pass "Pass=*" + set rdonly "onFocus=this.blur();" + } else { + set pass "Pass=" + set rdonly "" + } + + if {$_wp(flexserver) && [info exists env(REMOTE_USER)]} { + set onblur onBlur=customSave() + } else { + set onblur "" + } + + cgi_text $pass type=password maxlength=30 tableindex=2 $rdonly $onblur + } + } + + cgi_table_row { + cgi_table_data align=right valign=middle { + cgi_puts [font face=Helvetica size=+1 "Server:"] + } + + cgi_table_data align=left valign=top { + if {[info exists _wp(hosts)]} { + if {$_wp(flexserver)} { + set onchange onChange=customServer() + if {[info exists env(REMOTE_USER)]} { + set onblur onBlur=customSave() + } else { + set onblur "" + } + } else { + set onchange "" + set onblur "" + } + + cgi_select Server align=left $onchange $onblur { + for {set j 0} {$j < [llength $_wp(hosts)]} {incr j} { + cgi_option [lindex [lindex $_wp(hosts) $j] 0] value=$j + } + + if {$_wp(flexserver)} { + cgi_javascript { + cgi_puts "document.write('<option value=\"-1\">Server of Your Choice');" + } + } + } + } else { + cgi_text Server= type=text maxlength=256 + } + } + } + } + } + } + + if {[info exists env(REMOTE_USER)]} { + cgi_table_row { + cgi_table_data align=center valign=top height=1% colspan=8 { + cgi_puts "Protect your privacy! When you finish, [cgi_url "completely exit your Web browser" "http://www.washington.edu/computing/web/logout.html"]." + } + } + } + + cgi_table_row { + cgi_table_data align=center valign=top colspan=8 "style=padding-bottom:10" { + cgi_submit_button login=Login + } + } + + if {[info exists _wp(plainservpath)] && [string length $_wp(plainservpath)]} { + cgi_table_row { + cgi_table_data colspan=8 align=center valign=middle { + cgi_table border=0 width=30% { + cgi_table_row { + cgi_table_data rowspan=2 valign=top { + if {$ssl} { + set checked checked + } else { + set checked "" + } + + cgi_checkbox ssl=1 $checked + } + + cgi_table_data { + cgi_put [cgi_font size=-1 face=Helvetica "Use [cgi_url "SSL Session Encryption" "$_wp(serverpath)/$_wp(appdir)/$_wp(ui1dir)/help/secure.html" target=_blank]"] + cgi_br + set t "Session encryption over low-speed connections may slow WebPine, but prevents eavesdropping. Passwords are safely encrypted though." + + cgi_division style=background-color:#eeeeee { + cgi_put [cgi_font size=-2 face=Helvetica $t] + } + } + } + } + } + } + } else { + cgi_text ssl=1 type=hidden notab + } + + if {[info exists _wp(oldserverpath)] && [regexp {^[Hh][Tt][Tt][Pp][Ss]://} $_wp(oldserverpath)]} { + cgi_table_row { + cgi_table_data colspan=8 align=center valign=middle { + cgi_division "style=\"width: 30% ; font-family: Helvetica; font-size: small ; background-color: #EEEEEE; padding: 8 2 \"" { + cgi_puts "For the time being, the [cgi_url "old version" $_wp(oldserverpath)] is still available." + } + } + } + } + + if {[catch {open [file join $_wp(cgipath) $_wp(motd)] r} id] == 0} { + cgi_table_row { + cgi_table_data colspan=8 height=20% valign=top { + cgi_table width=100% { + cgi_table_data height=40 width=18% { + # cgi_puts [cgi_imglink bang] + cgi_puts [cgi_nbspace] + } + + cgi_table_data { + cgi_puts [font size=-1 face=Helvetica [read $id]] + } + + cgi_table_data width=18% { + # cgi_puts [cgi_imglink bang] + cgi_puts [cgi_nbspace] + } + } + } + } + + close $id + } + } + } + } + } +} diff --git a/web/cgi/session/init.tcl b/web/cgi/session/init.tcl new file mode 100755 index 00000000..00f0f903 --- /dev/null +++ b/web/cgi/session/init.tcl @@ -0,0 +1,218 @@ +#!./tclsh +# $Id: init.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# init.tcl +# +# Purpose: CGI script to establish foundation for webpine session + +# and any global config +source ./alpine.tcl + + +cgi_eval { + if {$_wp(debug)} { + cgi_debug -on + } + + # + # Import username and password from pubcookie, if possible. + # Otherwise get it from the form that was submitted. + # + cgi_input + + if {[catch {cgi_import User}] || 0 == [string length $User]} { + WPInfoPage "Bogus Username" \ + "[font size=+2 "Sorry, didn't catch your [bold name]!"]" \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start], and fill in a [italic Username]..." + return + } + + if {[catch {cgi_import Pass}]} { + set Pass "" + } + + if {[catch {cgi_import Server}] || 0 == [string length $Server]} { + WPInfoPage "Bogus Server" \ + "[font size=+2 "Invalid Server specified"]" \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start], and fill in a [italic Server]..." + return + } + + catch {cgi_import hPx} + + set defconf [file join $_wp(confdir) $_wp(defconf)] + set confloc "" + + if {[string length $Server] < 256 && 0 == [regexp {[[:cntrl:]]} $Server]} { + if {[info exists _wp(hosts)] && $Server >= 0 && $Server < [llength $_wp(hosts)]} { + set sdata [lindex $_wp(hosts) $Server] + + set env(IMAP_SERVER) "[subst [lindex $sdata 1]]/user=$User" + + if {[llength $sdata] > 2 && [string length [lindex $sdata 2]]} { + set defconf [subst [lindex $sdata 2]] + } else { + # + # Validate input? + # + WPInfoPage "Internal Error" \ + [font size=+2 "IMAP Server Mismatch"] \ + "Please complain to the [link Admin] and visit the [cgi_link Start] later." + return + } + } elseif {[regexp {/user=} $Server]} { + set env(IMAP_SERVER) "$Server" + } else { + set env(IMAP_SERVER) "$Server/user=$User" + } + + set confloc "\{$env(IMAP_SERVER)\}$_wp(config)" + + regexp {^[^:/]*} $env(IMAP_SERVER) env(IMAP_SERVER_BASE) + } else { + WPInfoPage "Bad Server Name" [font size=+2 "Server Name too long or has bogus characters."] \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start] to try again..." + return + } + + set confloc "\{$env(IMAP_SERVER)\}$_wp(config)" + + if {[catch {regexp {^[^:/]*} $env(IMAP_SERVER) env(IMAP_SERVER_BASE)}]} { + set env(IMAP_SERVER_BASE) "" + } + + # in less rigid settings, it might make sense to allow + # for random input folder names... + # cgi_import Folder + + # + # Server, folder and credentials in hand, fork the client... + # <OL> + # <LI> The session is *assumed* to run over SSL. + # <LI> The server is *assumed* to be a black box + # (no, possibly hostile, user shells) + # <LI> We need to run the alpine process as the given user. + # Unless we bind to a specific server, http authentication + # isn't sufficient as t + # + # <LI> The session-id connects future requests to the newly + # created alpine engine. + # <LI> The auth-cookie will tell us the session-id isn't coming from + # j. random cracker's client + # </OL> + # + + if {[catch {exec [file join $_wp(bin) launch.tcl]} _wp(sessid)]} { + WPInfoPage "Internal Error" [font size=+2 $_wp(sessid)] \ + "Please complain to the [link Admin] and visit the [cgi_link Start] later." + return + } else { + WPValidId $_wp(sessid) + } + + if {[catch {cgi_import ssl}] || $ssl == 0} { + WPCmd set serverroot $_wp(plainservpath) + cgi_root $_wp(plainservpath) + } + + # stash login credentials away for later + if {[catch { + WPCmd set nojs 1 + WPCmd PESession creds 0 $confloc $User $Pass + } result]} { + WPInfoPage "Initialization Failure" [font size=+2 "Initialization Failure: $result"] \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start] to try again..." + catch {WPCmd exit} + return + } + + set cookiepath $_wp(appdir) + + # stash session open parms in alpined's interpreter + lappend parms User + lappend parms $User + lappend parms Server + lappend parms $Server + lappend parms confloc + lappend parms $confloc + lappend parms defconf + lappend parms $defconf + lappend parms startpage + + lappend parms "$_wp(appdir)/$_wp(ui2dir)/browse/0/INBOX" + lappend parms prunepage + lappend parms "" + + if {[info exists hPx]} { + lappend parms hPx + lappend parms $hPx + } + + if {[catch {WPCmd set wp_open_parms $parms} result]} { + WPInfoPage "Internal Error" [font size=+2 $result] \ + "Please complain to the [link Admin] and visit the [cgi_link Start] later." + return + } + + # return a page that says we're logging in the user + # have that page return to opening the session... + + catch {WPCmd set wp_ver_dir $cookiepath} + + set sessid "$_wp(sessid)@[info hostname]" + + cgi_http_head { + WPExportCookie sessid $sessid $cookiepath + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + cgi_http_equiv Refresh "0; url=$_wp(serverpath)/session/logon.tcl?sessid=$sessid" + } + + cgi_body { + cgi_table height="20%" { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_nbspace] + } + } + } + + cgi_center { + cgi_table border=0 width=500 cellpadding=3 { + cgi_table_row { + cgi_table_data align=center rowspan=2 { + cgi_put [cgi_imglink logo] + } + + cgi_table_data rowspan=2 { + cgi_put [cgi_img [WPimg dot2] border=0 width=18] + } + + cgi_table_data { + cgi_puts [cgi_font size=+2 "Logging into $_wp(appname)"] + } + } + + cgi_table_row { + cgi_table_data { + cgi_puts "Please be patient! Depending on Inbox size, server load and other factors this may take a moment [cgi_img [WPimg dotblink]]" + } + } + } + } + } + } +} diff --git a/web/cgi/session/logon.tcl b/web/cgi/session/logon.tcl new file mode 100755 index 00000000..2d675cf1 --- /dev/null +++ b/web/cgi/session/logon.tcl @@ -0,0 +1,169 @@ +#!./tclsh +# $Id: logon.tcl 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# logon.tcl +# +# Purpose: CGI script to authenticate user based on provided +# credentials and launch them into the mailbox index + +# and any global config +source ./alpine.tcl + +# don't use WPEval since it'll mask open's credential failure case +cgi_eval { + + if {$_wp(debug)} { + cgi_debug -on + } + + # + # Import username and password from pubcookie, if possible. + # Otherwise get it from the form that was submitted. + # + cgi_input + + if {[catch { + cgi_import sessid + WPValidId $sessid + } result]} { + WPInfoPage "Web Alpine Error" [font size=+2 "$result"] \ + "Please complain to the [cgi_link Admin] and visit the [cgi_link Start] later." + return + } + + if {[catch {WPCmd set wp_open_parms} parms]} { + WPInfoPage "Internal Error" [font size=+2 $parms] \ + "Please complain to the [link Admin] and visit the [cgi_link Start] later." + } else { + catch {WPCmd unset wp_open_parms} + + foreach {p v} $parms { + set $p $v + } + + if {[catch {WPCmd PESession open $User $confloc $defconf} answer]} { + if {0 == [string length $answer] || 0 == [string compare BADPASSWD [lindex $answer 0]]} { + set answer "Unknown Username or Incorrect Password" + } + + set alerts {} + if {[catch {WPCmd PEInfo statmsgs} statmsgs] == 0} { + # display any IMAP alerts + foreach m $statmsgs { + if {[regexp {^Alert received.*\[ALERT\] (.*)$} $m dummy a]} { + if {[lsearch -exact $alerts $a] < 0} { + lappend alerts $a + } + } + } + } + + WPInfoPage "Login Failure" [font size=+2 $answer] \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start] to try again..." \ + {} [join $alerts "<br>"] + + # unlaunch the thing + catch {WPCmd PESession close} + catch {WPCmd exit} + return + } + + # determine suitable number of index lines for the indicated display size + # based on: + # + # 1. a header length of 72 pixels + # 2. a TD font-size plus padding of 24 points + # + + set indexheight [WPCmd PEInfo indexheight] + if {[string length $indexheight] == 0} { set indexheight $_wp(indexheight)} + if {[info exists hPx] && [regexp {^[0-9]+$} $hPx]} { + # "66" comes from _wp(titlethick) + _wp(titlesep) + ((index tables cellpaddings * 2) = 8) + some fudge + set indexlines [expr (($hPx - 66) / $indexheight) - 1] + } + + if {[info exists indexlines] == 0 || $indexlines <= 0} { + set indexlines [WPCmd PEInfo indexlines] + } + + if {$indexlines <= 0} { + set indexlines $_wp(indexlines) + } + + # start with the message indicated by the + # 'incoming-startup-rule' in the current index + set firstmsg 1 + if {![catch {WPCmd PEMailbox firstinteresting} firstint] && $firstint > 0} { + set messagecount [WPCmd PEMailbox messagecount] + for {set i 1} {$i < $messagecount} {incr i $indexlines} { + if {$i >= $firstint} { + break + } + + set firstmsg $i + } + + # show whole last page + if {$firstmsg + $indexlines > $messagecount} { + if {[set n [expr ($messagecount + 1) - $indexlines]] > 0} { + set firstmsg $n + } else { + set firstmsg 1 + } + } + } + + if {[catch {WPCmd PEInfo sort} defsort]} { + set defsort {Date 0} + } + + # set these in alpined's interp so they're fished out by WPImport + if {[catch { + WPCmd set sort [lindex $defsort 0] + WPCmd set rev [lindex $defsort 1] + WPCmd set ppg $indexlines + WPCmd set width $_wp(width) + WPCmd set serverid $Server} result]} { + WPInfoPage "Initialization Failure" [font size=+2 $result] \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start] to try again..." + catch {WPCmd PESession close} + catch {WPCmd exit} + return + } + + if {[catch {WPCmd PEMailbox uid $firstmsg} exp]} { + set exp 1 + } + + WPCmd set top $exp + + if {[catch {WPCmd set serverroot} serverroot] == 0} { + cgi_root $serverroot + } + + set startpage "[cgi_root]/${startpage}?sessid=$sessid" + + if {[string length $prunepage] && [WPCmd PEInfo prunecheck] == 1} { + set startpage "[cgi_root]/${prunepage}cid=[WPCmd PEInfo key]&sessid=${sessid}&start=[WPPercentQuote ${startpage}]" + } + + cgi_http_head { + if {[info exists env(REMOTE_USER)]} { + # redirect thru intermediate so session id and secured user name can get bound in uidampper + cgi_redirect $_wp(serverpath)/session/startup.tcl?sessid=${sessid}&page=[WPPercentQuote $startpage] + } else { + cgi_redirect $startpage + } + } + } +} diff --git a/web/cgi/session/logout.tcl b/web/cgi/session/logout.tcl new file mode 100755 index 00000000..698e3558 --- /dev/null +++ b/web/cgi/session/logout.tcl @@ -0,0 +1,67 @@ +#!./tclsh +# $Id: logout.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# Imported args +set logout_vars { + {serverid {} 0} + {expinbox {} 0} + {expcurrent {} 0} + {cid "Missing Command ID"} +} + +# and any global config +source ./alpine.tcl + +WPEval $logout_vars { + + if {$cid != [WPCmd PEInfo key]} { + error [list _action Logout "Invalid Operation ID" "Please close this window."] + } + + if {$expinbox && [catch {WPCmd PEMailbox expunge inbox} result]} { + set logouterr $result + } + + if {$expcurrent && [catch {WPCmd PEMailbox expunge current} result]} { + if {[info exists logouterr] == 0} { + set logouterr $result + } + } + + if {[catch {WPCmd PESession close} result]} { + if {[info exists logouterr] == 0} { + set logouterr $result + } + } + + if {[catch {WPCmd set wp_ver_dir} verdir]} { + set verdir $_wp(appdir) + } + + catch {WPCmd exit} + + cgi_http_head { + set parms "?verdir=${verdir}" + + if {[regexp {^[0-9]+$} $serverid]} { + append parms "&serverid=$serverid" + } + + if {[info exists logouterr]} { + append parms "&logerr=[WPPercentQuote $logouterr]" + } + + cgi_redirect $_wp(serverpath)/$_wp(appdir)/farewell.tcl${parms} + } +} + diff --git a/web/cgi/session/logout/alpine.tcl b/web/cgi/session/logout/alpine.tcl new file mode 120000 index 00000000..5ad8d42f --- /dev/null +++ b/web/cgi/session/logout/alpine.tcl @@ -0,0 +1 @@ +../alpine.tcl
\ No newline at end of file diff --git a/web/cgi/session/logout/logout.tcl b/web/cgi/session/logout/logout.tcl new file mode 100755 index 00000000..39587e4e --- /dev/null +++ b/web/cgi/session/logout/logout.tcl @@ -0,0 +1,51 @@ +#!./tclsh + + +# +# and any global config +# + +source ./alpine.tcl + +cgi_eval { + + cgi_input + + if {[catch {cgi_import serverid}]} { + set serverid 0 + } + + catch {cgi_import logerr} + + cgi_http_head { + WPStdHttpHdrs + + # clear cookies + cgi_cookie_set sessid=0 expires=now + } + + if {[info exists env(REMOTE_USER)]} { + set log_text [font class=notice "Protect your privacy![cgi_nl]When you finish, [cgi_url "completely exit your Web browser" http://www.washington.edu/computing/web/logout.html class=notice]."] + append log_text "[cgi_nl][cgi_nl]Or you may want to:" + append log_text "<center><ul>" + if {[catch {cgi_import ppg}]} { + set perpage "" + } else { + set perpage "&ppg=$ppg" + } + + append log_text "<li>[cgi_url "restart Web Alpine" "http://alpine.washington.edu"]" + append log_text "<li>[cgi_url "go to MyUW" "http://myuw.washington.edu"]" + append log_text "</ul></center>" + set log_url "" + } else { + set log_text "Please visit the [cgi_link Start] for a new session." + set log_url $_wp(serverpath)/ + } + + if {[info exists logerr] && [string length $logerr]} { + set log_text "[cgi_bold "Please Note"]: A problem, \"$logerr\", occurred while ending your session.<p>${log_text}" + } + + WPInfoPage "Logged Out" "[font size=+2 face=Helvetica "Thank you for using Alpine"]" $log_text $log_url +} diff --git a/web/cgi/session/logout/tclsh b/web/cgi/session/logout/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/session/logout/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/session/monitor.tcl b/web/cgi/session/monitor.tcl new file mode 100755 index 00000000..70edf61f --- /dev/null +++ b/web/cgi/session/monitor.tcl @@ -0,0 +1,282 @@ +#!./tclsh +# $Id: monitor.tcl 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# monitor.tcl + +# read config +source ./alpine.tcl + +proc nicetime {timeoutput} { + if {[regexp {^[0-9]+ } $timeoutput msec]} { + return "[format {%d.%06d} [expr {$msec / 1000000}] [expr {$msec % 1000000}]] seconds" + } else { + return $timeoutput + } +} + +# take process snapshot +#set cmd "/bin/ps -lC alpined --sort=cutime" +set cmd "/bin/ps -auxww --sort=cutime" +if {[catch "exec $cmd" result]} { + set prohdr "ps error: $result" + set proclist {} +} else { + set r [split $result "\n"] + set prochdr [lindex $r 0] + set proclist [lrange $r 1 end] +} + +cgi_eval { + cgi_html { + cgi_head { + cgi_title "Web Alpine Monitor" + cgi_puts "<style type='text/css'>" + cgi_puts ".monsec { text-decoration: underline ; margin: 4}" + cgi_puts "</style>" + } + + cgi_body { + cgi_h2 "WebPine Status // [info hostname] // [clock format [clock seconds]]" + + ## + ## system performance monitor + ##n + cgi_preformatted { + # simple server load + set cmd "/usr/ucb/uptime" + if {[catch "exec $cmd" result]} { + cgi_puts "uptime unavailable: $result" + } else { + cgi_puts [cgi_span class=monsec "Server uptime"] + foreach l [split $result "\n"] { + cgi_puts " $l" + } + } + + cgi_br + + # list alpined adapters + foreach l $proclist { + if {[regexp $_wp(servlet) $l] || [regexp $_wp(pc_servlet) $l]} { + lappend adapters $l + } + } + + cgi_puts [cgi_span class=monsec "WebPine Adapters ([llength $adapters])"] + cgi_puts " $prochdr" + foreach l $adapters { + cgi_puts " $l" + } + + cgi_br + + # tmp disc usage + cgi_puts [cgi_span class=monsec "Temp Directory Usage ($_wp(tmpdir))"] + set cmd "/bin/df $_wp(tmpdir)" + if {[catch "exec $cmd" result]} { + cgi_puts "usage unavailable: $result" + } else { + foreach l [split $result "\n"] { + cgi_puts " $l" + } + } + + cgi_br + + # detach staging usage + cgi_puts [cgi_span class=monsec "Detach Staging Usage ($_wp(tmpdir))"] + set cmd "/bin/df $_wp(detachpath)" + if {[catch "exec $cmd" result]} { + cgi_puts "usage unavailable: $result" + } else { + foreach l [split $result "\n"] { + cgi_puts " $l" + } + } + + if {[info exists report_env]} { + cgi_br + + cgi_puts [cgi_span class=monsec "Environment:"] + + set cgiv { + SERVER_SOFTWARE + SERVER_NAME + GATEWAY_INTERFACE + SERVER_PROTOCOL + SERVER_PORT + REQUEST_METHOD + PATH_INFO + PATH_TRANSLATED + SCRIPT_NAME + QUERY_STRING + REMOTE_HOST + REMOTE_ADDR + AUTH_TYPE + REMOTE_USER + REMOTE_IDENT + CONTENT_TYPE + CONTENT_LENGTH + HTTP_ACCEPT + HTTP_USER_AGENT + } + foreach v $cgiv { + if {[info exists env($v)]} { + cgi_puts " $v: $env($v)" + } + } + } + + + ## + ## session specific feedback + ## + if {[info exists _wp(monitors)] + && [info exists env(REMOTE_USER)] + && [lsearch -exact $_wp(monitors) $env(REMOTE_USER)] >= 0} { + + cgi_br + + cgi_puts [cgi_span class=monsec "Kerberos ticket cache info"] + foreach l [glob "[file join $_wp(tmpdir) krb]*"] { + set file [file join $_wp(tmpdir) $l] + cgi_put " [exec /bin/ls -l $file]" + if {[catch {expr {[clock seconds] - [file mtime $file]}} d]} { + } else { + cgi_puts " ([expr {$d / 3600}] hours, [expr {($d % 3600) / 60}] minutes old)" + } + } + + cgi_br + + cgi_puts [cgi_span class=monsec "uid_mapper Process"] + # Condition of uid_mapper + cgi_puts " $prochdr" + foreach l $proclist { + if {[regexp uidmapper $l]} { + lappend umlist $l + } + } + + if {[info exists umlist]} { + foreach l $umlist { + cgi_puts " $l" + } + } else { + cgi_puts " HELP!!! NO UIDMAPPER RUNNING!!!" + } + + cgi_br + + if {[info exists _wp(hosts)] && [llength $_wp(hosts)]} { + cgi_puts [cgi_span class=monsec "Session Performance (netid: $env(REMOTE_USER))"] + + set sdata [lindex $_wp(hosts) 0] + set User $env(REMOTE_USER) + set env(IMAP_SERVER) "[subst [lindex $sdata 1]]/user=$env(REMOTE_USER)" + + if {[llength $sdata] > 2 && [string length [lindex $sdata 2]]} { + set defconf [subst [lindex $sdata 2]] + set confloc "\{$env(IMAP_SERVER)\}$_wp(config)" + cgi_puts " User Config: $confloc" + + # launch session + cgi_put " alpined Launch: " + set ct [time { + if {[catch {exec [file join $_wp(bin) launch.tcl]} _wp(sessid)]} { + set err "FAILURE: $_wp(sessid)" + } else { + WPValidId $_wp(sessid) + } + }] + + if {[info exists err]} { + cgi_puts $err + } else { + cgi_puts [nicetime $ct] + + cgi_put " Open Inbox: " + set ct [time { + if {[catch {WPCmd PESession open $env(REMOTE_USER) "" $confloc $defconf} answer]} { + set err "FAILURE: " + if {[info exists answer]} { + if {[string length $answer] == 0} { + append err "Unknown Username or Incorrect Password" + } else { + append err $answer + } + } else { + append err "Unknown reason" + } + } + }] + + if {[info exists err]} { + cgi_puts $err + } else { + cgi_puts [nicetime $ct] + + cgi_put " Fetch First Message: " + + set ct [time { + if {[catch { + set msg [WPCmd PEMailbox first] + set uid [WPCmd PEMailbox uid $msg] + set txt [WPCmd PEMessage $uid text] + } txt]} { + set err $txt + } + }] + + if {[info exists err]} { + cgi_puts "FAILURE: $err" + } else { + cgi_puts [nicetime $ct] + + cgi_put " Fetch Last Message: " + + set ct [time { + if {[catch { + set msg [WPCmd PEMailbox last] + set uid [WPCmd PEMailbox uid $msg] + set txt [WPCmd PEMessage $uid text] + } txt]} { + set err $txt + } + }] + + if {[info exists err]} { + cgi_puts "FAILURE: $err" + } else { + cgi_puts [nicetime $ct] + } + } + } + + set ct [time { + catch {WPCmd PESession close} + catch {WPCmd exit} + }] + + cgi_puts " Close Session: [nicetime $ct]" + } + } else { + cgi_puts "Invalid host configuration" + } + + } + } + } + } + } +}
\ No newline at end of file diff --git a/web/cgi/session/queryauth.tcl b/web/cgi/session/queryauth.tcl new file mode 100755 index 00000000..27e10c97 --- /dev/null +++ b/web/cgi/session/queryauth.tcl @@ -0,0 +1,120 @@ +#!./tclsh +# $Id: queryauth.tcl 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# queryauth.tcl +# +# Purpose: CGI script to generate html form used to ask for authentication +# credentials + +# input: +set query_vars { + {cid "Missing Command ID"} + {authcol "Missing Authenticaion Collection"} + {authfolder "Missing Authentication Folder"} + {authpage "No Post Authorization Instructions"} + {authcancel "No Auth Cancel Instructions"} + {authuser "" ""} + {reason "" ""} +} + +# Output: +# +# HTML/Javascript/CSS data representing the message specified +# by the 'uid' argument + + +# inherit global config +source ./alpine.tcl +source ../$_wp(appdir)/$_wp(ui1dir)/cmdfunc.tcl + + +set query_menu { + { + {} + { + { + # * * * * Help * * * * + cgi_put "Get Help" + } + } + } +} + + +WPEval $query_vars { + + if {$cid != [WPCmd PEInfo key]} { + error [list _action open "Invalid Operation ID" "Click Back button to try again."] + } + + cgi_http_head { + WPStdHttpHdrs + } + + cgi_html { + cgi_head { + WPStdHtmlHdr "Authentication Credentials" + WPStyleSheets + } + + if {[string length $authuser]} { + set onload "onLoad=document.auth.pass.focus()" + } else { + set onload "onLoad=document.auth.user.focus()" + } + + cgi_body BGCOLOR="$_wp(bordercolor)" $onload { + cgi_form $_wp(serverpath)/session/setauth.tcl method=post enctype=multipart/form-data name=auth target=_top { + cgi_text "sessid=$sessid" type=hidden notab + cgi_text "cid=$cid" type=hidden notab + cgi_text "authcol=$authcol" type=hidden notab + cgi_text "authfolder=$authfolder" type=hidden notab + cgi_text "authpage=$authpage" type=hidden notab + cgi_text "authcancel=$authcancel" type=hidden notab + + cgi_table border=0 cellspacing=0 cellpadding=2 width="100%" height="100%" { + cgi_table_row { + eval { + cgi_table_data $_wp(menuargs) { + WPTFCommandMenu query_menu {} + } + } + + cgi_table_data valign=top class=dialog { + cgi_division align=center class=dialog "style=\"padding:30 12%\"" { + if {[info exists reason] && [string compare BADPASSWD [string range $reason 0 8]]} { + cgi_puts $reason + } else { + cgi_puts "Login Required" + } + } + + cgi_center { + cgi_puts [cgi_font size=+1 class=dialog "Username: "] + cgi_text user=$authuser maxlength=30 size=25% + cgi_br + cgi_br + cgi_puts [cgi_font size=+1 class=dialog "Password: "] + cgi_text pass= type=password maxlength=30 size=25% + cgi_br + cgi_br + cgi_submit_button auths=Login + cgi_submit_button cancel=Cancel + } + } + } + } + } + } + } +} diff --git a/web/cgi/session/setauth.tcl b/web/cgi/session/setauth.tcl new file mode 100755 index 00000000..c2da7a6b --- /dev/null +++ b/web/cgi/session/setauth.tcl @@ -0,0 +1,68 @@ +#!./tclsh +# $Id: setauth.tcl 764 2007-10-23 23:44:49Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# setauth.tcl +# +# Purpose: CGI script to generate html form used to ask for authentication +# credentials + +# Input: +set auth_vars { + {cid "Missing Command ID"} + {authcol "No Authorization Collection"} + {authfolder "No Authorization Folder"} + {authpage "No Post Authorization Instructions"} + {authcancel "No Auth Cancel Instructions"} + {auths "" 0} + {user "" 0} + {pass "" 0} + {cancel "" 0} +} + +# Output: +# +# Redirect to specified post-authentication page + +# inherit global config +source ./alpine.tcl + + +WPEval $auth_vars { + + if {$cid != [WPCmd PEInfo key]} { + error [list _action open "Invalid Operation ID" "Click Back button to try again."] + } + + # if NOT cancelled + if {[string compare $auths "Login"] == 0 + && [string length $user] + && [catch {WPCmd PESession creds $authcol $authfolder $user $pass}] == 0} { + set redirect $authpage + } else { + set redirect $authcancel + } + + cgi_http_head { + # redirect to the place we stuffed the export info. use the ip address + # to foil spilling any session cookies or the like + + if {[info exists env(SERVER_PROTOCOL)] && [regexp {[Hh][Tt][Tt][PP]/([0-9]+)\.([0-9]+)} $env(SERVER_PROTOCOL) m vmaj vmin] && $vmaj >= 1 && $vmin >= 1} { + cgi_puts "Status: 303 Temporary Redirect" + } else { + cgi_puts "Status: 302 Redirected" + } + + cgi_puts "URI: $redirect" + cgi_puts "Location: $redirect" + } +} diff --git a/web/cgi/session/setauth2.tcl b/web/cgi/session/setauth2.tcl new file mode 100755 index 00000000..ccb4ce17 --- /dev/null +++ b/web/cgi/session/setauth2.tcl @@ -0,0 +1,58 @@ +#!./tclsh +# $Id: setauth2.tcl 391 2007-01-25 03:53:59Z mikes@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# setauth2.tcl +# +# Purpose: CGI script to accept user authorization +# credentials via xmlHttpRequest + +# Input: +set auth_vars { + {c "No Authorization Collection"} + {f "No Authorization Folder"} + {auths "" 0} + {user "" 0} + {pass "" 0} + {cancel "" 0} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $auth_vars { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + return + } +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" +set answer "Problem setting authorization credentials" + + +if {[string compare $auths "Login"] == 0 + && [string length $user] + && [catch {WPCmd PESession creds $c $f $user $pass} answer] == 0} { + cgi_puts "$answer" +} else { + cgi_puts "Cannot accept login: $answer" +} diff --git a/web/cgi/session/setpassphrase.tcl b/web/cgi/session/setpassphrase.tcl new file mode 100755 index 00000000..b4d25e26 --- /dev/null +++ b/web/cgi/session/setpassphrase.tcl @@ -0,0 +1,52 @@ +#!./tclsh +# $Id: setpassphrase.tcl 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# setpassphrase.tcl +# +# Purpose: CGI script to accept user passphrase +# via xmlHttpRequest + +# Input: +set auth_vars { + {auths "" 0} + {pass "" 0} + {cancel "" 0} +} + +# Output: +# + +# inherit global config +source ./alpine.tcl + +# Import data validate it and get session id +if {[catch {WPGetInputAndID sessid}]} { + return +} + +# grok parameters +foreach item $auth_vars { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + return + } +} + +cgi_puts "Content-type: text/html; charset=\"UTF-8\"\n" +set answer "Problem setting passphrase" + +if {[string compare $auths "Smime"] != 0 + || [string length $pass] == 0 + || [catch {WPCmd PESession setpassphrase $pass} answer]} { + cgi_puts "Cannot accept passphrase: $answer" +} diff --git a/web/cgi/session/startup.tcl b/web/cgi/session/startup.tcl new file mode 100755 index 00000000..9e3feec8 --- /dev/null +++ b/web/cgi/session/startup.tcl @@ -0,0 +1,33 @@ +#!./tclsh +# $Id: startup.tcl 764 2007-10-23 23:44:49Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# read config +source ./alpine.tcl + +# Input: page + +# Output: redirection to given page + +cgi_eval { + cgi_input + + if {[catch {cgi_import page}]} { + WPInfoPage "Bogus Page Request" \ + "[font size=+2 "Invalid Page Request!"]" \ + "Please click your browser's [bold Back] button to return to the [cgi_link Start]" + } else { + cgi_http_head { + cgi_redirect $page + } + } +}
\ No newline at end of file diff --git a/web/cgi/session/tclsh b/web/cgi/session/tclsh new file mode 120000 index 00000000..385fc6c6 --- /dev/null +++ b/web/cgi/session/tclsh @@ -0,0 +1 @@ +../tclsh
\ No newline at end of file diff --git a/web/cgi/sounds/ding.wav b/web/cgi/sounds/ding.wav Binary files differnew file mode 100644 index 00000000..5741f232 --- /dev/null +++ b/web/cgi/sounds/ding.wav diff --git a/web/cgi/sounds/mail_msg.wav b/web/cgi/sounds/mail_msg.wav Binary files differnew file mode 100644 index 00000000..d6370e0a --- /dev/null +++ b/web/cgi/sounds/mail_msg.wav diff --git a/web/cgi/tclsh b/web/cgi/tclsh new file mode 120000 index 00000000..922d6309 --- /dev/null +++ b/web/cgi/tclsh @@ -0,0 +1 @@ +../bin/tclsh
\ No newline at end of file diff --git a/web/config/alpine.tcl b/web/config/alpine.tcl new file mode 100644 index 00000000..531dafaf --- /dev/null +++ b/web/config/alpine.tcl @@ -0,0 +1,1148 @@ +# Web Alpine Config options +# $Id: alpine.tcl 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $ +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +encoding system "utf-8" + +set _wp(appname) Alpine +set _wp(admin) admin@sample-domain.edu +set _wp(helpdesk) admin@sample-domain.edu +set _wp(comments) help@sample-domain.edu + +# List of userid's allowed to request the monitor script output +set _wp(monitors) {} + +# directory prefix web server uses for web alpine page requests +# Note: set to {} if DocumentRoot set to the root of web alpine cgi scripts +set _wp(urlprefix) webmail + +# file system path to CGI application files +# directory containing web alpine application scripts and supporting tools +set _wp(fileroot) /usr/local/libexec/alpine + +set _wp(tmpdir) /tmp + +# NOTE: Make SURE tclsh and alpine.tcl symlinks in this directory +set _wp(cgipath) [file join $_wp(fileroot) cgi] + +# CGI scripts implementing U/I, session cookie scope +set _wp(appdir) alpine + +# UI versions +set _wp(ui1dir) 1.0 +set _wp(ui2dir) 2.0 + +# place for CGI scripts not requiring session-key +set _wp(pubdir) pub + +# place for binaries referenced by the CGI scripts +set _wp(bin) [file join $_wp(fileroot) bin] +set _wp(servlet) alpined +set _wp(pc_servlet) pc_alpined +set _wp(pldap) alpineldap + +# place for config files referenced by the CGI scripts +set _wp(confdir) [file join $_wp(fileroot) config] +set _wp(conffile) pine.conf +set _wp(defconf) $_wp(conffile) + +# place for library files used by CGI scripts +set _wp(lib) [file join $_wp(fileroot) lib] + +# directory used temporarily to stage attatched and detached files +set _wp(detachpath) [file join $_wp(fileroot) detach] + +set _wp(imagepath) [file join / $_wp(urlprefix) images] + +set _wp(buttonpath) [file join $_wp(imagepath) buttons silver] + +set _wp(staticondir) env + +set _wp(servername) [info hostname] + +# MUST specify SSL/TLS connection +set _wp(serverport) {} +set _wp(serverpath) https://[file join [join [eval list $_wp(servername) $_wp(serverport)] :] $_wp(urlprefix)] + +# MAY specify a plaintext connection (comment out if plain support undesired) +set _wp(plainport) {} +set _wp(plainservpath) http://[file join [join [eval list $_wp(servername) $_wp(plainport)] :] $_wp(urlprefix)] + +# url of faq page(s) available from initial greeting page +#set _wp(faq) "http://www.yourserver/faqs/alpine.html" + +# url of informational page accessible from initial greeting page +set _wp(releaseblurb) "$_wp(plainservpath)/alpine/help/release.html" + +# url of previous version server to be accessible from initial greeting page +#set _wp(oldserverpath) "https://previous.version.server.edu:444/" + +# session id length: make sure the integer count below matches what's built +# into the pubcookie: "src/pubcookie/wp_uidmapper_lib.h:#define WP_KEY_LEN 6" +set _wp(sessidlen) 6 + +# Where and what format the alpined comm socket should take +set _wp(sockdir) $_wp(tmpdir) +set _wp(sockpat) wp%s + +# skin settings +set _wp(bordercolor) #FEFAC9 +set _wp(menucolor) #3E2E6D +set _wp(dialogcolor) #FEFAC9 +set _wp(titlecolor) #000000 +set _wp(logodir) alpine + +# various timerouts, dimensions and feature settings +set _wp(refresh) 600 +set _wp(timeout) 900 +set _wp(autodraft) 300 +set _wp(logoutpause) 60 +set _wp(indexlines) 20 +set _wp(indexlinesmax) 50 +set _wp(indexheight) 24 +set _wp(navheight) 28 +set _wp(width) 80 +set _wp(titleheight) 34 +set _wp(titlesep) 4 +set _wp(config) remote_pinerc +set _wp(motd) motd +set _wp(save_cache_max) 6 +set _wp(fldr_cache_max) 20 +set _wp(fldr_cache_def) 3 +set _wp(statushelp) 0 +set _wp(imgbuttons) 0 +set _wp(keybindings) 1 +set _wp(dictionary) 0 +set _wp(debug) 0 +set _wp(cmdtime) 0 +set _wp(evaltime) 0 +set _wp(menuargs) {width="112" nowrap valign=top} +set _wp(ispell) /usr/local/bin/ispell + +# Yahoo! User Interface Library location +#set _wp(yui) $_wp(serverpath)/$_wp(appdir)/$_wp(ui2dir)/lib/yui +set _wp(yui) "http://yui.yahooapis.com/2.7.0" + +# usage reporter - input: username as first command line argument +# output: space separated integers usage and total +#set _wp(usage) $_wp(bin)/usage.tcl +#set _wp(usage_link) "https://uwnetid.washington.edu/disk/" + +# limit uploads to 1 file at a time, maximum 20MB. +set _wp(uplim_files) 1 +set _wp(uplim_bytes) 20000000 + +# verify sessid from consistent REMOTE_ADDR (set to 0 for proxying clusters) +set _wp(hostcheck) 0 + +# set to list of domains for which ssl is NOT required +#set _wp(ssl_safe_domains) {} + +# set to list of address blocks or ranges for which ssl is NOT required +#set _wp(ssl_safe_addrs) {} + +# set this value to zero to turn OFF ssl by default +set _wp(ssl_default) 1 + +# allow connecting user to specify imap server on greeting page +set _wp(flexserver) 1 + +# make sure tmp files and such are ours alone to read/write +catch {exec umask 044} + +#fix up indexheight so it isn't too high or too low +set _wp(indexheight) [expr {$_wp(indexheight) <= 20 ? 20 : $_wp(indexheight) >= 30 ? 30 : $_wp(indexheight)}] + +# SPAM reporting facility, if set "Report Spam" button appears at top of View Page +#set _wp(spamaddr) spamaddr@sample-domain.edu +#set _wp(spamfolder) junk-mail +#set _wp(spamsubj) "ATTACHED SPAM" + +# external mail filter config link +#set _wp(filter_link) http://delivery-filter.sample-domain.edu/filter/config + +# external vacation config link +#set _wp(vacation_link) http://vacation.sample-domain.edu/vacation/config + +# +# Nickname server bindings. If not present, prompt for the +# destination of the default pinerc location. +# +set _wp(hosts) { + { + Deskmail + $User.deskmail.washington.edu/ssl + $_wp(confdir)/conf.deskmail + } +} + +# Everybody inherits the cgi, comm packages +lappend auto_path $_wp(lib) + +package require cgi +package require WPComm + +# Recipient of bad news bubbling up from cgi.tcl... +cgi_admin_mail_addr $_wp(admin) + +cgi_sendmail {} + +#cgi_mail_relay localhost +cgi_mail_relay smtpserver.sample-domain.edu + +# set permissions for owner-only handling +cgi_tmpfile_permissions 0640 + +#set upload limits +cgi_file_limit $_wp(uplim_files) $_wp(uplim_bytes) + +# universal body tag parameters +cgi_body_args link=#0000FF vlink=#000080 alink=#FF0000 marginwidth=0 marginheight=0 topmargin=0 leftmargin=0 + +# Common Images Image definitions +cgi_imglink logo [file join $_wp(imagepath) logo $_wp(logodir) big.gif] border=0 "alt=Web Alpine" +cgi_imglink smalllogo [file join $_wp(imagepath) logo $_wp(logodir) small.gif] border=0 "alt=About Web Alpine" +cgi_imglink background [file join $_wp(imagepath) logo $_wp(logodir) back.gif] border=0 align=top +cgi_imglink dot [file join $_wp(imagepath) dot2.gif] border=0 align=top +cgi_imglink increas [file join $_wp(imagepath) increas4.gif] border=0 align=absmiddle +cgi_imglink decreas [file join $_wp(imagepath) decreas4.gif] border=0 align=absmiddle +cgi_imglink expand [file join $_wp(imagepath) b_plus.gif] border=0 "alt=Expand" height=9 width=9 +cgi_imglink contract [file join $_wp(imagepath) b_minus.gif] border=0 "alt=Collapse" height=9 width=9 +cgi_imglink fullhdr [file join $_wp(imagepath) hdr.gif] border=0 "alt=Full Header" +cgi_imglink nofullhdr [file join $_wp(imagepath) hdrnon.gif] border=0 "alt=Digested Header" +cgi_imglink bang [file join $_wp(imagepath) caution.gif] border=0 "alt=!" +cgi_imglink postmark [file join $_wp(imagepath) postmark.gif] border=0 "alt=New Mail" +cgi_imglink gtab [file join $_wp(imagepath) tabs gtab.gif] border=0 align=top +cgi_imglink gdtab [file join $_wp(imagepath) tabs gdtab.gif] border=0 align=top +cgi_imglink abtab [file join $_wp(imagepath) tabs abtab.gif] border=0 align=top +cgi_imglink abdtab [file join $_wp(imagepath) tabs abdtab.gif] border=0 align=top +cgi_imglink ctab [file join $_wp(imagepath) tabs ctab.gif] border=0 align=top +cgi_imglink cdtab [file join $_wp(imagepath) tabs cdtab.gif] border=0 align=top +cgi_imglink ftab [file join $_wp(imagepath) tabs ftab.gif] border=0 align=top +cgi_imglink fdtab [file join $_wp(imagepath) tabs fdtab.gif] border=0 align=top +cgi_imglink mltab [file join $_wp(imagepath) tabs mltab.gif] border=0 align=top +cgi_imglink mldtab [file join $_wp(imagepath) tabs mldtab.gif] border=0 align=top +cgi_imglink mvtab [file join $_wp(imagepath) tabs mvtab.gif] border=0 align=top +cgi_imglink mvdtab [file join $_wp(imagepath) tabs mvdtab.gif] border=0 align=top +cgi_imglink rtab [file join $_wp(imagepath) tabs rtab.gif] border=0 align=top +cgi_imglink rdtab [file join $_wp(imagepath) tabs rdtab.gif] border=0 align=top + + +# Link definitions +cgi_link Admin "Web Alpine Administrator" "mailto:$_wp(admin)" +cgi_link Start "Web Alpine Home Page" "$_wp(serverpath)/session/greeting.tcl" target=_top + +# Internally referenced CGI directory root +cgi_root $_wp(serverpath) +cgi_suffix .tcl + +# have cgi.tcl convert eols in muiltipart/form-data +set _cgi(no_binary_upload) 1 + +proc WPSocketName {sessid} { + global _wp + + return [file join $_wp(sockdir) [format $_wp(sockpat) $sessid]] +} + +proc WPValidId {{sessid {}}} { + global _wp env + + if {[string length $sessid] == 0} { + set created 1 + + # Session Handle: a bit reasonably random number. the format + # is convenient for pubcookie auth'd support + set rnum {} + set rsrc /dev/urandom + set idbytelength [expr {$_wp(sessidlen) * 4}] + if {[file readable $rsrc] && [catch {open $rsrc r} fp] == 0} { + while {1} { + for {set i 0} {$i < $idbytelength} {incr i} { + if {$i && ($i % 4) == 0} { + append rnum "." + } + + if {[catch {read $fp 1} n] == 0} { + binary scan $n c x + set x [expr ($x & 0xff)] + append rnum [format {%02x} $x] + } else { + set rnum {} + break + } + } + + if {[file exists [WPSocketName $rnum]]} { + set rnum {} + } else { + break + } + } + + close $fp + } + + # second choice for random numbers + if {[string length $rnum] == 0} { + expr srand([clock seconds]) + for {set i 0} {$i < $idbytelength} {incr i 4} { + if {$i && ($i % 4) == 0} { + append rnum "." + } + + append rnum [format {%08x} [expr int((100000000 * rand()))]] + } + } + + # generate a session ID + set _wp(sessid) $rnum + } else { + set sessidparts [split $sessid {@}] + switch [llength $sessidparts] { + 1 { + set _wp(sessid) $sessid + } + 2 { + if {[string compare [string tolower [lindex $sessidparts 1]] [string tolower [info hostname]]]} { + regexp {^([a-zA-Z]*://).*} [cgi_root] match proto + error [list redirect "${proto}[lindex $sessidparts 1]:$env(SERVER_PORT)?$env(QUERY_STRING)"] + } else { + set _wp(sessid) [lindex $sessidparts 0] + } + } + default { + error "Malformed Session ID: $sessid" + } + } + } + + set _wp(sockname) [WPSocketName $_wp(sessid)] + + if {[info exists _wp(cumulative)]} { + rename WPCmd WPCmd.orig + rename WPCmdTimed WPCmd + } + + if {[info exists _wp(hostcheck)] && $_wp(hostcheck) == 1 && ![info exists created] + && [catch {WPCmd set wp_client} client] == 0 + && (([info exists env(REMOTE_ADDR)] && [string length $env(REMOTE_ADDR)] && [string compare $client $env(REMOTE_ADDR)]) + || ([info exists env(REMOTE_HOST)] && [string length $env(REMOTE_HOST)] && [string compare $client $env(REMOTE_HOST)]))} { + error "Request from unrecognized client" + } +} + +proc WPAbort {} { + WPCleanup + cgi_exit +} + +proc WPCleanup {} { + global _wp + + if {[info exists _wp(cleanup)]} { + foreach item $_wp(cleanup) { + catch {eval $item} + } + } +} + +proc WPEval {vars cmd} { + global _wp + + if {$_wp(cmdtime) || $_wp(evaltime)} { + set _wp(cumulative) 0 + } + + set _wp(cmd) $cmd + set _wp(vars) [linsert $vars 0 [list sessid "Missing Session ID"]] + + uplevel 1 { + cgi_eval { + if {$_wp(debug) > 1} { + cgi_debug -on + } + + # Session id? + if {[catch {WPGetInputAndID sessid}]} { + return + } + + foreach item $_wp(vars) { + if {[catch {eval WPImport $item} errstr]} { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + return + } + } + + # evaluate the given script + if {[catch {cgi_buffer $_wp(cmd)} result]} { + + reset_cgi_state + + if {[string index $result 0] == "_"} { + switch -- [lindex $result 0] { + _info { + WPInfoPage [lindex $result 1] [font size=+2 [lindex $result 2]] [lindex $result 3] + } + _action { + switch -regexp -- [lindex $result 2] { + "[Ii]nactive [Ss]ession" { + WPInactivePage + } + default { + if {[string length [lindex $result 3]]} { + set remedy [lindex $result 3] + } else { + set remedy " Click your browser's Back button to return to previous page." + } + WPInfoPage "[lindex $result 1] Error" [font size=+2 [lindex $result 2]] \ + "Please report this to the [cgi_link Admin].$remedy" + } + } + } + _redirect { + cgi_http_head { + cgi_redirect [lindex $result 1] + } + + cgi_html { cgi_body {} } + } + _close { + if {[string length [lindex $result 1]] == 0} { + set result "Indeterminate error" + } + + WPInfoPage "Web Alpine Error" [font size=+2 [lindex $result 1]] "Please close this window." + } + default { + if {[string length $result]} { + WPInfoPage "Web Alpine Error" [font size=+2 "Eval Error: $result"] \ + "Please complain to the [cgi_link Admin]. Click Back button to return to previous page." + } else { + WPInfoPage "Web Alpine Error" [font size=+2 "Indeterminate error response"] \ + "Please complain to the [cgi_link Admin] and click Back button to return to previous page." + } + } + } + } else { + if {[regexp {[Ii]nactive [Ss]ession} $result]} { + WPInactivePage + } else { + WPInfoPage "Web Alpine Error" [font size=+2 "Error: $result"] \ + "Please report this to the [cgi_link Admin]. Try clicking your browser's Back button to return to a working page." + } + } + } else { + catch {cgi_puts $result} + } + } + } + + # cleanup here + WPCleanup + + if {[info exists _wp(cumulative)]} { + WPdebug "Cumulative Eval: $_wp(cumulative)" + unset _wp(cumulative) + } +} + +proc WPGetInputAndID {_sessid} { + global _wp + upvar $_sessid sessid + + # Import data and validate it + if {[catch {cgi_input "sessid=8543949466398&"} result]} { + WPInfoPage "Web Alpine Error" [font size=+2 $result] "Please close this window." + error "Cannot get CGI Input" + } + + if {[catch {WPImport sessid "Missing Session ID"} errstr]} { + if {[regexp {.*sessid.*no such.*} $errstr]} { + WPInactivePage [list "Your browser may have failed to send the necessary <i>cookie</i> information. Please verify your browser configuration has cookies enabled."] + } else { + WPInfoPage "Web Alpine Error" [font size=+2 $errstr] "Please close this window." + } + + error "Session ID Failure" + } else { + # initialization here + if {[catch {WPValidId $sessid} result]} { + if {[string compare [lindex $result 0] redirect]} { + WPInfoPage "Web Alpine Error" [font size=+2 "$result"] \ + "Please complain to the [cgi_link Admin] and visit the [cgi_link Start] later." + } else { + cgi_http_head { + cgi_redirect [lindex $result 1] + } + } + + error "Unrecoverable Error" + } elseif {$_wp(sessid) == 0} { + WPInactivePage + error "Inactive Session" + } + + if {[catch {WPCmd set serverroot} serverroot] == 0} { + cgi_root $serverroot + } + } +} + +proc WPCmdEval {args} { + return [eval $args] +} + +proc WPCmd {args} { + global _wp + + return [WPSend $_wp(sockname) $args] +} + +proc WPCmdTimed {args} { + global _wp + + set t [lindex [time {set r [WPSend $_wp(sockname) $args]}] 0] + incr _wp(cumulative) $t + + if {$_wp(cmdtime)} { + WPdebug "time $t : $args" + } + + return $r +} + +proc WPLoadCGIVar {_var} { + upvar $_var var + + if {[catch {cgi_import_as $_var var} result] + && [catch {WPCmd set $_var} var] + && [catch {cgi_import_cookie_as $_var var} result]} { + error [list _action "Import Cookie $_var" $result] + } +} + +proc WPLoadCGIVarAs {_var _varas} { + upvar $_varas varas + + if {[catch {cgi_import_as $_var varas} result] + && [catch {WPCmd set $_var} varas] + && [catch {cgi_import_cookie_as $_var varas} result]} { + set varas "" + } +} + +proc WPImport {valname {errstring ""} {default 0}} { + upvar $valname val + + if {[catch {cgi_import_as $valname val} result]} { + if {[catch {WPCmd set $valname} val]} { + if {[catch {cgi_import_cookie_as $valname val} result]} { + if {[string length $errstring] > 0} { + error "$errstring: $result" + } else { + set val $default + } + } + } + } +} + + +proc WPExportCookie {name value {scope ""}} { + global _wp + + cgi_cookie_set $name=$value "path=[file join / $_wp(urlprefix) $scope]" +} + + +# handle dynamic sizing of images showing thread relationships +proc WPThreadImageLink {t h} { + global _wp + + return "<img src=\"[file join $_wp(imagepath) ${t}.gif]\" border=0 align=top height=${h} width=14>" +} + + +proc WPInactivePage {{reasons ""}} { + set l {} + foreach r $reasons { + append l "<li>$r" + } + + WPInfoPage "Inactive Session" \ + "[font size=+2 "Web Alpine Session No Longer Active"]" \ + "There are several reasons why a session might become inactive.<ul><li>A bookmarked reference to a Web Alpine page.<li>Failed periodic page reload due to browser/system suspension associated with power saving mode, etc.${l}</ul><p>Please visit the [cgi_link Start] to start a new session." +} + +proc WPInfoPage {title exp1 {exp2 ""} {imgurl {}} {exp3 ""}} { + global _wp + + catch { + + cgi_html { + cgi_head { + cgi_title $title + cgi_stylesheet [file join / $_wp(urlprefix) $_wp(pubdir) standard.css] + } + + cgi_body { + cgi_table height="20%" { + cgi_table_row { + cgi_table_data { + cgi_puts [cgi_nbspace] + } + } + } + + cgi_center { + cgi_table border=0 width=500 cellpadding=3 { + cgi_table_row { + cgi_table_data align=center rowspan=3 { + if {[string length $imgurl]} { + cgi_put [cgi_url [cgi_imglink logo] $imgurl] + } else { + cgi_put [cgi_imglink logo] + } + } + + cgi_table_data rowspan=3 { + cgi_put [nbspace] + cgi_put [nbspace] + } + + cgi_table_data { + cgi_puts $exp1 + } + + } + + if {[string length $exp3]} { + cgi_table_row { + cgi_table_data "style=\"border: 1px solid red; background-color: pink\"" { + cgi_puts $exp3 + } + } + } + + if {[string length $exp2]} { + cgi_table_row { + cgi_table_data { + cgi_puts $exp2 + } + } + } + } + } + } + } + } +} + +proc WPimg {image {extension gif}} { + global _wp + + return [file join $_wp(imagepath) ${image}.${extension}] +} + +proc WPCharValue {c} { + scan "$c" %c n + return $n +} + +proc WPPercentQuote {arg {exclude {}}} { + set t "\[^0-9a-zA-Z_${exclude}\]" + if {[regsub -all $t $arg {[format "%%%.2X" [WPCharValue "\\&"]]} subarg]} { + set x [subst $subarg] + return $x + } else { + return $arg + } +} + +proc WPJSQuote {l} { + regsub -all {([\\'])} $l {\\\1} l + return $l +} + +proc WPurl {cmd cmdargs text explanation args} { + global _wp + + lappend urlargs $text + lappend urlargs $cmd + if {[regexp "^java*" $cmd] == 0 && [string first . $cmd] < 0} { + append urlargs ".tcl" + } + + if {[string length $cmdargs]} { + if {[set i [string first "?" $cmdargs]] >= 0} { + append urlargs "[cgi_quote_url [string range $cmdargs 0 [expr {$i - 1}]]]?[cgi_quote_url [string range $cmdargs [incr i] end]]" + } else { + append urlargs "?[cgi_quote_url $cmdargs]" + } + } + + if {$_wp(statushelp)} { + lappend urlargs [WPmouseover $explanation] + lappend urlargs "onMouseOut=window.status=''" + } + + return [eval "cgi_url $urlargs $args"] +} + +proc WPMenuURL {cmd cmdargs text explanation args} { + return [WPurl $cmd $cmdargs $text $explanation class=menubar [join $args]] +} + +proc WPGetTDFontSize {{ih 24}} { + if {$ih <= 20 } {return 12} + if {$ih >= 30 } {return 24} + return [expr {$ih - 8}] +} + +proc WPGetviewFontSize {{ih 24}} { + if {$ih <= 20 } {return 8} + if {$ih >= 30 } {return 13} + return [expr {($ih / 2) - 2}] +} + +proc WPIndexLineHeight {{ih 0}} { + global _wp + + set ih [WPCmd PEInfo indexheight] + if {[string length $ih] == 0 || $ih <= 0} { + set ih $_wp(indexheight) + } + + return [expr {($ih < 20) ? 20 : $ih}] +} + +proc WPStyleSheets {{ih 0}} { + global _wp + + cgi_stylesheet [file join / $_wp(urlprefix) $_wp(pubdir) standard.css] + + if {$ih <= 0} { + set ih [WPIndexLineHeight] + } + + cgi_puts "<style type='text/css'>\nTD { font-size: [WPGetTDFontSize $ih]px }\n.view {font-size: [WPGetviewFontSize $ih]pt }\n</style>" + return $ih +} + +proc WPStdScripts {{ih 0}} { + global _wp + + set ih [WPStyleSheets $ih] + + cgi_script language="JavaScript" src="[file join / $_wp(urlprefix) $_wp(pubdir) standard.js]" {} + cgi_script language="JavaScript1.3" {cgi_put "js_version = '1.3';"} + cgi_javascript { + cgi_puts "function getIndexHeight(){return $ih}" + } +} + +proc WPStdHttpHdrs {{ctype {}} {expires 0}} { + global _wp + + # set date and expires headers the same to prevent caching + # Date: Tue, 15 Nov 1994 08:12:31 GMT + set doctime [clock seconds] + + if {[string length $ctype]} { + cgi_content_type $ctype + } else { + cgi_content_type + } + + cgi_puts "Date: [clock format $doctime -gmt true -format "%a, %d %b %Y %H:%M:%S GMT"]" + if {$expires == 0} { + set _wp(nocache) 1 + cgi_puts "Cache-Control: no-cache" + cgi_puts "Expires: [clock format [expr {$doctime - 31536000}] -gmt true -format "%a, %d %b %Y %H:%M:%S GMT"]" + } elseif {$expires > 0} { + cgi_puts "Expires: [clock format [expr {$doctime + ($expires * 60)}] -gmt true -format "%a, %d %b %Y %H:%M:%S GMT"]" + } +} + +proc WPStdHtmlHdr {pagetitle {pagescript ""} {newmail 0}} { + global _wp + + if {0 && $newmail} { + set nm "* " + } else { + set nm "" + } + + cgi_title "${nm}Web Alpine - $pagetitle" + # cgi_base "href=$_wp(serverpath)/" + if {[info exists _wp(nocache)]} { + cgi_http_equiv Pragma no-cache + } + + # cgi_http_equiv Expires $_wp(docdate) + cgi_meta "name=Web Alpine" content=[clock format [file mtime [info script]] -format "%y%m%d/%H%M"] + if {[catch {WPCmd set nojs} nojs] || $nojs != 1} { + cgi_script type="text/javascript" language="JavaScript" { + cgi_puts "if(self != top) top.location.href = location.href;" + cgi_puts "js_version = '1.0';" + } + } + + cgi_put "<link rel=\"icon\" href=\"[cgi_root]/favicon.ico\" type=\"image/x-icon\">" + cgi_put "<link rel=\"shortcut icon\" href=\"[cgi_root]/favicon.ico\" type=\"image/x-icon\"> " +} + +proc WPHtmlHdrReload {pagescript} { + global _wp + + if {[regexp {\?} $pagescript]} { + set c "&" + } else { + set c "?" + } + + cgi_http_equiv Refresh "$_wp(refresh); url=[cgi_root]/${pagescript}${c}reload=1" +} + +proc WPNewMail {reload {viewpage msgview.tcl}} { + + if {[catch {WPCmd PEMailbox newmail $reload} newmail]} { + return -code error $newmail + } + + set newref "" + + if {[set msgsnew [lindex $newmail 0]] > 0} { + if {[string length $viewpage]} { + if {[string first {?} $viewpage] < 0} { + set delim ? + } else { + set delim & + } + + set newurl "${viewpage}${delim}uid=[lindex $newmail 1]" + } else { + set newurl [lindex $newmail 1] + } + + set newicon "postmark" + set newtext [cgi_quote_html [WPCmd PEMailbox newmailstatmsg]] + + if {[WPCmd PEInfo feature enable-newmail-sound]} { + #set audio sounds/mail_msg.wav + set audio /sounds/ding.wav + if {[isIE]} { + set newsound "<bgsound src=\"$audio\" loop=\"1\" volume=\"100\">" + } else { + set newsound "<embed src=\"$audio\" autostart=\"true\" hidden width=0 height=0 loop=\"false\"><noembed><bgsound src=\"$audio\" loop=\"1\"></noembed>" + } + } else { + set newsound {} + } + + if {0 == [string length $newtext]} { + set newtext "You have $msgsnew new message[WPplural $msgsnew]" + } + + lappend newref [list $newtext $newicon $newurl $newsound] + } + + if {[set deleted [lindex $newmail 2]] > 0} { + set newtext "$deleted Message[WPplural $deleted] removed from folder" + lappend newref [list $newtext "" ""] + } + + foreach statmsg [WPStatusMsgs] { + lappend newref [list $statmsg "" ""] + WPCmd PEInfo statmsg "" + } + + if {!$reload} { + WPCmd PEMailbox newmailreset + } + + return $newref +} + +proc WPStatusMsgs {} { + set retmsgs "" + set lastmsg "" + if {[catch {WPCmd PEInfo statmsgs} statmsgs] == 0} { + foreach statmsg $statmsgs { + if {[string length $statmsg] > 0 && [string compare $statmsg $lastmsg]} { + if {[regexp "^Pinerc \(.+\) NOT saved$" $statmsg]} { + lappend retmsgs "Another Pine/WebPine session may be running. Settings cannot be saved." + } else { + lappend retmsgs $statmsg + } + + set lastmsg $statmsg + } + } + } + + return $retmsgs +} + +proc WPStatusIcon {uid {extension gif} {statbits ""}} { + global _wp + + if {[string length $statbits] == 0} { + set statbits [WPCmd PEMessage $uid statusbits] + } + + if {[string index $statbits 0]} { + append sicon "new" + set alt " N" + set fullalt "New " + } else { + append sicon "read" + set alt " " + set fullalt "Viewed " + } + + if {[string index $statbits 3]} { + append sicon "imp" + set alt "*[string range $alt 1 end]" + set fullaltend ", important message" + } elseif {([string index $statbits 4] || [string index $statbits 5])} { + append sicon "you" + set alt "+[string range $alt 1 end]" + set fullaltend " message to you" + } + + if {[string index $statbits 2]} { + append sicon "ans" + set alt "[string range $alt 0 0]A" + append fullalt ", answered" + } + + if {[string index $statbits 1]} { + append sicon "del" + set alt "[string range $alt 0 0]D" + append fullalt ", deleted" + } + + if {[info exists fullaltend]} { + append fullalt $fullaltend + } else { + append fullalt message + } + + regsub -all { } $alt {\ } alt + + return [list [file join $_wp(imagepath) $_wp(staticondir) ${sicon}.${extension}] i_${uid} $alt $fullalt] +} + +proc WPStatusLabel {uid} { + global _wp + + set statbits [WPCmd PEMessage $uid statusbits] + + if {[string index $statbits 0]} { + set sl new + } else { + set sl read + } + + if {[string index $statbits 3]} { + set sl important + } + + if {[string index $statbits 1]} { + set sl deleted + } + + if {[string index $statbits 2]} { + set sl answered + } + + return $sl +} + +proc WPStatusImg {uid} { + set sicon [WPStatusIcon $uid] + return [cgi_img [lindex $sicon 0] name=[lindex $sicon 1] id=[lindex $sicon 1] height=16 width=42 border=0 alt=[lindex $sicon 3]] +} + +proc WPSessionState {args} { + switch [llength $args] { + 1 - + 2 { + if {[catch {WPCmd PEInfo alpinestate} state_list] == 0} { + array set state_array $state_list + if {[llength $args] == 1} { + return $state_array([lindex $args 0]) + } else { + set state_array([lindex $args 0]) [lindex $args 1] + set state_list [array get state_array] + if {[catch {WPCmd PEInfo alpinestate $state_list} result]} { + error "Can't set session state : $result" + } + } + } else { + error "Can't read session state" + } + } + default { + error "Unknown SessionState Parameters: $args" + } + } +} + +proc WPScriptVersion {tag {inc 0}} { + if {[catch {WPCmd set wp_script_version} sv]} { + set versions($tag) [expr int((1000 * rand()))] + set sv [array get versions] + catch {WPCmd set wp_script_version $sv} + } else { + array set versions $sv + + if {![info exists versions($tag)]} { + set versions($tag) [expr int((1000 * rand()))] + set sv [array get versions] + catch {WPCmd set wp_script_version $sv} + } elseif {$inc} { + incr versions($tag) $inc + set sv [array get versions] + catch {WPCmd set wp_script_version $sv} + } + } + + return $versions($tag) +} + +proc WPplural {count} { + if {$count > 1} { + return "s" + } + + return "" +} + +proc WPcomma {number {dot ,}} { + set x "" + + while {[set n [string length $number]] > 3} { + set x "${dot}[string range $number [incr n -3] end]$x" + set number [string range $number 0 [incr n -1]] + } + + return "$number$x" +} + +proc isIE {} { + global env + + return [expr {[info exists env(HTTP_USER_AGENT)] == 1 && [string first MSIE $env(HTTP_USER_AGENT)] >= 0}] +} + +proc isW3C {} { + global env + + return [expr {[info exists env(HTTP_USER_AGENT)] && (([regexp {^Mozilla/([0-9]).[0-9]+} $env(HTTP_USER_AGENT) match majorversion] && $majorversion > 4) || ([regexp {Opera ([0-9])\.[0-9]+} $env(HTTP_USER_AGENT) match majorversion] && $majorversion > 5))}] +} + +proc WPdebug {args} { + global _wp + + switch [lindex $args 0] { + level { + if {[regexp {^([0-9])+$} [lindex $args 1]]} { + WPSend $_wp(sockname) [subst {PEDebug level [lindex $args 1]}] + } + } + imap { + switch [lindex $args 1] { + on { + WPSend $_wp(sockname) [subst {ePEDebug imap 4}] + } + off { + WPSend $_wp(sockname) [subst {PEDebug imap 0}] + } + } + } + default { + WPSend $_wp(sockname) "PEDebug write [list [list [file tail [info script]]: [lrange $args 0 end]]]" + } + } +} + +proc WPdebugstack {} { + set stack {} + + for {set n [expr {[info level] - 1}]} {$n > 0} {incr n -1} { + append stack "$n) [info level $n]\n" + } + return $stack +} + + +############################################################## +# routines to improve integration with cgi.tcl +############################################################## + +# routine exposing some of cgi.tcl's innards. +# Should be exported by cgi.tcl package. +proc reset_cgi_state {} { + global _cgi + + catch {unset _cgi(http_head_in_progress)} + catch {unset _cgi(http_head_done)} + catch {unset _cgi(http_status_done)} + catch {unset _cgi(html_in_progress)} + catch {unset _cgi(head_in_progress)} + catch {unset _cgi(head_done)} + catch {unset _cgi(html_done)} + catch {unset _cgi(head_suppress_tag)} + catch {unset _cgi(body_in_progress)} + catch {unset _cgi(tag_in_progress)} + catch {unset _cgi(form_in_progress)} + catch {unset _cgi(close_proc)} + + if {[info exists _cgi(returnIndex)]} { + while {[set _cgi(returnIndex)] > 0} { + incr _cgi(returnIndex) -1 + rename cgi_puts "" + rename cgi_puts$_cgi(returnIndex) cgi_puts + } + } +} + +############################################################### +# routines to process (and be called in) html template files +############################################################### + +proc html_readfile {file} { + set x [open $file "r"] + set result [read $x] + close $x + return $result +} + +proc html_eval {_vars_ _this_} { + foreach {_i_ _j_} $_vars_ { + if {$_i_ == "global"} {global $_j_} {set $_i_ $_j_} + } + unset _vars_ _i_ _j_ + return [subst $_this_] +} + +proc html_loop {varslist text} { + set result "" + foreach {vars} $varslist { + append result [html_eval $vars $text] + } + return $result +} diff --git a/web/config/conf.deskmail b/web/config/conf.deskmail new file mode 100644 index 00000000..4f760c75 --- /dev/null +++ b/web/config/conf.deskmail @@ -0,0 +1,55 @@ +# +# Defaults that make more sense in our browser +# oriented world... +# +inbox-path={${WPUSER}.deskmail.washington.edu/tls}inbox + +user-domain=u.washington.edu + +folder-collections="Deskmail Folders" {${WPUSER}.deskmail.washington.edu/tls}mail/[] + +literal-signature="" + +address-book={${WPUSER}.deskmail.washington.edu/tls}remote_addrbook + +feature-list=enable-msg-view-urls, + enable-msg-view-web-hostnames, + enable-msg-view-addresses, + enable-msg-view-attachments, + compose-rejects-unqualified-addrs, + enable-aggregate-command-set, + auto-zoom-after-select, + auto-unselect-after-apply, + fcc-without-attachments, + quell-empty-directories + +normal-background-color=white +normal-foreground-color=black +quote1-foreground-color=000,000,153 +quote1-background-color=white +quote2-foreground-color=051,051,255 +quote2-background-color=white +quote3-foreground-color=051,153,255 +quote3-background-color=white + +rsh-open-timeout=0 +ssh-open-timeout=0 + +index-format=ATT STATUS FROMORTO(18%) SUBJECT(70%) SMARTDATETIME(12%) SIZENARROW PRIORITY + +viewer-hdr-colors=/HDR=Subject/FG=black/BG=yellow, + /HDR=message-id/FG=black/BG=206\x2C206\x2C206, + /HDR=In-reply-to/FG=black/BG=206\x2C206\x2C206 + +wp-indexlines=25 +wp-aggstate=2 + +sort-key=date/reverse + +ldap-servers=people.u.washington.edu "/base=o=University of Washington,c=US/impl=1/rhs=0/ref=0/nosub=0/type=/srch=/time=/size=/cust=/nick=/matr=/catr=/satr=/gatr=" + +addressbook-formats=FULLNAME NICKNAME ADDRESS + +rss-news=http://uwnews.org/apps/uwnews/public/rss.aspx?q=uwnAllCategories&numToShow=10 + +rss-weather=http://www.weather.gov/xml/current_obs/KBFI.rss diff --git a/web/config/pine.conf b/web/config/pine.conf new file mode 100644 index 00000000..e9f4c29c --- /dev/null +++ b/web/config/pine.conf @@ -0,0 +1,52 @@ +# +# Defaults that make more sense in our browser +# oriented world... +# +inbox-path={${IMAP_SERVER}}inbox + +smtp-server=localhost + +user-domain=${IMAP_SERVER_BASE} + +folder-collections="Folders" {${IMAP_SERVER}}mail/[] + +literal-signature="" + +address-book={${IMAP_SERVER}}remote_addrbook + +feature-list=enable-msg-view-urls, + enable-msg-view-web-hostnames, + enable-msg-view-addresses, + enable-msg-view-attachments, + compose-rejects-unqualified-addrs, + enable-aggregate-command-set, + auto-zoom-after-select, + auto-unselect-after-apply, + quell-empty-directories + +normal-background-color=white +normal-foreground-color=black +quote1-foreground-color=000,000,153 +quote1-background-color=white +quote2-foreground-color=051,051,255 +quote2-background-color=white +quote3-foreground-color=051,153,255 +quote3-background-color=white + +rsh-open-timeout=0 +ssh-open-timeout=0 + +index-format=ATT STATUS FROMORTO(18%) SUBJECT(70%) SMARTDATETIME(12%) SIZENARROW PRIORITY + +viewer-hdr-colors=/HDR=Subject/FG=black/BG=yellow, + /HDR=message-id/FG=black/BG=206\x2C206\x2C206, + /HDR=In-reply-to/FG=black/BG=206\x2C206\x2C206 + +sort-key=date + +addressbook-formats=FULLNAME NICKNAME ADDRESS + +rss-news=http://uwnews.org/apps/uwnews/public/rss.aspx?q=uwnAllCategories&numToShow=10 + +rss-weather=http://www.weather.gov/xml/current_obs/KBFI.rss + diff --git a/web/detach b/web/detach new file mode 120000 index 00000000..d1373a3e --- /dev/null +++ b/web/detach @@ -0,0 +1 @@ +/tmp/webpine
\ No newline at end of file diff --git a/web/lib/README b/web/lib/README new file mode 100644 index 00000000..d85c369d --- /dev/null +++ b/web/lib/README @@ -0,0 +1,8 @@ + + + after building alpined, make sure the shared library + libwpcomm1.0.0 is in this directory. once it is + run the pkgcreate.tcl script by hand which will create + the tcl index file pkgIndex.tcl. This only has to be + done once. + diff --git a/web/lib/pkgcreate b/web/lib/pkgcreate new file mode 100755 index 00000000..ee75a10b --- /dev/null +++ b/web/lib/pkgcreate @@ -0,0 +1,3 @@ +#!/usr/bin/tclsh +# allow for earlier versions of Tcl that don't define pkg_mkIndex +catch {pkg_mkIndex . cgi.tcl *.so} diff --git a/web/src/Makefile.am b/web/src/Makefile.am new file mode 100644 index 00000000..5e822d91 --- /dev/null +++ b/web/src/Makefile.am @@ -0,0 +1,22 @@ +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +all: + cd @abs_top_srcdir@/web/src/cgi.tcl-1.10 && ./configure --prefix=@abs_top_srcdir@/web/lib + +install: + cd @abs_top_srcdir@/web/src/alpined.d && make install + cd @abs_top_srcdir@/web/src/cgi.tcl-1.10 && make install SCRIPTDIR=@abs_top_srcdir@/web/lib + cd @abs_top_srcdir@/web/lib && tclsh ./pkgcreate + if test -x pubcookie/wp_uidmapper ; then $(LN) -f pubcookie/wp_uidmapper @abs_top_srcdir@/web/bin ; fi + if test -x pubcookie/wp_tclsh ; then $(LN) -f pubcookie/wp_tclsh @abs_top_srcdir@/web/bin ; fi + if test -x pubcookie/wp_gssapi_proxy ; then $(LN) -f pubcookie/wp_gssapi_proxy @abs_top_srcdir@/web/bin ; fi diff --git a/web/src/Makefile.in b/web/src/Makefile.in new file mode 100644 index 00000000..b208cc32 --- /dev/null +++ b/web/src/Makefile.in @@ -0,0 +1,421 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = web/src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/VERSION \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +C_CLIENT_CFLAGS = @C_CLIENT_CFLAGS@ +C_CLIENT_GCCOPTLEVEL = @C_CLIENT_GCCOPTLEVEL@ +C_CLIENT_LDFLAGS = @C_CLIENT_LDFLAGS@ +C_CLIENT_SPECIALS = @C_CLIENT_SPECIALS@ +C_CLIENT_TARGET = @C_CLIENT_TARGET@ +C_CLIENT_WITH_IPV6 = @C_CLIENT_WITH_IPV6@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISPELLPROG = @ISPELLPROG@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN = @LN@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKE = @MAKE@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NPA_PROG = @NPA_PROG@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PWPROG = @PWPROG@ +RANLIB = @RANLIB@ +REGEX_BUILD = @REGEX_BUILD@ +RM = @RM@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPELLPROG = @SPELLPROG@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEB_BINDIR = @WEB_BINDIR@ +WEB_BUILD = @WEB_BUILD@ +WEB_PUBCOOKIE_BUILD = @WEB_PUBCOOKIE_BUILD@ +WEB_PUBCOOKIE_LIB = @WEB_PUBCOOKIE_LIB@ +WEB_PUBCOOKIE_LINK = @WEB_PUBCOOKIE_LINK@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +acx_pthread_config = @acx_pthread_config@ +alpine_interactive_spellcheck = @alpine_interactive_spellcheck@ +alpine_simple_spellcheck = @alpine_simple_spellcheck@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign web/src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign web/src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +all: + cd @abs_top_srcdir@/web/src/cgi.tcl-1.10 && ./configure --prefix=@abs_top_srcdir@/web/lib + +install: + cd @abs_top_srcdir@/web/src/alpined.d && make install + cd @abs_top_srcdir@/web/src/cgi.tcl-1.10 && make install SCRIPTDIR=@abs_top_srcdir@/web/lib + cd @abs_top_srcdir@/web/lib && tclsh ./pkgcreate + if test -x pubcookie/wp_uidmapper ; then $(LN) -f pubcookie/wp_uidmapper @abs_top_srcdir@/web/bin ; fi + if test -x pubcookie/wp_tclsh ; then $(LN) -f pubcookie/wp_tclsh @abs_top_srcdir@/web/bin ; fi + if test -x pubcookie/wp_gssapi_proxy ; then $(LN) -f pubcookie/wp_gssapi_proxy @abs_top_srcdir@/web/bin ; fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/web/src/alpined.d/Makefile.am b/web/src/alpined.d/Makefile.am new file mode 100644 index 00000000..9101e4fb --- /dev/null +++ b/web/src/alpined.d/Makefile.am @@ -0,0 +1,52 @@ +## Process this file with automake to produce Makefile.in +## Use aclocal -I m4; automake + +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + +# This is because alpined, libwpcomm and friends are +# not intended for system-wide consumption +locbindir = @abs_srcdir@/../../bin +loclibdir = @abs_srcdir@/../../lib + +locbin_PROGRAMS = alpined alpineldap + +alpined_SOURCES = alpined.c busy.c color.c imap.c ldap.c remote.c \ + signal.c debug.c status.c stubs.c \ + alpined.h color.h ldap.h + +alpineldap_SOURCES = alpineldap.c busy.c color.c imap.c ldap.c remote.c \ + signal.c debug.c status.c stubs.c \ + alpined.h color.h ldap.h + +LDADD = local.o \ + @top_srcdir@/pith/libpith.a \ + @top_srcdir@/pith/osdep/libpithosd.a \ + @top_srcdir@/pith/charconv/libpithcc.a \ + @top_srcdir@/c-client/c-client.a \ + $(WEB_PUBCOOKIE_LIB) + +loclib_LTLIBRARIES = libwpcomm.la + +libwpcomm_la_SOURCES = wpcomm.c + +libwpcomm_la_LDFLAGS = -rpath '$(loclibdir)' -version-info 1:0:0 + +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include + +AM_LDFLAGS = `cat @top_srcdir@/c-client/LDFLAGS` + +CLEANFILES = local.c + +local.c: alpineldap.c color.c imap.c ldap.c remote.c signal.c \ + debug.c status.c stubs.c alpined.h color.h ldap.h + echo "char datestamp[]="\"`date`\"";" > local.c + echo "char hoststamp[]="\"`hostname`\"";" >> local.c diff --git a/web/src/alpined.d/Makefile.in b/web/src/alpined.d/Makefile.in new file mode 100644 index 00000000..644fd530 --- /dev/null +++ b/web/src/alpined.d/Makefile.in @@ -0,0 +1,695 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# ======================================================================== +# Copyright 2006 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +locbin_PROGRAMS = alpined$(EXEEXT) alpineldap$(EXEEXT) +subdir = web/src/alpined.d +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/VERSION \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(loclibdir)" "$(DESTDIR)$(locbindir)" +LTLIBRARIES = $(loclib_LTLIBRARIES) +libwpcomm_la_LIBADD = +am_libwpcomm_la_OBJECTS = wpcomm.lo +libwpcomm_la_OBJECTS = $(am_libwpcomm_la_OBJECTS) +libwpcomm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libwpcomm_la_LDFLAGS) $(LDFLAGS) -o $@ +PROGRAMS = $(locbin_PROGRAMS) +am_alpined_OBJECTS = alpined.$(OBJEXT) busy.$(OBJEXT) color.$(OBJEXT) \ + imap.$(OBJEXT) ldap.$(OBJEXT) remote.$(OBJEXT) \ + signal.$(OBJEXT) debug.$(OBJEXT) status.$(OBJEXT) \ + stubs.$(OBJEXT) +alpined_OBJECTS = $(am_alpined_OBJECTS) +alpined_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +alpined_DEPENDENCIES = local.o @top_srcdir@/pith/libpith.a \ + @top_srcdir@/pith/osdep/libpithosd.a \ + @top_srcdir@/pith/charconv/libpithcc.a \ + @top_srcdir@/c-client/c-client.a $(am__DEPENDENCIES_1) +am_alpineldap_OBJECTS = alpineldap.$(OBJEXT) busy.$(OBJEXT) \ + color.$(OBJEXT) imap.$(OBJEXT) ldap.$(OBJEXT) remote.$(OBJEXT) \ + signal.$(OBJEXT) debug.$(OBJEXT) status.$(OBJEXT) \ + stubs.$(OBJEXT) +alpineldap_OBJECTS = $(am_alpineldap_OBJECTS) +alpineldap_LDADD = $(LDADD) +alpineldap_DEPENDENCIES = local.o @top_srcdir@/pith/libpith.a \ + @top_srcdir@/pith/osdep/libpithosd.a \ + @top_srcdir@/pith/charconv/libpithcc.a \ + @top_srcdir@/c-client/c-client.a $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libwpcomm_la_SOURCES) $(alpined_SOURCES) \ + $(alpineldap_SOURCES) +DIST_SOURCES = $(libwpcomm_la_SOURCES) $(alpined_SOURCES) \ + $(alpineldap_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_LDFLAGS = `cat @top_srcdir@/c-client/LDFLAGS` +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +C_CLIENT_CFLAGS = @C_CLIENT_CFLAGS@ +C_CLIENT_GCCOPTLEVEL = @C_CLIENT_GCCOPTLEVEL@ +C_CLIENT_LDFLAGS = @C_CLIENT_LDFLAGS@ +C_CLIENT_SPECIALS = @C_CLIENT_SPECIALS@ +C_CLIENT_TARGET = @C_CLIENT_TARGET@ +C_CLIENT_WITH_IPV6 = @C_CLIENT_WITH_IPV6@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISPELLPROG = @ISPELLPROG@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN = @LN@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKE = @MAKE@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NPA_PROG = @NPA_PROG@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PWPROG = @PWPROG@ +RANLIB = @RANLIB@ +REGEX_BUILD = @REGEX_BUILD@ +RM = @RM@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPELLPROG = @SPELLPROG@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEB_BINDIR = @WEB_BINDIR@ +WEB_BUILD = @WEB_BUILD@ +WEB_PUBCOOKIE_BUILD = @WEB_PUBCOOKIE_BUILD@ +WEB_PUBCOOKIE_LIB = @WEB_PUBCOOKIE_LIB@ +WEB_PUBCOOKIE_LINK = @WEB_PUBCOOKIE_LINK@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +acx_pthread_config = @acx_pthread_config@ +alpine_interactive_spellcheck = @alpine_interactive_spellcheck@ +alpine_simple_spellcheck = @alpine_simple_spellcheck@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# This is because alpined, libwpcomm and friends are +# not intended for system-wide consumption +locbindir = @abs_srcdir@/../../bin +loclibdir = @abs_srcdir@/../../lib +alpined_SOURCES = alpined.c busy.c color.c imap.c ldap.c remote.c \ + signal.c debug.c status.c stubs.c \ + alpined.h color.h ldap.h + +alpineldap_SOURCES = alpineldap.c busy.c color.c imap.c ldap.c remote.c \ + signal.c debug.c status.c stubs.c \ + alpined.h color.h ldap.h + +LDADD = local.o \ + @top_srcdir@/pith/libpith.a \ + @top_srcdir@/pith/osdep/libpithosd.a \ + @top_srcdir@/pith/charconv/libpithcc.a \ + @top_srcdir@/c-client/c-client.a \ + $(WEB_PUBCOOKIE_LIB) + +loclib_LTLIBRARIES = libwpcomm.la +libwpcomm_la_SOURCES = wpcomm.c +libwpcomm_la_LDFLAGS = -rpath '$(loclibdir)' -version-info 1:0:0 +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include +CLEANFILES = local.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign web/src/alpined.d/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign web/src/alpined.d/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-loclibLTLIBRARIES: $(loclib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(loclibdir)" || $(MKDIR_P) "$(DESTDIR)$(loclibdir)" + @list='$(loclib_LTLIBRARIES)'; test -n "$(loclibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(loclibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(loclibdir)"; \ + } + +uninstall-loclibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(loclib_LTLIBRARIES)'; test -n "$(loclibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(loclibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(loclibdir)/$$f"; \ + done + +clean-loclibLTLIBRARIES: + -test -z "$(loclib_LTLIBRARIES)" || rm -f $(loclib_LTLIBRARIES) + @list='$(loclib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libwpcomm.la: $(libwpcomm_la_OBJECTS) $(libwpcomm_la_DEPENDENCIES) + $(libwpcomm_la_LINK) -rpath $(loclibdir) $(libwpcomm_la_OBJECTS) $(libwpcomm_la_LIBADD) $(LIBS) +install-locbinPROGRAMS: $(locbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(locbindir)" || $(MKDIR_P) "$(DESTDIR)$(locbindir)" + @list='$(locbin_PROGRAMS)'; test -n "$(locbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(locbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(locbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-locbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(locbin_PROGRAMS)'; test -n "$(locbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(locbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(locbindir)" && rm -f $$files + +clean-locbinPROGRAMS: + @list='$(locbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +alpined$(EXEEXT): $(alpined_OBJECTS) $(alpined_DEPENDENCIES) + @rm -f alpined$(EXEEXT) + $(LINK) $(alpined_OBJECTS) $(alpined_LDADD) $(LIBS) +alpineldap$(EXEEXT): $(alpineldap_OBJECTS) $(alpineldap_DEPENDENCIES) + @rm -f alpineldap$(EXEEXT) + $(LINK) $(alpineldap_OBJECTS) $(alpineldap_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpined.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpineldap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/busy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stubs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wpcomm.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(loclibdir)" "$(DESTDIR)$(locbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-locbinPROGRAMS \ + clean-loclibLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-locbinPROGRAMS install-loclibLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-locbinPROGRAMS uninstall-loclibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-locbinPROGRAMS clean-loclibLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-locbinPROGRAMS \ + install-loclibLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-locbinPROGRAMS \ + uninstall-loclibLTLIBRARIES + + +local.c: alpineldap.c color.c imap.c ldap.c remote.c signal.c \ + debug.c status.c stubs.c alpined.h color.h ldap.h + echo "char datestamp[]="\"`date`\"";" > local.c + echo "char hoststamp[]="\"`hostname`\"";" >> local.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/web/src/alpined.d/alpined.c b/web/src/alpined.d/alpined.c new file mode 100644 index 00000000..e35ba9e6 --- /dev/null +++ b/web/src/alpined.d/alpined.c @@ -0,0 +1,16404 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: alpined.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* ======================================================================== + Implement alpine TCL interfaces. Execute TCL interfaces + via interpreter reading commands and writing results over + UNIX domain socket. + ======================================================================== */ + + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" +#include "../../../c-client/imap4r1.h" + +#include "../../../pith/osdep/color.h" /* color support library */ +#include "../../../pith/osdep/canaccess.h" +#include "../../../pith/osdep/temp_nam.h" +#include "../../../pith/osdep/collate.h" +#include "../../../pith/osdep/filesize.h" +#include "../../../pith/osdep/writ_dir.h" +#include "../../../pith/osdep/err_desc.h" + +#include "../../../pith/stream.h" +#include "../../../pith/context.h" +#include "../../../pith/state.h" +#include "../../../pith/msgno.h" +#include "../../../pith/debug.h" +#include "../../../pith/init.h" +#include "../../../pith/conf.h" +#include "../../../pith/conftype.h" +#include "../../../pith/detoken.h" +#include "../../../pith/flag.h" +#include "../../../pith/help.h" +#include "../../../pith/remote.h" +#include "../../../pith/status.h" +#include "../../../pith/mailcmd.h" +#include "../../../pith/savetype.h" +#include "../../../pith/save.h" +#include "../../../pith/reply.h" +#include "../../../pith/sort.h" +#include "../../../pith/ldap.h" +#include "../../../pith/addrbook.h" +#include "../../../pith/ablookup.h" +#include "../../../pith/takeaddr.h" +#include "../../../pith/bldaddr.h" +#include "../../../pith/copyaddr.h" +#include "../../../pith/thread.h" +#include "../../../pith/folder.h" +#include "../../../pith/mailview.h" +#include "../../../pith/indxtype.h" +#include "../../../pith/icache.h" +#include "../../../pith/mailindx.h" +#include "../../../pith/mailpart.h" +#include "../../../pith/mimedesc.h" +#include "../../../pith/detach.h" +#include "../../../pith/newmail.h" +#include "../../../pith/charset.h" +#include "../../../pith/util.h" +#include "../../../pith/rfc2231.h" +#include "../../../pith/string.h" +#include "../../../pith/send.h" +#include "../../../pith/options.h" +#include "../../../pith/list.h" +#include "../../../pith/mimetype.h" +#include "../../../pith/mailcap.h" +#include "../../../pith/sequence.h" +#include "../../../pith/smime.h" +#include "../../../pith/url.h" +#include "../../../pith/charconv/utf8.h" + +#include "alpined.h" +#include "color.h" +#include "imap.h" +#include "ldap.h" +#include "debug.h" +#include "stubs.h" + +#include <tcl.h> + + +/* + * Fake screen dimension for word wrap and such + */ +#define FAKE_SCREEN_WIDTH 80 +#define FAKE_SCREEN_LENGTH 24 + +/* + * Aribtrary minimum display width (in characters) + */ +#define MIN_SCREEN_COLS 20 + + +/* + * Maximum number of lines allowed in signatures + */ +#define SIG_MAX_LINES 24 +#define SIG_MAX_COLS 1024 + + +/* + * Number of seconds we'll wait before we assume the client has wondered + * on to more interesting content + */ +#define PE_INPUT_TIMEOUT 1800 + + +/* + * Posting error lenght max + */ +#define WP_MAX_POST_ERROR 128 + + +/* + * AUTH Response Tokens + */ +#define AUTH_EMPTY_STRING "NOPASSWD" +#define AUTH_FAILURE_STRING "BADPASSWD" + +/* + * CERT Response Tokens + */ +#define CERT_QUERY_STRING "CERTQUERY" +#define CERT_FAILURE_STRING "CERTFAIL" + + +/* + * Charset used within alpined and to communicate with alpined + * Note: posting-charset still respected + */ +#define WP_INTERNAL_CHARSET "UTF-8" + + +/* + * Globals referenced throughout pine... + */ +struct pine *ps_global; /* THE global variable! */ + + +/* + * More global state + */ +long gPeITop, gPeICount; + +long gPeInputTimeout = PE_INPUT_TIMEOUT; +long gPEAbandonTimeout = 0; + + +/* + * Authorization issues + */ +int peNoPassword, peCredentialError; +int peCertFailure, peCertQuery; +char peCredentialRequestor[CRED_REQ_SIZE]; + +char *peSocketName; + +char **peTSig; + +CONTEXT_S *config_context_list; + +STRLIST_S *peCertHosts; + +bitmap_t changed_feature_list; +#define F_CH_ON(feature) (bitnset((feature),changed_feature_list)) +#define F_CH_OFF(feature) (!F_CH_ON(feature)) +#define F_CH_TURN_ON(feature) (setbitn((feature),changed_feature_list)) +#define F_CH_TURN_OFF(feature) (clrbitn((feature),changed_feature_list)) +#define F_CH_SET(feature,value) ((value) ? F_CH_TURN_ON((feature)) \ + : F_CH_TURN_OFF((feature))) + + +typedef struct _status_msg { + time_t posted; + unsigned type:3; + unsigned seen:1; + long id; + char *text; + struct _status_msg *next; +} STATMSG_S; + +static STATMSG_S *peStatList; + +typedef struct _composer_attachment { + unsigned file:1; + unsigned body:1; + char *id; + union { + struct { + char *local; + char *remote; + char *type; + char *subtype; + char *description; + long size; + } f; + struct { + BODY *body; + } b; + struct { + long msgno; + char *part; + } msg; + } l; + struct _composer_attachment *next; +} COMPATT_S; + +static COMPATT_S *peCompAttach; + +/* + * Holds data passed + */ +typedef struct _msg_data { + ENVELOPE *outgoing; + METAENV *metaenv; + PINEFIELD *custom; + STORE_S *msgtext; + STRLIST_S *attach; + char *fcc; + int fcc_colid; + int postop_fcc_no_attach; + char *charset; + char *priority; + int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *); + unsigned flowed:1; + unsigned html:1; + unsigned qualified_addrs:1; +} MSG_COL_S; + + +/* + * locally global structure to keep track of various bits of state + * needed to collect filtered output + */ +static struct _embedded_data { + Tcl_Interp *interp; + Tcl_Obj *obj; + STORE_S *store; + long uid; + HANDLE_S *handles; + char inhandle; + ENVELOPE *env; + BODY *body; + struct { + char fg[7]; + char bg[7]; + char fgdef[7]; + char bgdef[7]; + } color; +} peED; + + +/* + * RSS stream cache + */ +typedef struct _rss_cache_s { + char *link; + time_t stale; + int referenced; + RSS_FEED_S *feed; +} RSS_CACHE_S; + +#define RSS_NEWS_CACHE_SIZE 1 +#define RSS_WEATHER_CACHE_SIZE 1 + + +#ifdef ENABLE_LDAP +WPLDAP_S *wpldap_global; +#endif + +/* + * random string generator flags + */ +#define PRS_NONE 0x0000 +#define PRS_LOWER_CASE 0x0001 +#define PRS_UPPER_CASE 0x0002 +#define PRS_MIXED_CASE 0x0004 + +/* + * peSaveWork flag definitions + */ +#define PSW_NONE 0x00 +#define PSW_COPY 0x01 +#define PSW_MOVE 0x02 + +/* + * Message Collector flags + */ +#define PMC_NONE 0x00 +#define PMC_FORCE_QUAL 0x01 +#define PMC_PRSRV_ATT 0x02 + +/* + * length of thread info string + */ +#define WP_MAX_THRD_S 64 + +/* + * static buf size for putenv() if necessary + */ +#define PUTENV_MAX 64 + + + +/*---------------------------------------------------------------------- + General use big buffer. It is used in the following places: + compose_mail: while parsing header of postponed message + append_message2: while writing header into folder + q_status_messageX: while doing printf formatting + addr_book: Used to return expanded address in. (Can only use here + because mm_log doesn't q_status on PARSE errors !) + alpine.c: When address specified on command line + init.c: When expanding variable values + and many many more... + + ----*/ +char tmp_20k_buf[20480]; + + + + +/* Internal prototypes */ +void peReturn(int, char *, char *); +int peWrite(int, char *); +char *peCreateUserContext(Tcl_Interp *, char *, char *, char *); +void peDestroyUserContext(struct pine **); +char *peLoadConfig(struct pine *); +int peCreateStream(Tcl_Interp *, CONTEXT_S *, char *, int); +void peDestroyStream(struct pine *); +void pePrepareForAuthException(void); +char *peAuthException(void); +void peInitVars(struct pine *); +int peSelect(Tcl_Interp *, int, Tcl_Obj **, int); +int peSelectNumber(Tcl_Interp *, int, Tcl_Obj **, int); +int peSelectDate(Tcl_Interp *, int, Tcl_Obj **, int); +int peSelectText(Tcl_Interp *, int, Tcl_Obj **, int); +int peSelectStatus(Tcl_Interp *, int, Tcl_Obj **, int); +char *peSelValTense(Tcl_Obj *); +char *peSelValYear(Tcl_Obj *); +char *peSelValMonth(Tcl_Obj *); +char *peSelValDay(Tcl_Obj *); +int peSelValCase(Tcl_Obj *); +int peSelValField(Tcl_Obj *); +int peSelValFlag(Tcl_Obj *); +int peSelected(Tcl_Interp *, int, Tcl_Obj **, int); +int peSelectError(Tcl_Interp *, char *); +int peApply(Tcl_Interp *, int, Tcl_Obj **); +char *peApplyFlag(MAILSTREAM *, MSGNO_S *, char, int, long *); +int peApplyError(Tcl_Interp *, char *); +int peIndexFormat(Tcl_Interp *); +int peAppendIndexParts(Tcl_Interp *, imapuid_t, Tcl_Obj *, int *); +int peAppendIndexColor(Tcl_Interp *, imapuid_t, Tcl_Obj *, int *); +int peMessageStatusBits(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +char *peMsgStatBitString(struct pine *, MAILSTREAM *, MSGNO_S *, long, long, long, int *); +Tcl_Obj *peMsgStatNameList(Tcl_Interp *, struct pine *, MAILSTREAM *, MSGNO_S *, long, long, long, int *); +int peNewMailResult(Tcl_Interp *); +int peMessageSize(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageDate(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageSubject(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageFromAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageToAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageCcAddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageField(Tcl_Interp *, imapuid_t, char *); +int peMessageStatus(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageCharset(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageBounce(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageSpamNotice(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +char *peSendSpamReport(long, char *, char *, char *); +int peMsgnoFromUID(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageHeader(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +void peFormatEnvelope(MAILSTREAM *, long, char *, ENVELOPE *, gf_io_t, long, char *, int); +void peFormatEnvelopeAddress(MAILSTREAM *, long, char *, char *, ADDRESS *, int, char *, gf_io_t); +void peFormatEnvelopeNewsgroups(char *, char *, int, gf_io_t); +void peFormatEnvelopeText(char *, char *); +int peMessageAttachments(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessageBody(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMessagePartFromCID(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peLocateBodyByCID(char *, char *, BODY *); +char *peColorStr(char *, char *); +int peInterpWritec(int); +int peInterpFlush(void); +int peNullWritec(int); +void peGetMimeTyping(BODY *, Tcl_Obj **, Tcl_Obj **, Tcl_Obj **, Tcl_Obj **); +int peGetFlag(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peIsFlagged(MAILSTREAM *, imapuid_t, char *); +int peSetFlag(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMsgSelect(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peReplyHeaders(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peAppListF(Tcl_Interp *, Tcl_Obj *, char *, ...); +void pePatAppendID(Tcl_Interp *, Tcl_Obj *, PAT_S *); +void pePatAppendPattern(Tcl_Interp *, Tcl_Obj *, PAT_S *); +char *pePatStatStr(int); +int peReplyText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peSoStrToList(Tcl_Interp *, Tcl_Obj *, STORE_S *); +int peForwardHeaders(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peForwardText(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peDetach(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peAttachInfo(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peSaveDefault(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peSaveWork(Tcl_Interp *, imapuid_t, int, Tcl_Obj **, long); +int peSave(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peCopy(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peMove(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peGotoDefault(Tcl_Interp *, imapuid_t, Tcl_Obj **); +int peTakeaddr(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peTakeFrom(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peAddSuggestedContactInfo(Tcl_Interp *, Tcl_Obj *, ADDRESS *); +int peReplyQuote(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +long peMessageNumber(imapuid_t); +long peSequenceNumber(imapuid_t); +int peMsgCollector(Tcl_Interp *, int, Tcl_Obj **, + int (*)(METAENV *, BODY *, char *, CONTEXT_S **, char *), long); +int peMsgCollected(Tcl_Interp *, MSG_COL_S *, char *, long); +void peMsgSetParm(PARAMETER **, char *, char *); +Tcl_Obj *peMsgAttachCollector(Tcl_Interp *, BODY *); +int peFccAppend(Tcl_Interp *, Tcl_Obj *, char *, int); +int peDoPost(METAENV *, BODY *, char *, CONTEXT_S **, char *); +int peDoPostpone(METAENV *, BODY *, char *, CONTEXT_S **, char *); +int peWriteSig (Tcl_Interp *, char *, Tcl_Obj **); +int peInitAddrbooks(Tcl_Interp *, int); +int peRuleStatVal(char *, int *); +int peRuleSet(Tcl_Interp *, Tcl_Obj **); +int peAppendCurrentSort(Tcl_Interp *interp); +int peAppendDefaultSort(Tcl_Interp *interp); +#if 0 +ADDRESS *peAEToAddress(AdrBk_Entry *); +char *peAEFcc(AdrBk_Entry *); +#endif +NAMEVAL_S *sort_key_rules(int); +NAMEVAL_S *wp_indexheight_rules(int); +PINEFIELD *peCustomHdrs(void); +STATMSG_S *sml_newmsg(int, char *); +char *sml_getmsg(void); +char **sml_getmsgs(void); +void sml_seen(void); +#ifdef ENABLE_LDAP +int peLdapQueryResults(Tcl_Interp *); +int peLdapStrlist(Tcl_Interp *, Tcl_Obj *, char **); +int init_ldap_pname(struct pine *); +#endif /* ENABLE_LDAP */ +char *strqchr(char *, int, int *, int); +Tcl_Obj *wp_prune_folders(CONTEXT_S *, char *, int, char *, + unsigned, int *, int, Tcl_Interp *); +int hex_colorstr(char *, char *); +int hexval(char); +int ascii_colorstr(char *, char *); +COMPATT_S *peNewAttach(void); +void peFreeAttach(COMPATT_S **); +COMPATT_S *peGetAttachID(char *); +char *peFileAttachID(char *, char *, char *, char *, char *, int); +char *peBodyAttachID(BODY *); +void peBodyMoveContents(BODY *, BODY *); +int peClearAttachID(char *); +char *peRandomString(char *, int, int); +void ms_init(STRING *, void *, unsigned long); +char ms_next(STRING *); +void ms_setpos(STRING *, unsigned long); +long peAppendMsg(MAILSTREAM *, void *, char **, char **, STRING **); +int remote_pinerc_failure(void); +char *peWebAlpinePrefix(void); +void peNewMailAnnounce(MAILSTREAM *, long, long); +int peMessageNeedPassphrase(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); +int peRssReturnFeed(Tcl_Interp *, char *, char *); +int peRssPackageFeed(Tcl_Interp *, RSS_FEED_S *); +RSS_FEED_S *peRssFeed(Tcl_Interp *, char *, char *); +RSS_FEED_S *peRssFetch(Tcl_Interp *, char *); +void peRssComponentFree(char **,char **,char **,char **,char **,char **); +void peRssClearCacheEntry(RSS_CACHE_S *); + + +/* Prototypes for Tcl-exported methods */ +int PEInit(Tcl_Interp *interp, char *); +void PEExitCleanup(ClientData); +int PEInfoCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEConfigCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEDebugCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PESessionCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEMailboxCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEThreadCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEMessageCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEFolderCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEComposeCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEPostponeCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEAddressCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PEClistCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PELdapCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +int PERssCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); + +/* Append package */ +typedef struct append_pkg { + MAILSTREAM *stream; /* source stream */ + unsigned long msgno; /* current message number */ + unsigned long msgmax; /* maximum message number */ + char *flags; /* current flags */ + char *date; /* message internal date */ + STRING *message; /* stringstruct of message */ +} APPEND_PKG; + +STRINGDRIVER mstring = { + ms_init, /* initialize string structure */ + ms_next, /* get next byte in string structure */ + ms_setpos /* set position in string structure */ +}; + + +/*---------------------------------------------------------------------- + main routine -- entry point + + Args: argv, argc -- The command line arguments + + + Setup c-client drivers and dive into TCL interpreter engine + + ----*/ + +int +main(int argc, char *argv[]) +{ + int ev = 1, s, cs, n, co, o, l, bl = 256, argerr; + char *buf, sname[256]; + struct sockaddr_un name; + Tcl_Interp *interp; +#if PUBCOOKIE + extern AUTHENTICATOR auth_gss_proxy; +#endif + + srandom(getpid() + time(0)); + + /*---------------------------------------------------------------------- + Initialize c-client + ----------------------------------------------------------------------*/ + + /* + * NO LOCAL DRIVERS ALLOWED + * For this to change pintecld *MUST* be running under the user's UID and + * and signal.[ch] need to get fixed to handle KOD rather than change + * the debug level + */ + mail_link (&imapdriver); /* link in the imap driver */ + mail_link (&unixdriver); /* link in the unix driver */ + mail_link (&dummydriver); /* link in the dummy driver */ + + /* link authentication drivers */ +#if PUBCOOKIE + auth_link (&auth_gss_proxy); /* pubcoookie proxy authenticator */ +#endif + auth_link (&auth_md5); /* link in the md5 authenticator */ + auth_link (&auth_pla); + auth_link (&auth_log); /* link in the log authenticator */ + ssl_onceonlyinit (); + mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 2); + +#if PUBCOOKIE + /* if REMOTE_USER set, use it as username */ + if(buf = getenv("REMOTE_USER")) + env_init(buf, "/tmp"); +#endif + + if(!mail_parameters(NULL, DISABLE_DRIVER, "unix")){ + fprintf(stderr, "Can't disable unix driver"); + exit(1); + } + + /* + * Set network timeouts so we don't hang forever + * The open timeout can be pretty short since we're + * just opening tcp connection. The read timeout needs + * to be longer because the response to some actions can + * take awhile. Hopefully this is well within httpd's + * cgi timeout threshold. + */ + mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 30); + mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 60); + + /*---------------------------------------------------------------------- + Initialize pith library + ----------------------------------------------------------------------*/ + pith_opt_remote_pinerc_failure = remote_pinerc_failure; + pith_opt_user_agent_prefix = peWebAlpinePrefix; + pith_opt_newmail_announce = peNewMailAnnounce; + + setup_for_index_index_screen(); + + + /*---------------------------------------------------------------------- + Parse arguments + ----------------------------------------------------------------------*/ + debug = 0; + for(argerr = 0; !argerr && ((n = getopt(argc,argv,"d")) != -1); ) { + switch(n) { + case 'd' : debug++; break; + case '?' : argerr = 1; break; + } + } + + if(argerr || optind != argc){ + char *p = strrchr(argv[0],'/'); + fprintf(stderr, "Usage: %s [-d]\n", p ? p + 1 : argv[0]); + exit(1); + } + + /*---------------------------------------------------------------------- + Hop into the Tcl processing loop + ----------------------------------------------------------------------*/ + + buf = (char *) fs_get(bl * sizeof(char)); + + if(fgets(sname, 255, stdin) && *sname){ + if(sname[l = strlen(sname) - 1] == '\n') + sname[l] = '\0'; + + if((s = socket(AF_UNIX, SOCK_STREAM, 0)) != -1){ + + name.sun_family = AF_UNIX; + strcpy(name.sun_path, peSocketName = sname); + l = sizeof(name); + + if(bind(s, (struct sockaddr *) &name, l) == 0){ + if(listen(s, 5) == 0){ + /* + * after the groundwork's done, go into the background. + * the fork saves the caller from invoking us in the background + * which introduces a timing race between the first client + * request arrival and our being prepared to accept it. + */ + if(debug < 10){ + switch(fork()){ + case -1 : /* error */ + perror("fork"); + exit(1); + + case 0 : /* child */ + close(0); /* disassociate */ + close(1); + close(2); + setpgrp(0, 0); + break; + + default : /* parent */ + exit(0); + } + } + + debug_init(); + dprint((SYSDBG_INFO, "started")); + + interp = Tcl_CreateInterp(); + + PEInit(interp, sname); + + while(1){ + struct timeval tv; + fd_set rfd; + + FD_ZERO(&rfd); + FD_SET(s, &rfd); + tv.tv_sec = (gPEAbandonTimeout) ? gPEAbandonTimeout : gPeInputTimeout; + tv.tv_usec = 0; + if((n = select(s+1, &rfd, 0, 0, &tv)) > 0){ + socklen_t ll = l; + + gPEAbandonTimeout = 0; + + if((cs = accept(s, (struct sockaddr *) &name, &ll)) == -1){ + dprint((SYSDBG_ERR, "accept failure: %s", + error_description(errno))); + break; + } + + dprint((5, "accept success: %d", cs)); + + /* + * tcl commands are prefixed with a number representing + * the length of the command string and a newline character. + * the characters representing the length and the newline + * are not included in the command line length calculation. + */ + o = co = 0; + while((n = read(cs, buf + o, bl - o - 1)) > 0){ + o += n; + if(!co){ + int i, x = 0; + + for(i = 0; i < o; i++) + if(buf[i] == '\n'){ + co = ++i; + l = x + co; + if(bl < l + 1){ + bl = l + 1; + fs_resize((void **) &buf, bl * sizeof(char)); + } + + break; + } + else + x = (x * 10) + (buf[i] - '0'); + } + + if(o && o == l) + break; + } + + if(n == 0){ + dprint((SYSDBG_ERR, "read EOF")); + } + else if(n < 0){ + dprint((SYSDBG_ERR, "read failure: %s", error_description(errno))); + } + else{ + buf[o] = '\0'; + + /* Log every Eval if somebody *really* wants to see it. */ + if(debug > 6){ + char dbuf[5120]; + int dlim = (debug >= 9) ? 256 : 5120 - 32; + + snprintf(dbuf, sizeof(dbuf), "Tcl_Eval(%.*s)", dlim, &buf[co]); + + /* But DON'T log any clear-text credentials */ + if(dbuf[9] == 'P' + && dbuf[10] == 'E' + && dbuf[11] == 'S' + && !strncmp(dbuf + 12, "ession creds ", 13)){ + char *p; + + for(p = &dbuf[25]; *p; p++) + *p = 'X'; + } + + dprint((1, dbuf)); + } + + switch(Tcl_Eval(interp, &buf[co])){ + case TCL_OK : peReturn(cs, "OK", interp->result); break; + case TCL_ERROR : peReturn(cs, "ERROR", interp->result); break; + case TCL_BREAK : peReturn(cs, "BREAK", interp->result); break; + case TCL_RETURN : peReturn(cs, "RETURN", interp->result); break; + default : peReturn(cs, "BOGUS", "eval returned unexpected value"); break; + } + } + + close(cs); + } + else if(errno != EINTR){ + if(n < 0){ + dprint((SYSDBG_ALERT, "select failure: %s", error_description(errno))); + } + else{ + dprint((SYSDBG_INFO, "timeout after %d seconds", tv.tv_sec)); + } + + Tcl_Exit(0); + + /* Tcl_Exit should never return. Getting here is an error. */ + dprint((SYSDBG_ERR, "Tcl_Exit failure")); + } + } + } + else + perror("listen"); + } + else + perror("bind"); + + close(s); + unlink(sname); + } + else + perror("socket"); + } + else + fprintf(stderr, "Can't read socket name\n"); + + exit(ev); +} + + +/* + * peReturn - common routine to return TCL result + */ +void +peReturn(int sock, char *status, char *result) +{ + if(peWrite(sock, status)) + if(peWrite(sock, "\n")) + peWrite(sock, result); +} + +/* + * peWrite - write all the given string on the given socket + */ +int +peWrite(int sock, char *s) +{ + int i, n; + + for(i = 0, n = strlen(s); n; n = n - i) + if((i = write(sock, s + i, n)) < 0){ + dprint((SYSDBG_ERR, "write: %s", error_description(errno))); + return(0); + } + + return(1); +} + +/* + * PEInit - Initialize exported TCL functions + */ +int +PEInit(Tcl_Interp *interp, char *sname) +{ + dprint((2, "PEInit: %s", sname)); + + if(Tcl_Init(interp) == TCL_ERROR) { + return(TCL_ERROR); + } + + Tcl_CreateObjCommand(interp, "PEInfo", PEInfoCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEConfig", PEConfigCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEDebug", PEDebugCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PESession", PESessionCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEFolder", PEFolderCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEMailbox", PEMailboxCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEThread", PEThreadCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEMessage", PEMessageCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PECompose", PEComposeCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEPostpone", PEPostponeCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEAddress", PEAddressCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PEClist", PEClistCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PELdap", PELdapCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateObjCommand(interp, "PERss", PERssCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + Tcl_CreateExitHandler(PEExitCleanup, sname); + +#ifdef ENABLE_LDAP + wpldap_global = (WPLDAP_S *)fs_get(sizeof(WPLDAP_S)); + wpldap_global->query_no = 0; + wpldap_global->ldap_search_list = NULL; +#endif /* ENABLE_LDAP */ + + return(TCL_OK); +} + + +void +PEExitCleanup(ClientData clientData) +{ + dprint((4, "PEExitCleanup")); + + if(ps_global){ + /* destroy any open stream */ + peDestroyStream(ps_global); + + /* destroy user context */ + peDestroyUserContext(&ps_global); + } + +#ifdef ENABLE_LDAP + if(wpldap_global){ + if(wpldap_global->ldap_search_list) + free_wpldapres(wpldap_global->ldap_search_list); + fs_give((void **)&wpldap_global); + } +#endif /* ENABLE_LDAP */ + + if((char *) clientData) + unlink((char *) clientData); + + peFreeAttach(&peCompAttach); + + dprint((SYSDBG_INFO, "finished")); +} + + +/* + * PEInfoCmd - export various bits of alpine state + */ +int +PEInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err = "Unknown PEInfo request"; + + dprint((2, "PEInfoCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else{ + char *s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(!strcmp(s1, "colorset")){ + char *varname, *fghex, *bghex; + char tvname[256], asciicolor[256]; + struct variable *vtmp; + Tcl_Obj **cObj; + int cObjc; + SPEC_COLOR_S *hcolors, *thc; + + if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){ + Tcl_SetResult(interp, "colorset: can't read variable name", TCL_STATIC); + return(TCL_ERROR); + } + + if(!strcmp(varname, "viewer-hdr-colors")){ + char *newhdr = NULL, *newpat = NULL, *utype; + int hindex, i; + + if(objc < 5){ + Tcl_SetResult(interp, "colorset: too few view-hdr args", TCL_STATIC); + return(TCL_ERROR); + } + + hcolors = spec_colors_from_varlist(ps_global->VAR_VIEW_HDR_COLORS, 0); + if(!(utype = Tcl_GetStringFromObj(objv[3], NULL))){ + Tcl_SetResult(interp, "colorset: can't read operation", TCL_STATIC); + return(TCL_ERROR); + } + + if(!strcmp(utype, "delete")){ + if(!hcolors){ + Tcl_SetResult(interp, "colorset: no viewer-hdrs to delete", TCL_STATIC); + return(TCL_ERROR); + } + + if(Tcl_GetIntFromObj(interp, objv[4], &hindex) == TCL_ERROR){ + Tcl_SetResult(interp, "colorset: can't read index", TCL_STATIC); + return(TCL_ERROR); + } + + if(hindex == 0){ + thc = hcolors; + hcolors = hcolors->next; + thc->next = NULL; + free_spec_colors(&thc); + } + else{ + /* zero based */ + for(thc = hcolors, i = 1; thc && i < hindex; thc = thc->next, i++) + ; + + if(thc && thc->next){ + SPEC_COLOR_S *thc2 = thc->next; + + thc->next = thc2->next; + thc2->next = NULL; + free_spec_colors(&thc2); + } + else{ + Tcl_SetResult(interp, "colorset: invalid index", TCL_STATIC); + return(TCL_ERROR); + } + } + } + else if(!strcmp(utype, "add")){ + if(objc != 6){ + Tcl_SetResult(interp, "colorset: wrong number of view-hdr add args", TCL_STATIC); + return(TCL_ERROR); + } + + if(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) != TCL_OK) + return (TCL_ERROR); + + if(cObjc != 2){ + Tcl_SetResult(interp, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + + newhdr = Tcl_GetStringFromObj(cObj[0], NULL); + newpat = Tcl_GetStringFromObj(cObj[1], NULL); + if(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) != TCL_OK) + return (TCL_ERROR); + + if(cObjc != 2){ + Tcl_SetResult(interp, "colorset: wrong number of colors for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + + fghex = Tcl_GetStringFromObj(cObj[0], NULL); + bghex = Tcl_GetStringFromObj(cObj[1], NULL); + if(newhdr && newpat && fghex && bghex){ + SPEC_COLOR_S **hcp; + + for(hcp = &hcolors; *hcp != NULL; hcp = &(*hcp)->next) + ; + + *hcp = (SPEC_COLOR_S *)fs_get(sizeof(SPEC_COLOR_S)); + (*hcp)->inherit = 0; + (*hcp)->spec = cpystr(newhdr); + (*hcp)->fg = cpystr((ascii_colorstr(asciicolor, fghex) == 0) ? asciicolor : "black"); + (*hcp)->bg = cpystr((ascii_colorstr(asciicolor, bghex) == 0) ? asciicolor : "white"); + + if(newpat && *newpat) + (*hcp)->val = string_to_pattern(newpat); + else + (*hcp)->val = NULL; + + (*hcp)->next = NULL; + } + else{ + Tcl_SetResult(interp, "colorset: invalid args for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + } + else if(!strcmp(utype, "update")){ + if(objc != 6){ + Tcl_SetResult(interp, "colorset: wrong number of view-hdr update args", TCL_STATIC); + return(TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) == TCL_OK + && cObjc == 3 + && Tcl_GetIntFromObj(interp, cObj[0], &hindex) == TCL_OK + && (newhdr = Tcl_GetStringFromObj(cObj[1], NULL)) + && (newpat = Tcl_GetStringFromObj(cObj[2], NULL)))){ + Tcl_SetResult(interp, "colorset: view-hdr update can't read index or header", TCL_STATIC); + return (TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) == TCL_OK + && cObjc == 2 + && (fghex = Tcl_GetStringFromObj(cObj[0], NULL)) + && (bghex = Tcl_GetStringFromObj(cObj[1], NULL)))){ + Tcl_SetResult(interp, "colorset: view-hdr update can't read colors", TCL_STATIC); + return (TCL_ERROR); + } + + for(thc = hcolors, i = 0; thc && i < hindex; thc = thc->next, i++) + ; + + if(!thc){ + Tcl_SetResult(interp, "colorset: view-hdr update invalid index", TCL_STATIC); + return (TCL_ERROR); + } + + if(thc->spec) + fs_give((void **)&thc->spec); + + thc->spec = cpystr(newhdr); + if(ascii_colorstr(asciicolor, fghex) == 0) { + if(thc->fg) + fs_give((void **)&thc->fg); + + thc->fg = cpystr(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid foreground color value %.100s", fghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, bghex) == 0) { + if(thc->bg) + fs_give((void **)&thc->bg); + + thc->bg = cpystr(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(thc->val) + fs_give((void **)&thc->val); + + if(newpat && *newpat){ + thc->val = string_to_pattern(newpat); + } + } + else{ + Tcl_SetResult(interp, "colorset: unknown operation", TCL_STATIC); + return(TCL_ERROR); + } + + vtmp = &ps_global->vars[V_VIEW_HDR_COLORS]; + for(i = 0; vtmp->main_user_val.l && vtmp->main_user_val.l[i]; i++) + fs_give((void **)&vtmp->main_user_val.l[i]); + + if(vtmp->main_user_val.l) + fs_give((void **)&vtmp->main_user_val.l); + + vtmp->main_user_val.l = varlist_from_spec_colors(hcolors); + set_current_val(vtmp, FALSE, FALSE); + free_spec_colors(&hcolors); + return(TCL_OK); + } + else { + if(objc != 4){ + Tcl_SetResult(interp, "colorset: Wrong number of args", TCL_STATIC); + return(TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[3], &cObjc, &cObj) == TCL_OK + && cObjc == 2 + && (fghex = Tcl_GetStringFromObj(cObj[0], NULL)) + && (bghex = Tcl_GetStringFromObj(cObj[1], NULL)))){ + Tcl_SetResult(interp, "colorset: Problem reading fore/back ground colors", TCL_STATIC); + return (TCL_ERROR); + } + + snprintf(tvname, sizeof(tvname), "%.200s-foreground-color", varname); + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name || vtmp->is_list){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, fghex) == 0) { + if(vtmp->main_user_val.p) + fs_give((void **)&vtmp->main_user_val.p); + + vtmp->main_user_val.p = cpystr(asciicolor); + set_current_val(vtmp, FALSE, FALSE); + if(!strucmp(varname, "normal")) + pico_set_fg_color(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid color value %.100s", fghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color"); + vtmp++; + if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name) + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name || vtmp->is_list){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, bghex) == 0) { + if(vtmp->main_user_val.p) + fs_give((void **)&vtmp->main_user_val.p); + + vtmp->main_user_val.p = cpystr(asciicolor); + set_current_val(vtmp, FALSE, FALSE); + if(!strucmp(varname, "normal")) + pico_set_bg_color(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + Tcl_SetResult(interp, "1", TCL_STATIC); + return(TCL_OK); + } + } + else if(!strcmp(s1, "lappend")){ + if(objc >= 4){ + Tcl_Obj *dObj; + int i; + + if((dObj = Tcl_ObjGetVar2(interp, objv[2], NULL, TCL_LEAVE_ERR_MSG)) != NULL){ + for(i = 3; i < objc; i++) + if(Tcl_ListObjAppendElement(interp, dObj, objv[i]) != TCL_OK) + return(TCL_ERROR); + + if(i == objc){ + return(TCL_OK); + } + } + else + err = "PEInfo lappend: Unknown list name"; + } + else + err = "PEInfo lappend: Too few args"; + } + else if(objc == 2){ + if(!strcmp(s1, "version")){ + char buf[256]; + + /* + * CMD: version + * + * Returns: string representing Pine version + * engine built on + */ + Tcl_SetResult(interp, ALPINE_VERSION, TCL_STATIC); + return(TCL_OK); + } + else if(!strcmp(s1, "revision")){ + char buf[16]; + + /* + * CMD: revision + * + * Returns: string representing Pine SVN revision + * engine built on + */ + + Tcl_SetResult(interp, get_alpine_revision_number(buf, sizeof(buf)), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "key")){ + static char key[64]; + + if(!key[0]) + peRandomString(key,32,PRS_UPPER_CASE); + + Tcl_SetResult(interp, key, TCL_STATIC); + return(TCL_OK); + } + else if(!strcmp(s1, "indexheight")){ + Tcl_SetResult(interp, ps_global->VAR_WP_INDEXHEIGHT ? + ps_global->VAR_WP_INDEXHEIGHT : "", TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "indexlines")){ + Tcl_SetResult(interp, ps_global->VAR_WP_INDEXLINES ? + ps_global->VAR_WP_INDEXLINES : "0", TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "aggtabstate")){ + Tcl_SetResult(interp, ps_global->VAR_WP_AGGSTATE ? + ps_global->VAR_WP_AGGSTATE : "0", TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "alpinestate")){ + char *wps, *p, *q; + + if((wps = ps_global->VAR_WP_STATE) != NULL){ + wps = p = q = cpystr(wps); + do + if(*q == '\\' && *(q+1) == '$') + q++; + while((*p++ = *q++) != '\0'); + } + + Tcl_SetResult(interp, wps ? wps : "", TCL_VOLATILE); + + if(wps) + fs_give((void **) &wps); + + return(TCL_OK); + } + else if(!strcmp(s1, "foreground")){ + char *color; + + if(!((color = pico_get_last_fg_color()) + && (color = color_to_asciirgb(color)) + && (color = peColorStr(color,tmp_20k_buf)))) + color = "000000"; + + Tcl_SetResult(interp, color, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "background")){ + char *color; + + if(!((color = pico_get_last_bg_color()) + && (color = color_to_asciirgb(color)) + && (color = peColorStr(color,tmp_20k_buf)))) + color = "FFFFFF"; + + Tcl_SetResult(interp, color, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "flaglist")){ + int i; + char *p; + Tcl_Obj *itemObj; + + /* + * BUG: This list should get merged with the static list in "cmd_flag" + * and exported via some function similar to "feature_list()" + */ + static char *flag_list[] = { + "Important", "New", "Answered", "Deleted", NULL + }; + + /* + * CMD: flaglist + * + * Returns: list of FLAGS available for setting + */ + for(i = 0; (p = flag_list[i]); i++) + if((itemObj = Tcl_NewStringObj(p, -1)) != NULL){ + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + itemObj) != TCL_OK) + ; + } + + return(TCL_OK); + } + else if(!strcmp(s1, "featurelist")){ + int i; + char *curfeature, *s; + FEATURE_S *feature; + Tcl_Obj *itemObj, *secObj = NULL, *resObj = NULL; + + /* + * CMD: featurelist + * + * Returns: list of FEATURES available for setting + */ + for(i = 0, curfeature = NULL; (feature = feature_list(i)); i++) + if((s = feature_list_section(feature)) != NULL){ + if(!curfeature || strucmp(s, curfeature)){ + if(resObj) { + Tcl_ListObjAppendElement(interp, + secObj, + resObj); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + secObj); + } + + secObj = Tcl_NewListObj(0, NULL); + resObj = Tcl_NewListObj(0, NULL); + if(Tcl_ListObjAppendElement(interp, + secObj, + Tcl_NewStringObj(s,-1)) != TCL_OK) + ; + + curfeature = s; + } + + if((itemObj = Tcl_NewStringObj(feature->name, -1)) != NULL){ + if(Tcl_ListObjAppendElement(interp, + resObj, + itemObj) != TCL_OK) + ; + } + } + + if(resObj){ + Tcl_ListObjAppendElement(interp, secObj, resObj); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), secObj); + } + + return(TCL_OK); + } + else if(!strcmp(s1, "featuresettings")){ + int i; + FEATURE_S *feature; + Tcl_Obj *itemObj; + + /* + * CMD: featuresettings + * + * Returns: list of FEATURES currently SET + */ + for(i = 0; (feature = feature_list(i)); i++) + if(feature_list_section(feature)){ + if(F_ON(feature->id, ps_global)){ + if((itemObj = Tcl_NewStringObj(feature->name, -1)) != NULL){ + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + itemObj) != TCL_OK) + ; + } + } + } + + return(TCL_OK); + } + else if(!strcmp(s1, "signature")){ + char *sig; + + if((ps_global->VAR_LITERAL_SIG + || (ps_global->VAR_SIGNATURE_FILE + && IS_REMOTE(ps_global->VAR_SIGNATURE_FILE))) + && (sig = detoken(NULL, NULL, 2, 0, 1, NULL, NULL))){ + char *p, *q; + + for(p = sig; (q = strindex(p, '\n')); p = q + 1) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, q - p)); + + if(*p) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, -1)); + + fs_give((void **) &sig); + } + else + Tcl_SetResult(interp, "", TCL_STATIC); + + return(TCL_OK); + } + else if(!strcmp(s1, "rawsig")){ + char *err = NULL, *sig = NULL, *p, *q; + + if(ps_global->VAR_LITERAL_SIG){ + char *err = NULL; + char **apval; + + if(ps_global->restricted){ + err = "Alpine demo can't change config file"; + } + else{ + /* BUG: no "exceptions file" support */ + if((apval = APVAL(&ps_global->vars[V_LITERAL_SIG], Main)) != NULL){ + sig = (char *) fs_get((strlen(*apval ? *apval : "") + 1) * sizeof(char)); + sig[0] = '\0'; + cstring_to_string(*apval, sig); + } + else + err = "Problem accessing configuration"; + } + } + else if(!IS_REMOTE(ps_global->VAR_SIGNATURE_FILE)) + snprintf(err = tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s", + ps_global->VAR_SIGNATURE_FILE ? ps_global->VAR_SIGNATURE_FILE : "<null>"); + else if(!(sig = simple_read_remote_file(ps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE))) + err = "Can't read remote pinerc"; + + if(err){ + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); + } + + for(p = sig; (q = strindex(p, '\n')); p = q + 1) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, q - p)); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, -1)); + fs_give((void **) &sig); + return(TCL_OK); + } + else if(!strcmp(s1, "statmsg")){ + char *s = sml_getmsg(); + /* BUG: can this be removed? */ + + Tcl_SetResult(interp, s ? s : "", TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "statmsgs")){ + char **s = sml_getmsgs(); + char **tmps, *lmsg = NULL; + + for(tmps = s; tmps && *tmps; lmsg = *tmps++) + if(!lmsg || strcmp(lmsg, *tmps)) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(*tmps, -1)); + + fs_give((void **)&s); + return(TCL_OK); + } + else if(!strcmp(s1, "saveconf")){ + write_pinerc(ps_global, Main, WRP_NOUSER); + return(TCL_OK); + } + else if(!strucmp(s1, "sort")){ + return(peAppendDefaultSort(interp)); + } + else if(!strcmp(s1, "ldapenabled")){ + /* + * CMD: ldapenabled + * + * Returns: 1 if enabled 0 if not + */ +#ifdef ENABLE_LDAP + Tcl_SetResult(interp, "1", TCL_VOLATILE); +#else + Tcl_SetResult(interp, "0", TCL_VOLATILE); +#endif + + return(TCL_OK); + } + else if(!strcmp(s1, "prunecheck")){ + time_t now; + struct tm *tm_now; + char tmp[50]; + + if(!check_prune_time(&now, &tm_now)){ + Tcl_SetResult(interp, "0", TCL_VOLATILE); + return(TCL_OK); + } else { + /* + * We're going to reset the last-time-pruned variable + * so that it asks a maximum of 1 time per month. + * PROs: Annoying-factor is at its lowest + * Can go ahead and move folders right away if + * pruning-rule is automatically set to do so + * CONs: Annoying-factor is at its lowest, if it's set + * later then we can ensure that the questions + * actually get answered or it will keep asking + */ + ps_global->last_expire_year = tm_now->tm_year; + ps_global->last_expire_month = tm_now->tm_mon; + snprintf(tmp, sizeof(tmp), "%d.%d", ps_global->last_expire_year, + ps_global->last_expire_month + 1); + set_variable(V_LAST_TIME_PRUNE_QUESTION, tmp, 0, 1, Main); + + Tcl_SetResult(interp, "1", TCL_VOLATILE); + } + return(TCL_OK); + } + else if(!strcmp(s1, "prunetime")){ + time_t now; + struct tm *tm_now; + CONTEXT_S *prune_cntxt; + Tcl_Obj *retObj = NULL; + int cur_month, ok = 1; + char **p; + static int moved_fldrs = 0; + + now = time((time_t *)0); + tm_now = localtime(&now); + cur_month = (1900 + tm_now->tm_year) * 12 + tm_now->tm_mon; + + if(!(prune_cntxt = default_save_context(ps_global->context_list))) + prune_cntxt = ps_global->context_list; + + if(prune_cntxt){ + if(ps_global->VAR_DEFAULT_FCC && *ps_global->VAR_DEFAULT_FCC + && context_isambig(ps_global->VAR_DEFAULT_FCC)) + if((retObj = wp_prune_folders(prune_cntxt, + ps_global->VAR_DEFAULT_FCC, + cur_month, "sent", + ps_global->pruning_rule, &ok, + moved_fldrs, interp)) != NULL) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + retObj); + + if(ok && ps_global->VAR_READ_MESSAGE_FOLDER + && *ps_global->VAR_READ_MESSAGE_FOLDER + && context_isambig(ps_global->VAR_READ_MESSAGE_FOLDER)) + if((retObj = wp_prune_folders(prune_cntxt, + ps_global->VAR_READ_MESSAGE_FOLDER, + cur_month, "read", + ps_global->pruning_rule, &ok, + moved_fldrs, interp)) != NULL) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + retObj); + if(ok && (p = ps_global->VAR_PRUNED_FOLDERS)){ + for(; ok && *p; p++) + if(**p && context_isambig(*p)) + if((retObj = wp_prune_folders(prune_cntxt, + *p, cur_month, "", + ps_global->pruning_rule, &ok, + moved_fldrs, interp)) != NULL) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + retObj); + } + } + moved_fldrs = 1; + return(TCL_OK); + } + else if(!strcmp(s1, "authrequestor")){ + Tcl_SetResult(interp, peCredentialRequestor, TCL_STATIC); + return(TCL_OK); + } + else if(!strcmp(s1, "noop")){ + /* tickle the imap server too */ + if(ps_global->mail_stream) + pine_mail_ping(ps_global->mail_stream); + + Tcl_SetResult(interp, "NOOP", TCL_STATIC); + return(TCL_OK); + } + else if(!strcmp(s1, "inputtimeout")){ + Tcl_SetResult(interp, int2string(get_input_timeout()), TCL_VOLATILE); + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(s1, "feature")){ + char *featurename; + int i, isset = 0; + FEATURE_S *feature; + + /* + * CMD: feature + * + * ARGS: featurename - + * + * Returns: 1 if named feature set, 0 otherwise + * + */ + if((featurename = Tcl_GetStringFromObj(objv[2], NULL)) != NULL) + for(i = 0; (feature = feature_list(i)); i++) + if(!strucmp(featurename, feature->name)){ + isset = F_ON(feature->id, ps_global); + break; + } + + Tcl_SetResult(interp, int2string(isset), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "colorget")){ + char *varname; + char tvname[256], hexcolor[256]; + struct variable *vtmp; + if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){ + return(TCL_ERROR); + } + if(strcmp("viewer-hdr-colors", varname) == 0){ + SPEC_COLOR_S *hcolors, *thc; + Tcl_Obj *resObj; + char hexcolor[256], *tstr = NULL; + + hcolors = spec_colors_from_varlist(ps_global->VAR_VIEW_HDR_COLORS, 0); + for(thc = hcolors; thc; thc = thc->next){ + resObj = Tcl_NewListObj(0,NULL); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(thc->spec, -1)); + hex_colorstr(hexcolor, thc->fg); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(hexcolor, -1)); + hex_colorstr(hexcolor, thc->bg); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(hexcolor, -1)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(thc->val + ? tstr = pattern_to_string(thc->val) + : "", -1)); + if(tstr) fs_give((void **)&tstr); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + resObj); + } + fs_give((void **)&hcolors); + return(TCL_OK); + } + else { + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-foreground-color"); + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++); + if(!vtmp->name) return(TCL_ERROR); + if(vtmp->is_list) return(TCL_ERROR); + if(!vtmp->current_val.p) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("", -1)); + else{ + hex_colorstr(hexcolor, vtmp->current_val.p); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(hexcolor, -1)); + } + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color"); + vtmp++; + if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name) + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name) return(TCL_ERROR); + if(vtmp->is_list) return(TCL_ERROR); + if(!vtmp->current_val.p) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("", -1)); + else{ + hex_colorstr(hexcolor, vtmp->current_val.p); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(hexcolor, -1)); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "varget")){ + struct variable *vtmp; + Tcl_Obj *itemObj, *resObj, *secObj; + char *vallist, *varname, tmperrmsg[256]; + int i; + NAMEVAL_S *tmpnv; + + /* + * CMD: varget + * + * Returns: get the values for the requested variable + * + * The list returned follows this general form: + * + * char *; variable name + * char **; list of set values + * char *; display type (listbox, text, textarea, ...) + * char **; list of possible values + * (so far this is only useful for listboxes) + */ + if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){ + Tcl_SetResult(interp, "Can't Tcl_GetStringFromObj", + TCL_VOLATILE); + return(TCL_ERROR); + } + + for(vtmp = ps_global->vars; + vtmp->name && strucmp(vtmp->name, varname); + vtmp++) + ; + + if(!vtmp->name){ + snprintf(tmperrmsg, sizeof(tmperrmsg), "Can't find variable named %s", + strlen(varname) < 200 ? varname : ""); + Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE); + return(TCL_ERROR); + } + if((itemObj = Tcl_NewStringObj(vtmp->name, -1)) != NULL){ + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + itemObj); + resObj = Tcl_NewListObj(0, NULL); + if(vtmp->is_list){ + for(i = 0 ; vtmp->current_val.l && vtmp->current_val.l[i]; i++){ + vallist = vtmp->current_val.l[i]; + if(*(vallist)) + itemObj = Tcl_NewStringObj(vallist, -1); + else + itemObj = Tcl_NewStringObj("", -1); + Tcl_ListObjAppendElement(interp, resObj, itemObj); + } + } + else{ + itemObj = Tcl_NewStringObj(vtmp->current_val.p ? + vtmp->current_val.p : "", -1); + Tcl_ListObjAppendElement(interp, resObj, itemObj); + } + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + resObj); + secObj = Tcl_NewListObj(0, NULL); + if(vtmp->is_list) + itemObj = Tcl_NewStringObj("textarea", -1); + else{ + NAMEVAL_S *(*tmpf)(int); + switch(vtmp - ps_global->vars){ + case V_SAVED_MSG_NAME_RULE: + tmpf = save_msg_rules; + break; + case V_FCC_RULE: + tmpf = fcc_rules; + break; + case V_SORT_KEY: + tmpf = sort_key_rules; + break; + case V_AB_SORT_RULE: + tmpf = ab_sort_rules; + break; + case V_FLD_SORT_RULE: + tmpf = fld_sort_rules; + break; + case V_GOTO_DEFAULT_RULE: + tmpf = goto_rules; + break; + case V_INCOMING_STARTUP: + tmpf = incoming_startup_rules; + break; + case V_PRUNING_RULE: + tmpf = pruning_rules; + break; + case V_WP_INDEXHEIGHT: + tmpf = wp_indexheight_rules; + break; + default: + tmpf = NULL; + break; + } + if(tmpf){ + for(i = 0; (tmpnv = (tmpf)(i)); i++){ + itemObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, itemObj, + Tcl_NewStringObj(tmpnv->name, -1)); + if(tmpnv->shortname) + Tcl_ListObjAppendElement(interp, itemObj, + Tcl_NewStringObj(tmpnv->shortname, -1)); + Tcl_ListObjAppendElement(interp, secObj, itemObj); + } + itemObj = Tcl_NewStringObj("listbox", -1); + } + else + itemObj = Tcl_NewStringObj("text", -1); + } + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + itemObj); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + secObj); + } + return(TCL_OK); + } + else if(!strcmp(s1, "rawsig")){ + + if(ps_global->VAR_LITERAL_SIG){ + char *cstring_version, *sig, *line; + int i, nSig; + Tcl_Obj **objSig; + + tmp_20k_buf[0] = '\0'; + Tcl_ListObjGetElements(interp, objv[2], &nSig, &objSig); + for(i = 0; i < nSig && i < SIG_MAX_LINES; i++) + if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL) + snprintf(tmp_20k_buf + strlen(tmp_20k_buf), SIZEOF_20KBUF - strlen(tmp_20k_buf), "%.*s\n", SIG_MAX_COLS, line); + + sig = cpystr(tmp_20k_buf); + + if((cstring_version = string_to_cstring(sig)) != NULL){ + set_variable(V_LITERAL_SIG, cstring_version, 0, 0, Main); + fs_give((void **)&cstring_version); + } + + fs_give((void **) &sig); + return(TCL_OK); + } + else + return(peWriteSig(interp, ps_global->VAR_SIGNATURE_FILE, + &((Tcl_Obj **)objv)[2])); + } + else if(!strcmp(s1, "statmsg")){ + char *msg; + + /* + * CMD: statmsg + * + * ARGS: msg - text to set + * + * Returns: nothing, but with global status message + * buf set to given msg + * + */ + if((msg = Tcl_GetStringFromObj(objv[2], NULL)) != NULL) + sml_addmsg(0, msg); + + return(TCL_OK); + } + else if(!strcmp(s1, "mode")){ + char *mode; + int rv = 0; + + /* + * CMD: mode + * + * ARGS: <mode> + * + * Returns: return value of given binary mode + * + */ + if((mode = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(!strcmp(mode, "full-header-mode")) + rv = ps_global->full_header; + } + + Tcl_SetResult(interp, int2string(rv), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "indexlines")){ + int n; + char *p; + + if(Tcl_GetIntFromObj(interp, objv[2], &n) == TCL_OK){ + set_variable(V_WP_INDEXLINES, p = int2string(n), 0, 0, Main); + Tcl_SetResult(interp, p, TCL_VOLATILE); + } + return(TCL_OK); + } + else if(!strcmp(s1, "aggtabstate")){ + int n; + char *p; + + if(Tcl_GetIntFromObj(interp, objv[2], &n) == TCL_OK){ + set_variable(V_WP_AGGSTATE, p = int2string(n), 0, 0, Main); + Tcl_SetResult(interp, p, TCL_VOLATILE); + } + return(TCL_OK); + } + else if(!strcmp(s1, "alpinestate")){ + char *wps, *p, *q, *twps = NULL; + int dollars = 0; + + if((wps = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + for(p = wps; *p; p++) + if(*p == '$') + dollars++; + + if(dollars){ + twps = (char *) fs_get(((p - wps) + (dollars + 1)) * sizeof(char)); + p = wps; + q = twps; + do{ + if(*p == '$') + *q++ = '\\'; + } + while((*q++ = *p++) != '\0'); + } + + set_variable(V_WP_STATE, twps ? twps : wps, 0, 1, Main); + Tcl_SetResult(interp, wps, TCL_VOLATILE); + if(twps) + fs_give((void **) &twps); + } + + return(TCL_OK); + } + else if(!strcmp(s1, "set")){ + Tcl_Obj *rObj; + + if((rObj = Tcl_ObjGetVar2(interp, objv[2], NULL, TCL_LEAVE_ERR_MSG)) != NULL){ + Tcl_SetObjResult(interp, rObj); + return(TCL_OK); + } + else + return(TCL_ERROR); + } + else if(!strcmp(s1, "unset")){ + char *varname; + + return((varname = Tcl_GetStringFromObj(objv[2], NULL)) ? Tcl_UnsetVar2(interp, varname, NULL, TCL_LEAVE_ERR_MSG) : TCL_ERROR); + } + } + else if(objc == 4){ + if(!strcmp(s1, "feature")){ + char *featurename; + int i, set, wasset = 0; + FEATURE_S *feature; + + /* + * CMD: feature + * + * ARGS: featurename - + * value - new value to assign flag + * + * Returns: 1 if named feature set, 0 otherwise + * + */ + if((featurename = Tcl_GetStringFromObj(objv[2], NULL)) + && Tcl_GetIntFromObj(interp, objv[3], &set) != TCL_ERROR) + for(i = 0; (feature = feature_list(i)); i++) + if(!strucmp(featurename, feature->name)){ + if(set != F_ON(feature->id, ps_global)){ + toggle_feature(ps_global, + &ps_global->vars[V_FEATURE_LIST], + feature, TRUE, Main); + + if(ps_global->prc) + ps_global->prc->outstanding_pinerc_changes = 1; + } + + break; + } + + Tcl_SetResult(interp, int2string(wasset), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(s1, "help")){ + HelpType text; + int i; + char **help_text, **ptext, *helpname, tmperrmsg[256], + *function; + Tcl_Obj *itemObj; + struct variable *vtmp; + FEATURE_S *ftmp; + + if(!(helpname = Tcl_GetStringFromObj(objv[2], NULL))){ + Tcl_SetResult(interp, + "Can't Tcl_GetStringFromObj for helpname", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(!(function = Tcl_GetStringFromObj(objv[3], NULL))){ + Tcl_SetResult(interp, + "Can't Tcl_GetStringFromObj for function", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(strucmp(function, "plain") == 0){ + if((text = help_name2section(helpname, strlen(helpname))) + == NO_HELP) + return(TCL_OK); + } + else if(strucmp(function, "variable") == 0){ + for(vtmp = ps_global->vars; + vtmp->name && strucmp(vtmp->name, helpname); + vtmp++); + if(!vtmp->name) { + snprintf(tmperrmsg, sizeof(tmperrmsg), "Can't find variable named %s", + strlen(helpname) < 200 ? helpname : ""); + Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE); + return(TCL_ERROR); + } + text = config_help(vtmp - ps_global->vars, 0); + if(text == NO_HELP) + return(TCL_OK); + } + else if(strucmp(function, "feature") == 0){ + for(i = 0; (ftmp = feature_list(i)); i++){ + if(!strucmp(helpname, ftmp->name)){ + text = ftmp->help; + break; + } + } + if(!ftmp || text == NO_HELP){ + return(TCL_OK); + } + } + else { + snprintf(tmperrmsg, sizeof(tmperrmsg), "Invalid function: %s", + strlen(helpname) < 200 ? function : ""); + Tcl_SetResult(interp, tmperrmsg, TCL_VOLATILE); + return(TCL_ERROR); + } + /* assumption here is that HelpType is char ** */ + help_text = text; + for(ptext = help_text; *ptext; ptext++){ + itemObj = Tcl_NewStringObj(*ptext, -1); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + itemObj); + } + return(TCL_OK); + } + else if(!strcmp(s1, "varset")){ + char *varname, **tmpstrlist, *line; + struct variable *vtmp; + Tcl_Obj **objVal; + int i, numlistvals = 0, strlistpos; + + if((varname = Tcl_GetStringFromObj(objv[2], NULL)) + && (Tcl_ListObjGetElements(interp, objv[3], &numlistvals, + &objVal) == TCL_OK)){ + for(vtmp = ps_global->vars; + vtmp->name && strucmp(vtmp->name, varname); + vtmp++); + if(!vtmp->name){ + return(TCL_ERROR); + } + else{ + /* found the variable */ + if(vtmp->is_list){ + for(i = 0; vtmp->main_user_val.l && vtmp->main_user_val.l[i]; i++) + fs_give((void **)&vtmp->main_user_val.l[i]); + if(vtmp->main_user_val.l) + fs_give((void **)&vtmp->main_user_val.l); + if(numlistvals > 0){ + tmpstrlist = (char **)fs_get((numlistvals + 1) * sizeof(char *)); + for(i = 0, strlistpos = 0; i < numlistvals; i++){ + if((line = Tcl_GetStringFromObj(objVal[i], 0)) != NULL){ + removing_leading_and_trailing_white_space(line); + if(*line) + tmpstrlist[strlistpos++] = cpystr(line); + } + } + tmpstrlist[strlistpos] = NULL; + vtmp->main_user_val.l = (char **)fs_get((strlistpos+1) * + sizeof(char *)); + for(i = 0; i <= strlistpos; i++) + vtmp->main_user_val.l[i] = tmpstrlist[i]; + fs_give((void **)&tmpstrlist); + } + set_current_val(vtmp, FALSE, FALSE); + return(TCL_OK); + } + else{ + if((line = Tcl_GetStringFromObj(objVal[0], NULL)) != NULL){ + if(strucmp(vtmp->name, "reply-indent-string")) + removing_leading_and_trailing_white_space(line); + if(vtmp->main_user_val.p) + fs_give((void **)&vtmp->main_user_val.p); + if(*line) + vtmp->main_user_val.p = cpystr(line); + set_current_val(vtmp, FALSE, FALSE); + return(TCL_OK); + } + } + } + } + return(TCL_ERROR); + } + else if(!strcmp(s1, "mode")){ + char *mode; + int value, rv = 0; + + /* + * CMD: mode + * + * ARGS: <mode> <value> + * + * Returns: old value of binary mode we were told to set + * + */ + if((mode = Tcl_GetStringFromObj(objv[2], NULL)) + && Tcl_GetIntFromObj(interp, objv[3], &value) != TCL_ERROR){ + if(!strcmp(mode, "full-header-mode")){ + rv = ps_global->full_header; + ps_global->full_header = value; + } + } + + Tcl_SetResult(interp, int2string(rv), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "set")){ + Tcl_Obj *rObj; + + if((rObj = Tcl_ObjSetVar2(interp, objv[2], NULL, objv[3], TCL_LEAVE_ERR_MSG)) != NULL){ + Tcl_SetObjResult(interp, rObj); + return(TCL_OK); + } + else + return(TCL_ERROR); + } + } + else + err = "PEInfo: Too many arguments"; + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +/* + * PEConfigCmd - edit various alpine config variables + * + * The goal here is to remember what's changed, but not write to pinerc + * until the user's actually chosen to save. + */ +int +PEConfigCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err = "Unknown PEConfig request"; + char *s1; + + dprint((2, "PEConfigCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); + } + s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(!strcmp(s1, "colorset")){ + char *varname, *fghex, *bghex; + char tvname[256], asciicolor[256]; + struct variable *vtmp; + Tcl_Obj **cObj; + int cObjc; + SPEC_COLOR_S *hcolors, *thc; + + if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){ + Tcl_SetResult(interp, "colorset: can't read variable name", TCL_STATIC); + return(TCL_ERROR); + } + + if(!strcmp(varname, "viewer-hdr-colors")){ + char *newhdr = NULL, *newpat = NULL, *utype; + int hindex, i; + + if(objc < 5){ + Tcl_SetResult(interp, "colorset: too few view-hdr args", TCL_STATIC); + return(TCL_ERROR); + } + + if(ps_global->vars[V_VIEW_HDR_COLORS].is_changed_val) + hcolors = spec_colors_from_varlist(ps_global->vars[V_VIEW_HDR_COLORS].changed_val.l, 0); + else + hcolors = spec_colors_from_varlist(ps_global->VAR_VIEW_HDR_COLORS, 0); + if(!(utype = Tcl_GetStringFromObj(objv[3], NULL))){ + Tcl_SetResult(interp, "colorset: can't read operation", TCL_STATIC); + return(TCL_ERROR); + } + + if(!strcmp(utype, "delete")){ + if(!hcolors){ + Tcl_SetResult(interp, "colorset: no viewer-hdrs to delete", TCL_STATIC); + return(TCL_ERROR); + } + + if(Tcl_GetIntFromObj(interp, objv[4], &hindex) == TCL_ERROR){ + Tcl_SetResult(interp, "colorset: can't read index", TCL_STATIC); + return(TCL_ERROR); + } + + if(hindex == 0){ + thc = hcolors; + hcolors = hcolors->next; + thc->next = NULL; + free_spec_colors(&thc); + } + else{ + /* zero based */ + for(thc = hcolors, i = 1; thc && i < hindex; thc = thc->next, i++) + ; + + if(thc && thc->next){ + SPEC_COLOR_S *thc2 = thc->next; + + thc->next = thc2->next; + thc2->next = NULL; + free_spec_colors(&thc2); + } + else{ + Tcl_SetResult(interp, "colorset: invalid index", TCL_STATIC); + return(TCL_ERROR); + } + } + } + else if(!strcmp(utype, "add")){ + if(objc != 6){ + Tcl_SetResult(interp, "colorset: wrong number of view-hdr add args", TCL_STATIC); + return(TCL_ERROR); + } + + if(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) != TCL_OK) + return (TCL_ERROR); + + if(cObjc != 2){ + Tcl_SetResult(interp, "colorset: wrong number of hdrs for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + + newhdr = Tcl_GetStringFromObj(cObj[0], NULL); + newpat = Tcl_GetStringFromObj(cObj[1], NULL); + if(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) != TCL_OK) + return (TCL_ERROR); + + if(cObjc != 2){ + Tcl_SetResult(interp, "colorset: wrong number of colors for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + + fghex = Tcl_GetStringFromObj(cObj[0], NULL); + bghex = Tcl_GetStringFromObj(cObj[1], NULL); + if(newhdr && newpat && fghex && bghex){ + SPEC_COLOR_S **hcp; + + for(hcp = &hcolors; *hcp != NULL; hcp = &(*hcp)->next) + ; + + *hcp = (SPEC_COLOR_S *)fs_get(sizeof(SPEC_COLOR_S)); + (*hcp)->inherit = 0; + (*hcp)->spec = cpystr(newhdr); + (*hcp)->fg = cpystr((ascii_colorstr(asciicolor, fghex) == 0) ? asciicolor : "black"); + (*hcp)->bg = cpystr((ascii_colorstr(asciicolor, bghex) == 0) ? asciicolor : "white"); + + if(newpat && *newpat) + (*hcp)->val = string_to_pattern(newpat); + else + (*hcp)->val = NULL; + + (*hcp)->next = NULL; + } + else{ + Tcl_SetResult(interp, "colorset: invalid args for view-hdr add", TCL_STATIC); + return(TCL_ERROR); + } + } + else if(!strcmp(utype, "update")){ + if(objc != 6){ + Tcl_SetResult(interp, "colorset: wrong number of view-hdr update args", TCL_STATIC); + return(TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[4], &cObjc, &cObj) == TCL_OK + && cObjc == 3 + && Tcl_GetIntFromObj(interp, cObj[0], &hindex) == TCL_OK + && (newhdr = Tcl_GetStringFromObj(cObj[1], NULL)) + && (newpat = Tcl_GetStringFromObj(cObj[2], NULL)))){ + Tcl_SetResult(interp, "colorset: view-hdr update can't read index or header", TCL_STATIC); + return (TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[5], &cObjc, &cObj) == TCL_OK + && cObjc == 2 + && (fghex = Tcl_GetStringFromObj(cObj[0], NULL)) + && (bghex = Tcl_GetStringFromObj(cObj[1], NULL)))){ + Tcl_SetResult(interp, "colorset: view-hdr update can't read colors", TCL_STATIC); + return (TCL_ERROR); + } + + for(thc = hcolors, i = 0; thc && i < hindex; thc = thc->next, i++) + ; + + if(!thc){ + Tcl_SetResult(interp, "colorset: view-hdr update invalid index", TCL_STATIC); + return (TCL_ERROR); + } + + if(thc->spec) + fs_give((void **)&thc->spec); + + thc->spec = cpystr(newhdr); + if(ascii_colorstr(asciicolor, fghex) == 0) { + if(thc->fg) + fs_give((void **)&thc->fg); + + thc->fg = cpystr(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid foreground color value %.100s", fghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, bghex) == 0) { + if(thc->bg) + fs_give((void **)&thc->bg); + + thc->bg = cpystr(asciicolor); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(thc->val) + fs_give((void **)&thc->val); + + if(newpat && *newpat){ + thc->val = string_to_pattern(newpat); + } + } + else{ + Tcl_SetResult(interp, "colorset: unknown operation", TCL_STATIC); + return(TCL_ERROR); + } + + vtmp = &ps_global->vars[V_VIEW_HDR_COLORS]; + for(i = 0; vtmp->changed_val.l && vtmp->changed_val.l[i]; i++) + fs_give((void **)&vtmp->changed_val.l[i]); + + if(vtmp->changed_val.l) + fs_give((void **)&vtmp->changed_val.l); + + vtmp->changed_val.l = varlist_from_spec_colors(hcolors); + vtmp->is_changed_val = 1; + free_spec_colors(&hcolors); + return(TCL_OK); + } + else { + if(objc != 4){ + Tcl_SetResult(interp, "colorset: Wrong number of args", TCL_STATIC); + return(TCL_ERROR); + } + + if(!(Tcl_ListObjGetElements(interp, objv[3], &cObjc, &cObj) == TCL_OK + && cObjc == 2 + && (fghex = Tcl_GetStringFromObj(cObj[0], NULL)) + && (bghex = Tcl_GetStringFromObj(cObj[1], NULL)))){ + Tcl_SetResult(interp, "colorset: Problem reading fore/back ground colors", TCL_STATIC); + return (TCL_ERROR); + } + + snprintf(tvname, sizeof(tvname), "%.200s-foreground-color", varname); + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name || vtmp->is_list){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, fghex) == 0) { + if(vtmp->changed_val.p) + fs_give((void **)&vtmp->changed_val.p); + + vtmp->changed_val.p = cpystr(asciicolor); + vtmp->is_changed_val = 1; + + /* We need to handle this in the actual config setting + * if(!strucmp(varname, "normal")) + * pico_set_fg_color(asciicolor); + */ + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid color value %.100s", fghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color"); + vtmp++; + if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name) + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name || vtmp->is_list){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background var %.100s", varname); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(ascii_colorstr(asciicolor, bghex) == 0) { + if(vtmp->changed_val.p) + fs_give((void **)&vtmp->changed_val.p); + + vtmp->changed_val.p = cpystr(asciicolor); + vtmp->is_changed_val = 1; + /* again, we need to handle this when we actually set the variable + * if(!strucmp(varname, "normal")) + * pico_set_bg_color(asciicolor); + */ + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "colorset: invalid background color value %.100s", bghex); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + Tcl_SetResult(interp, "1", TCL_STATIC); + return(TCL_OK); + } + } + else if(!strcmp(s1, "ruleset")){ + return(peRuleSet(interp, &((Tcl_Obj **)objv)[2])); + } + else if(objc == 2){ + if(!strcmp(s1, "featuresettings")){ + struct variable *vtmp; + int i; + FEATURE_S *feature; + + vtmp = &ps_global->vars[V_FEATURE_LIST]; + for(i = 0; (feature = feature_list(i)); i++) + if(feature_list_section(feature)){ + if(vtmp->is_changed_val ? F_CH_ON(feature->id) + : F_ON(feature->id, ps_global)){ + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(feature->name, -1)); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "rawsig")){ + char *err = NULL, *sig = NULL, *p, *q; + int i; + struct variable *vtmp; + + vtmp = &ps_global->vars[V_LITERAL_SIG]; + if(vtmp->is_changed_val ? vtmp->changed_val.p + : ps_global->VAR_LITERAL_SIG){ + char *err = NULL; + char **apval; + + if(ps_global->restricted){ + err = "Alpine demo can't change config file"; + } + else{ + /* BUG: no "exceptions file" support */ + apval = (vtmp->is_changed_val ? &vtmp->changed_val.p + : APVAL(&ps_global->vars[V_LITERAL_SIG], Main)); + if(apval){ + sig = (char *) fs_get((strlen(*apval ? *apval : "") + 1) * sizeof(char)); + sig[0] = '\0'; + cstring_to_string(*apval, sig); + } + else + err = "Problem accessing configuration"; + } + } + else if((vtmp = &ps_global->vars[V_SIGNATURE_FILE]) + && !IS_REMOTE(vtmp->is_changed_val ? vtmp->changed_val.p + : ps_global->VAR_SIGNATURE_FILE)) + snprintf(err = tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s", + vtmp->is_changed_val ? (vtmp->changed_val.p + ? vtmp->changed_val.p : "<null>") + : (ps_global->VAR_SIGNATURE_FILE + ? ps_global->VAR_SIGNATURE_FILE : "<null>")); + else if(!(peTSig || (sig = simple_read_remote_file(vtmp->is_changed_val + ? vtmp->changed_val.p + : ps_global->VAR_SIGNATURE_FILE, REMOTE_SIG_SUBTYPE)))) + err = "Can't read remote pinerc"; + + if(err){ + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(peTSig){ + for(i = 0; peTSig[i]; i++) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(peTSig[i],-1)); + } + else { + for(p = sig; (q = strindex(p, '\n')); p = q + 1) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, q - p)); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(p, -1)); + fs_give((void **) &sig); + } + return(TCL_OK); + } + else if(!strcmp(s1, "filters")){ + long rflags = ROLE_DO_FILTER | PAT_USE_CHANGED; + PAT_STATE pstate; + PAT_S *pat; + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(pat->patgrp->nick, -1)); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "scores")){ + long rflags = ROLE_DO_SCORES | PAT_USE_CHANGED; + PAT_STATE pstate; + PAT_S *pat; + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(pat->patgrp->nick, -1)); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "indexcolors")){ + long rflags = ROLE_DO_INCOLS | PAT_USE_CHANGED; + PAT_STATE pstate; + PAT_S *pat; + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate); + pat; + pat = next_pattern(&pstate)){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(pat->patgrp->nick, -1)); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "collections")){ + struct variable *vtmp; + int i; + CONTEXT_S *new_ctxt; + + vtmp = &ps_global->vars[V_FOLDER_SPEC]; + for(i = 0; (vtmp->is_changed_val + ? vtmp->changed_val.l && vtmp->changed_val.l[i] + : vtmp->current_val.l && vtmp->current_val.l[i]); + i++){ + new_ctxt = new_context(vtmp->is_changed_val + ? vtmp->changed_val.l[i] + : vtmp->current_val.l[i], NULL); + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", + new_ctxt->nickname + ? new_ctxt->nickname + : (new_ctxt->server + ? new_ctxt->server + : (new_ctxt->label + ? new_ctxt->label + : "Some Collection")), + new_ctxt->label ? new_ctxt->label : ""); + free_context(&new_ctxt); + } + vtmp = &ps_global->vars[V_NEWS_SPEC]; + for(i = 0; (vtmp->is_changed_val + ? vtmp->changed_val.l && vtmp->changed_val.l[i] + : vtmp->current_val.l && vtmp->current_val.l[i]); + i++){ + new_ctxt = new_context(vtmp->is_changed_val + ? vtmp->changed_val.l[i] + : vtmp->current_val.l[i], NULL); + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", + new_ctxt->nickname + ? new_ctxt->nickname + : (new_ctxt->server + ? new_ctxt->server + : (new_ctxt->label + ? new_ctxt->label + : "Some Collection")), + new_ctxt->label ? new_ctxt->label : ""); + free_context(&new_ctxt); + } + + return(TCL_OK); + } + else if(!strcmp(s1, "newconf")){ + struct variable *vtmp; + int i; + FEATURE_S *feature; + + for(vtmp = ps_global->vars; vtmp->name; vtmp++) + vtmp->is_changed_val = 0; + + for(i = 0; (feature = feature_list(i)); i++) + F_CH_SET(feature->id, F_ON(feature->id, ps_global)); + + if(peTSig){ + for(i = 0; peTSig[i]; i++) + fs_give((void **)&peTSig[i]); + fs_give((void **)&peTSig); + } + + close_patterns(ROLE_DO_FILTER | ROLE_DO_INCOLS | ROLE_DO_SCORES | PAT_USE_CHANGED); + return(TCL_OK); + } + else if(!strcmp(s1, "saveconf")){ + struct variable *vtmp; + int i, did_change = 0, def_sort_rev; + FEATURE_S *feature; + + if(ps_global->vars[V_FEATURE_LIST].is_changed_val){ + ps_global->vars[V_FEATURE_LIST].is_changed_val = 0; + for(i = 0; (feature = feature_list(i)); i++) + if(feature_list_section(feature)){ + if(F_CH_ON(feature->id) != F_ON(feature->id, ps_global)){ + did_change = 1; + toggle_feature(ps_global, + &ps_global->vars[V_FEATURE_LIST], + feature, TRUE, Main); + } + } + } + + for(vtmp = ps_global->vars; vtmp->name; vtmp++){ + if(vtmp->is_changed_val + && (vtmp - ps_global->vars != V_FEATURE_LIST)){ + if(vtmp->is_list){ + for(i = 0; vtmp->main_user_val.l + && vtmp->main_user_val.l[i]; i++) + fs_give((void **)&vtmp->main_user_val.l[i]); + if(vtmp->main_user_val.l) + fs_give((void **)&vtmp->main_user_val.l); + vtmp->main_user_val.l = vtmp->changed_val.l; + vtmp->changed_val.l = NULL; + } + else { + if(vtmp->main_user_val.p) + fs_give((void **)&vtmp->main_user_val.p); + vtmp->main_user_val.p = vtmp->changed_val.p; + vtmp->changed_val.p = NULL; + } + set_current_val(vtmp, FALSE, FALSE); + vtmp->is_changed_val = 0; + did_change = 1; + switch (vtmp - ps_global->vars) { + case V_USER_DOMAIN: + init_hostname(ps_global); + case V_FOLDER_SPEC: + case V_NEWS_SPEC: + free_contexts(&ps_global->context_list); + init_folders(ps_global); + break; + case V_NORM_FORE_COLOR: + pico_set_fg_color(vtmp->current_val.p); + break; + case V_NORM_BACK_COLOR: + pico_set_bg_color(vtmp->current_val.p); + break; + case V_ADDRESSBOOK: + case V_GLOB_ADDRBOOK: +#ifdef ENABLE_LDAP + case V_LDAP_SERVERS: +#endif + case V_ABOOK_FORMATS: + addrbook_reset(); + case V_INDEX_FORMAT: + init_index_format(ps_global->VAR_INDEX_FORMAT, + &ps_global->index_disp_format); + clear_index_cache(sp_inbox_stream(), 0); + break; + case V_PAT_FILTS: + close_patterns(ROLE_DO_FILTER | PAT_USE_CURRENT); + role_process_filters(); + break; + case V_PAT_INCOLS: + close_patterns(ROLE_DO_INCOLS | PAT_USE_CURRENT); + clear_index_cache(sp_inbox_stream(), 0); + role_process_filters(); + break; + case V_PAT_SCORES: + close_patterns(ROLE_DO_SCORES | PAT_USE_CURRENT); + role_process_filters(); + break; + case V_DEFAULT_FCC: + case V_DEFAULT_SAVE_FOLDER: + init_save_defaults(); + break; + case V_SORT_KEY: + decode_sort(ps_global->VAR_SORT_KEY, &ps_global->def_sort, &def_sort_rev); + break; + case V_VIEW_HDR_COLORS : + set_custom_spec_colors(ps_global); + break; + case V_POST_CHAR_SET : + update_posting_charset(ps_global, 1); + break; + default: + break; + } + } + } + if(peTSig){ + peWriteSig(interp, ps_global->VAR_SIGNATURE_FILE, NULL); + } + if(did_change){ + if(write_pinerc(ps_global, Main, WRP_NOUSER) == 0) + q_status_message(SM_ORDER, 0, 3, "Configuration changes saved!"); + } + return(TCL_OK); + } + else if(!strcmp(s1, "columns")){ + Tcl_SetResult(interp, int2string(ps_global->ttyo->screen_cols), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "indextokens")){ + INDEX_PARSE_T *tok; + int i; + + for(i = 0; (tok = itoken(i)) != NULL; i++) + if(tok->what_for & FOR_INDEX) + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(tok->name, -1)); + + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(s1, "varget")){ + char *varname = Tcl_GetStringFromObj(objv[2], NULL); + struct variable *vtmp; + Tcl_Obj *resObj, *secObj; + char *input_type; + int is_default, i; + NAMEVAL_S *tmpnv; + + if(varname == NULL) return(TCL_ERROR); + + for(vtmp = ps_global->vars; + vtmp->name && strucmp(vtmp->name, varname); + vtmp++) + ; + + if(!vtmp->name){ + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); + } + resObj = Tcl_NewListObj(0, NULL); + if(vtmp->is_list){ + if(vtmp->is_changed_val){ + for(i = 0; vtmp->changed_val.l && vtmp->changed_val.l[i]; i++){ + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(vtmp->changed_val.l[i], -1)); + } + } + else { + for(i = 0; vtmp->current_val.l && vtmp->current_val.l[i]; i++){ + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(vtmp->current_val.l[i], -1)); + } + } + } + else { + if(vtmp->is_changed_val){ + if(vtmp->changed_val.p) + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(vtmp->changed_val.p[0] + ? vtmp->changed_val.p + : "\"\"", -1)); + } + else { + if(vtmp->current_val.p) + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(vtmp->current_val.p[0] + ? vtmp->current_val.p + : "\"\"", -1)); + } + } + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + resObj); + secObj = Tcl_NewListObj(0, NULL); + if(vtmp->is_list) + input_type = cpystr("textarea"); + else{ + NAMEVAL_S *(*tmpf)(int); + switch(vtmp - ps_global->vars){ + case V_SAVED_MSG_NAME_RULE: + tmpf = save_msg_rules; + break; + case V_FCC_RULE: + tmpf = fcc_rules; + break; + case V_SORT_KEY: + tmpf = sort_key_rules; + break; + case V_AB_SORT_RULE: + tmpf = ab_sort_rules; + break; + case V_FLD_SORT_RULE: + tmpf = fld_sort_rules; + break; + case V_GOTO_DEFAULT_RULE: + tmpf = goto_rules; + break; + case V_INCOMING_STARTUP: + tmpf = incoming_startup_rules; + break; + case V_PRUNING_RULE: + tmpf = pruning_rules; + break; + case V_WP_INDEXHEIGHT: + tmpf = wp_indexheight_rules; + break; + default: + tmpf = NULL; + break; + } + if(tmpf){ + for(i = 0; (tmpnv = (tmpf)(i)); i++){ + if(tmpnv->shortname) + peAppListF(interp, secObj, "%s%s", tmpnv->name, tmpnv->shortname); + else + Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(tmpnv->name, -1)); + } + input_type = cpystr("listbox"); + } + else + input_type = cpystr("text"); + } + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(input_type, -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + secObj); + if(vtmp->is_list) + is_default = !vtmp->is_changed_val && !vtmp->main_user_val.l; + else + is_default = !vtmp->is_changed_val && !vtmp->main_user_val.p; + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(is_default)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(vtmp->is_fixed)); + return(TCL_OK); + } + else if(!strcmp(s1, "filtextended")){ + int fl, i; + long rflags = ROLE_DO_FILTER | PAT_USE_CHANGED; + PAT_STATE pstate; + PAT_S *pat; + Tcl_Obj *resObj = NULL, *tObj = NULL; + + if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR) + return(TCL_ERROR); + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate), i = 0; + pat && i != fl; + pat = next_pattern(&pstate), i++); + + if(!pat) + return(TCL_ERROR); + + /* append the pattern ID */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("id", -1)); + pePatAppendID(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* append the pattern */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("pattern", -1)); + pePatAppendPattern(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* now append the filter action */ + resObj = Tcl_NewListObj(0, NULL); + peAppListF(interp, resObj, "%s%i", "kill", pat->action->folder ? 0 : 1); + peAppListF(interp, resObj, "%s%p", "folder", pat->action->folder); + peAppListF(interp, resObj, "%s%i", "move_only_if_not_deleted", + pat->action->move_only_if_not_deleted); + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("filtaction", -1)); + Tcl_ListObjAppendElement(interp, tObj, resObj); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + } + else return(TCL_ERROR); + + return(TCL_OK); + } + else if(!strcmp(s1, "indexcolorextended")){ + int fl, i; + long rflags = ROLE_DO_INCOLS | PAT_USE_CHANGED; + PAT_STATE pstate; + PAT_S *pat; + Tcl_Obj *resObj = NULL, *tObj = NULL; + + if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR) + return(TCL_ERROR); + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate), i = 0; + pat && i != fl; + pat = next_pattern(&pstate), i++); + + if(!pat) + return(TCL_ERROR); + + /* append the pattern ID */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("id", -1)); + pePatAppendID(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* append the pattern */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("pattern", -1)); + pePatAppendPattern(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* now append the pattern colors */ + resObj = Tcl_NewListObj(0, NULL); + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("indexcolor", -1)); + if(pat->action->is_a_incol){ + char *color; + Tcl_Obj *colObj = Tcl_NewListObj(0, NULL); + + if(!(pat->action->incol + && pat->action->incol->fg + && pat->action->incol->fg[0] + && (color = color_to_asciirgb(pat->action->incol->fg)) + && (color = peColorStr(color,tmp_20k_buf)))) + color = ""; + + Tcl_ListObjAppendElement(interp, colObj, Tcl_NewStringObj(color, -1)); + + if(!(pat->action->incol + && pat->action->incol->bg + && pat->action->incol->bg[0] + && (color = color_to_asciirgb(pat->action->incol->bg)) + && (color = peColorStr(color,tmp_20k_buf)))) + color = ""; + + Tcl_ListObjAppendElement(interp, colObj, Tcl_NewStringObj(color, -1)); + Tcl_ListObjAppendElement(interp, tObj, colObj); + } + Tcl_ListObjAppendElement(interp, resObj, tObj); + + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("indexcolors", -1)); + Tcl_ListObjAppendElement(interp, tObj, resObj); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + } + else return(TCL_ERROR); + + return(TCL_OK); + } + else if(!strcmp(s1, "scoreextended")){ + int fl, i; + long rflags = ROLE_DO_SCORES | PAT_USE_CHANGED; + char *hdr = NULL; + PAT_STATE pstate; + PAT_S *pat; + Tcl_Obj *resObj = NULL, *tObj = NULL; + + if(Tcl_GetIntFromObj(interp, objv[2], &fl) == TCL_ERROR) + return(TCL_ERROR); + + close_every_pattern(); + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate), i = 0; + pat && i != fl; + pat = next_pattern(&pstate), i++); + + if(!pat) + return(TCL_ERROR); + + /* append the pattern ID */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("id", -1)); + pePatAppendID(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* append the pattern */ + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("pattern", -1)); + pePatAppendPattern(interp, tObj, pat); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* now append the filter action */ + resObj = Tcl_NewListObj(0, NULL); + peAppListF(interp, resObj, "%s%l", "scoreval", pat->action->scoreval); + if(pat->action->scorevalhdrtok) + hdr = hdrtok_to_stringform(pat->action->scorevalhdrtok); + + peAppListF(interp, resObj, "%s%s", "scorehdr", hdr ? hdr : ""); + + if(hdr) + fs_give((void **) &hdr); + + tObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tObj, Tcl_NewStringObj("scores", -1)); + Tcl_ListObjAppendElement(interp, tObj, resObj); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + } + else return(TCL_ERROR); + + return(TCL_OK); + } + else if(!strcmp(s1, "clextended")){ + int cl, i, j = 0, in_folder_spec = 0; + struct variable *vtmp; + char tpath[MAILTMPLEN], *p; + CONTEXT_S *ctxt; + + vtmp = &ps_global->vars[V_FOLDER_SPEC]; + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR) + return(TCL_ERROR); + for(i = 0; i < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l + && vtmp->changed_val.l[i]) + : (vtmp->current_val.l + && vtmp->current_val.l[i])); i++); + if(i == cl && (vtmp->is_changed_val + ? vtmp->changed_val.l && vtmp->changed_val.l[i] + : vtmp->current_val.l && vtmp->current_val.l[i])) + in_folder_spec = 1; + else { + vtmp = &ps_global->vars[V_NEWS_SPEC]; + for(j = 0; i + j < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l + && vtmp->changed_val.l[j]) + : (vtmp->current_val.l + && vtmp->current_val.l[j])); j++); + } + if(in_folder_spec || (i + j == cl && (vtmp->is_changed_val + ? vtmp->changed_val.l && vtmp->changed_val.l[j] + : vtmp->current_val.l && vtmp->current_val.l[j]))){ + ctxt = new_context(vtmp->is_changed_val ? vtmp->changed_val.l[in_folder_spec ? i : j] + : vtmp->current_val.l[in_folder_spec ? i : j], NULL); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ctxt->nickname ? ctxt->nickname : "", -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ctxt->label ? ctxt->label : "", -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ctxt->server ? ctxt->server : "", -1)); + tpath[0] = '\0'; + if(ctxt->context){ + strncpy(tpath, (ctxt->context[0] == '{' + && (p = strchr(ctxt->context, '}'))) + ? ++p + : ctxt->context, sizeof(tpath)); + tpath[sizeof(tpath)-1] = '\0'; + if((p = strstr(tpath, "%s")) != NULL) + *p = '\0'; + } + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(tpath, -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ctxt->dir && ctxt->dir->view.user + ? ctxt->dir->view.user : "", -1)); + free_context(&ctxt); + + return(TCL_OK); + } + else + return(TCL_ERROR); + } + else if(!strcmp(s1, "rawsig")){ + struct variable *vtmp; + char *cstring_version, *sig, *line; + int i, nSig; + Tcl_Obj **objSig; + + vtmp = &ps_global->vars[V_LITERAL_SIG]; + if(vtmp->is_changed_val ? vtmp->changed_val.p + : ps_global->VAR_LITERAL_SIG){ + + tmp_20k_buf[0] = '\0'; + Tcl_ListObjGetElements(interp, objv[2], &nSig, &objSig); + for(i = 0; i < nSig && i < SIG_MAX_LINES; i++) + if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL) + snprintf(tmp_20k_buf + strlen(tmp_20k_buf), SIZEOF_20KBUF - strlen(tmp_20k_buf), "%.*s\n", SIG_MAX_COLS, line); + + sig = cpystr(tmp_20k_buf); + + if((cstring_version = string_to_cstring(sig)) != NULL){ + if(vtmp->changed_val.p) + fs_give((void **)&vtmp->changed_val.p); + vtmp->is_changed_val = 1; + vtmp->changed_val.p = cstring_version; + } + + fs_give((void **) &sig); + return(TCL_OK); + } + else { + if(peTSig){ + for(i = 0; peTSig[i]; i++) + fs_give((void **)&peTSig[i]); + fs_give((void **)&peTSig); + } + Tcl_ListObjGetElements(interp, objv[2], &nSig, &objSig); + peTSig = (char **)fs_get(sizeof(char)*(nSig + 1)); + for(i = 0; i < nSig; i++){ + line = Tcl_GetStringFromObj(objSig[i], NULL); + peTSig[i] = cpystr(line ? line : ""); + } + peTSig[i] = NULL; + return(TCL_OK); + } + } + else if(!strcmp(s1, "colorget")){ + char *varname; + char tvname[256], hexcolor[256]; + struct variable *vtmp; + if(!(varname = Tcl_GetStringFromObj(objv[2], NULL))){ + return(TCL_ERROR); + } + if(strcmp("viewer-hdr-colors", varname) == 0){ + SPEC_COLOR_S *hcolors, *thc; + Tcl_Obj *resObj; + char hexcolor[256], *tstr = NULL; + + if(ps_global->vars[V_VIEW_HDR_COLORS].is_changed_val) + hcolors = spec_colors_from_varlist(ps_global->vars[V_VIEW_HDR_COLORS].changed_val.l, 0); + else + hcolors = spec_colors_from_varlist(ps_global->VAR_VIEW_HDR_COLORS, 0); + for(thc = hcolors; thc; thc = thc->next){ + resObj = Tcl_NewListObj(0,NULL); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(thc->spec, -1)); + hex_colorstr(hexcolor, thc->fg); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(hexcolor, -1)); + hex_colorstr(hexcolor, thc->bg); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(hexcolor, -1)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(thc->val + ? tstr = pattern_to_string(thc->val) + : "", -1)); + if(tstr) fs_give((void **)&tstr); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + resObj); + } + fs_give((void **)&hcolors); + return(TCL_OK); + } + else { + char *colorp; + + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-foreground-color"); + + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name) return(TCL_ERROR); + if(vtmp->is_list) return(TCL_ERROR); + + colorp = (vtmp->is_changed_val && vtmp->changed_val.p) + ? vtmp->changed_val.p + : (vtmp->current_val.p) ? vtmp->current_val.p + : vtmp->global_val.p; + + if(colorp){ + hex_colorstr(hexcolor, colorp); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(hexcolor, -1)); + } + else + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("", -1)); + + snprintf(tvname, sizeof(tvname), "%.200s%.50s", varname, "-background-color"); + vtmp++; + if((vtmp->name && strucmp(vtmp->name, tvname)) || !vtmp->name) + for(vtmp = &ps_global->vars[V_NORM_FORE_COLOR]; + vtmp->name && strucmp(vtmp->name, tvname); + vtmp++) + ; + + if(!vtmp->name) return(TCL_ERROR); + if(vtmp->is_list) return(TCL_ERROR); + + colorp = (vtmp->is_changed_val && vtmp->changed_val.p) + ? vtmp->changed_val.p + : (vtmp->current_val.p) ? vtmp->current_val.p + : vtmp->global_val.p; + + if(colorp){ + hex_colorstr(hexcolor, colorp); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(hexcolor, -1)); + } + else + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("", -1)); + } + return(TCL_OK); + } + else if(!strcmp(s1, "cldel")){ + int cl, i, j, n; + struct variable *vtmp; + char **newl; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR) + return(TCL_ERROR); + vtmp = &ps_global->vars[V_FOLDER_SPEC]; + for(i = 0; i < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i])); i++); + if(!(i == cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i])))){ + vtmp = &ps_global->vars[V_NEWS_SPEC]; + for(j = 0; i + j < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j])); + j++); + if(!(vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j]))) + return(TCL_ERROR); + i = j; + } + for(n = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[n]) + : (vtmp->current_val.l && vtmp->current_val.l[n]); n++); + newl = (char **)fs_get(n*(sizeof(char *))); + for(n = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[n]) + : (vtmp->current_val.l && vtmp->current_val.l[n]); n++){ + if(n < i) + newl[n] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[n] + : vtmp->current_val.l[n]); + else if(n > i) + newl[n-1] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[n] + : vtmp->current_val.l[n]); + } + newl[n-1] = NULL; + vtmp->is_changed_val = 1; + for(n = 0; vtmp->changed_val.l && vtmp->changed_val.l[n]; n++) + fs_give((void **) &vtmp->changed_val.l[n]); + if(vtmp->changed_val.l) fs_give((void **)&vtmp->changed_val.l); + vtmp->changed_val.l = newl; + + return(TCL_OK); + } + else if(!strcmp(s1, "columns")){ + int n; + char *p; + + if(Tcl_GetIntFromObj(interp, objv[2], &n) != TCL_ERROR + && n >= MIN_SCREEN_COLS + && n < (MAX_SCREEN_COLS - 1) + && ps_global->ttyo->screen_cols != n){ + clear_index_cache(sp_inbox_stream(), 0); + ps_global->ttyo->screen_cols = n; + set_variable(V_WP_COLUMNS, p = int2string(n), 0, 0, Main); + Tcl_SetResult(interp, p, TCL_VOLATILE); + } + else + Tcl_SetResult(interp, int2string(ps_global->ttyo->screen_cols), TCL_VOLATILE); + + return(TCL_OK); + } + else if(!strcmp(s1, "reset")){ + char *p; + + if((p = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(!strcmp(p,"pinerc")){ + struct variable *var; + PINERC_S *prc; + + /* new pinerc structure, copy location pointers */ + prc = new_pinerc_s(ps_global->prc->name); + prc->type = ps_global->prc->type; + prc->rd = ps_global->prc->rd; + prc->outstanding_pinerc_changes = 1; + + /* tie off original pinerc struct and free it */ + ps_global->prc->rd = NULL; + ps_global->prc->outstanding_pinerc_changes = 0; + free_pinerc_s(&ps_global->prc); + + /* set global->prc to new struct with no pinerc_lines + * and fool write_pinerc into not writing changed vars + */ + ps_global->prc = prc; + + /* + * write at least one var into nearly empty pinerc + * and clear user's var settings. clear global cause + * they'll get reset in peInitVars + */ + for(var = ps_global->vars; var->name != NULL; var++){ + var->been_written = ((var - ps_global->vars) != V_LAST_VERS_USED); + if(var->is_list){ + free_list_array(&var->main_user_val.l); + free_list_array(&var->global_val.l); + } + else{ + fs_give((void **)&var->main_user_val.p); + fs_give((void **)&var->global_val.p); + } + } + + write_pinerc(ps_global, Main, WRP_NOUSER | WRP_PRESERV_WRITTEN); + + peInitVars(ps_global); + return(TCL_OK); + } + } + } + } + else if(objc == 4){ + if(!strcmp(s1, "varset")){ + char *varname = Tcl_GetStringFromObj(objv[2], NULL); + struct variable *vtmp; + char **tstrlist = NULL, *line, *tline; + Tcl_Obj **objVal; + int i, strlistpos, numlistvals; + + if(varname == NULL) return(TCL_ERROR); + for(vtmp = ps_global->vars; + vtmp->name && strucmp(vtmp->name, varname); + vtmp++) + ; + if(!vtmp->name){ + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); + } + if(Tcl_ListObjGetElements(interp, objv[3], &numlistvals, + &objVal) != TCL_OK) + return(TCL_ERROR); + vtmp->is_changed_val = 1; + if(vtmp->is_list){ + if(vtmp->changed_val.l){ + for(i = 0; vtmp->changed_val.l[i]; i++) + fs_give((void **)&vtmp->changed_val.l[i]); + fs_give((void **)&vtmp->changed_val.l); + } + if(numlistvals) + tstrlist = (char **)fs_get((numlistvals + 1) * sizeof(char *)); + for(i = 0, strlistpos = 0; i < numlistvals; i++){ + if((line = Tcl_GetStringFromObj(objVal[i], 0)) != NULL){ + tline = cpystr(line); + removing_leading_and_trailing_white_space(tline); + if(*tline) + tstrlist[strlistpos++] = cpystr(tline); + fs_give((void **) &tline); + } + } + if(tstrlist) + tstrlist[strlistpos] = NULL; + vtmp->changed_val.l = tstrlist; + } + else { + if(vtmp->changed_val.p) + fs_give((void **)&vtmp->changed_val.p); + if(numlistvals){ + if((line = Tcl_GetStringFromObj(objVal[0], 0)) != NULL){ + tline = cpystr(line); + if(strucmp(vtmp->name, "reply-indent-string")) + removing_leading_and_trailing_white_space(tline); + if(!strcmp(tline, "\"\"")){ + tline[0] = '\0'; + } + else if(tline[0] == '\0'){ + fs_give((void **)&tline); + } + if(tline){ + vtmp->changed_val.p = cpystr(tline); + fs_give((void **)&tline); + } + } + else + vtmp->changed_val.p = cpystr(""); + } + } + return(TCL_OK); + } + else if(!strcmp(s1, "feature")){ + char *featurename; + int i, set, wasset = 0; + FEATURE_S *feature; + + /* + * CMD: feature + * + * ARGS: featurename - + * value - new value to assign flag + * + * Returns: 1 if named feature set, 0 otherwise + * + */ + if((featurename = Tcl_GetStringFromObj(objv[2], NULL)) + && Tcl_GetIntFromObj(interp, objv[3], &set) != TCL_ERROR) + for(i = 0; (feature = feature_list(i)); i++) + if(!strucmp(featurename, feature->name)){ + ps_global->vars[V_FEATURE_LIST].is_changed_val = 1; + wasset = F_CH_ON(feature->id); + F_CH_SET(feature->id, set); + break; + } + + Tcl_SetResult(interp, int2string(wasset), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "clshuff")){ + char *dir, *tstr, **newl; + int cl, up = 0, fvarn, nvarn, icnt, i; + struct variable *fvar, *nvar, *vtmp; + + if(!(dir = Tcl_GetStringFromObj(objv[2], NULL))) + return TCL_ERROR; + if(Tcl_GetIntFromObj(interp, objv[3], &cl) == TCL_ERROR) + return(TCL_ERROR); + if(!strcmp(dir, "up")) + up = 1; + else if(!strcmp(dir, "down")) + up = 0; + else + return(TCL_ERROR); + fvar = &ps_global->vars[V_FOLDER_SPEC]; + nvar = &ps_global->vars[V_NEWS_SPEC]; + for(fvarn = 0; fvar->is_changed_val ? (fvar->changed_val.l && fvar->changed_val.l[fvarn]) + : (fvar->current_val.l && fvar->current_val.l[fvarn]); fvarn++); + for(nvarn = 0; nvar->is_changed_val ? (nvar->changed_val.l && nvar->changed_val.l[nvarn]) + : (nvar->current_val.l && nvar->current_val.l[nvarn]); nvarn++); + if(cl < fvarn){ + vtmp = fvar; + icnt = cl; + } + else if(cl >= fvarn && cl < nvarn + fvarn){ + vtmp = nvar; + icnt = cl - fvarn; + } + else + return(TCL_ERROR); + if(vtmp == nvar && icnt == 0 && up){ + newl = (char **)fs_get((fvarn + 2)*sizeof(char *)); + for(i = 0; fvar->is_changed_val ? (fvar->changed_val.l && fvar->changed_val.l[i]) + : (fvar->current_val.l && fvar->current_val.l[i]); i++) + newl[i] = cpystr(fvar->is_changed_val ? fvar->changed_val.l[i] + : fvar->current_val.l[i]); + newl[i++] = cpystr(nvar->is_changed_val ? nvar->changed_val.l[0] + : nvar->current_val.l[0]); + newl[i] = NULL; + fvar->is_changed_val = 1; + for(i = 0; fvar->changed_val.l && fvar->changed_val.l[i]; i++) + fs_give((void **)&fvar->changed_val.l[i]); + if(fvar->changed_val.l) fs_give((void **)&fvar->changed_val.l); + fvar->changed_val.l = newl; + newl = (char **)fs_get(nvarn*sizeof(char *)); + for(i = 1; nvar->is_changed_val ? (nvar->changed_val.l && nvar->changed_val.l[i]) + : (nvar->current_val.l && nvar->current_val.l[i]); i++) + newl[i-1] = cpystr(nvar->is_changed_val ? nvar->changed_val.l[i] + : nvar->current_val.l[i]); + newl[i-1] = NULL; + nvar->is_changed_val = 1; + for(i = 0; nvar->changed_val.l && nvar->changed_val.l[i]; i++) + fs_give((void **)&nvar->changed_val.l[i]); + if(nvar->changed_val.l) fs_give((void **)&nvar->changed_val.l); + nvar->changed_val.l = newl; + vtmp = fvar; + icnt = fvarn; + } + else if(vtmp == fvar && icnt == fvarn - 1 && !up){ + newl = (char **)fs_get(fvarn*sizeof(char *)); + for(i = 0; fvar->is_changed_val ? (fvar->changed_val.l && fvar->changed_val.l[i+1]) + : (fvar->current_val.l && fvar->current_val.l[i+1]); i++) + newl[i] = cpystr(fvar->is_changed_val ? fvar->changed_val.l[i] + : fvar->current_val.l[i]); + newl[i] = NULL; + tstr = cpystr(fvar->is_changed_val ? fvar->changed_val.l[i] + : fvar->current_val.l[i]); + fvar->is_changed_val = 1; + for(i = 0; fvar->changed_val.l && fvar->changed_val.l[i]; i++) + fs_give((void **)&fvar->changed_val.l[i]); + if(fvar->changed_val.l) fs_give((void **)&fvar->changed_val.l); + fvar->changed_val.l = newl; + newl = (char **)fs_get((nvarn+2)*sizeof(char *)); + newl[0] = tstr; + for(i = 0; nvar->is_changed_val ? (nvar->changed_val.l && nvar->changed_val.l[i]) + : (nvar->current_val.l && nvar->current_val.l[i]); i++) + newl[i+1] = cpystr(nvar->is_changed_val ? nvar->changed_val.l[i] + : nvar->current_val.l[i]); + newl[i+1] = NULL; + nvar->is_changed_val = 1; + for(i = 0; nvar->changed_val.l && nvar->changed_val.l[i]; i++) + fs_give((void **)&nvar->changed_val.l[i]); + if(nvar->changed_val.l) fs_give((void **)&nvar->changed_val.l); + nvar->changed_val.l = newl; + vtmp = nvar; + icnt = 0; + } + else { + newl = (char **)fs_get(((vtmp == fvar ? fvarn : nvarn) + 1)*sizeof(char *)); + for(i = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i]); i++) + newl[i] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[i] + : vtmp->current_val.l[i]); + newl[i] = NULL; + vtmp->is_changed_val = 1; + for(i = 0; vtmp->changed_val.l && vtmp->changed_val.l[i]; i++) + fs_give((void **)&vtmp->changed_val.l[i]); + if(vtmp->changed_val.l) fs_give((void **)&vtmp->changed_val.l); + vtmp->changed_val.l = newl; + } + if(up){ + tstr = vtmp->changed_val.l[icnt-1]; + vtmp->changed_val.l[icnt-1] = vtmp->changed_val.l[icnt]; + vtmp->changed_val.l[icnt] = tstr; + } + else { + tstr = vtmp->changed_val.l[icnt+1]; + vtmp->changed_val.l[icnt+1] = vtmp->changed_val.l[icnt]; + vtmp->changed_val.l[icnt] = tstr; + } + return(TCL_OK); + } + } + else if(objc == 7){ + if(!strcmp(s1, "cledit") || !strcmp(s1, "cladd")){ + int add = 0, cl, quotes_needed = 0, i, j, newn; + char *nick, *server, *path, *view, context_buf[MAILTMPLEN*4]; + char **newl; + struct variable *vtmp; + + if(!strcmp(s1, "cladd")) add = 1; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR) + return(TCL_ERROR); + if(!(nick = Tcl_GetStringFromObj(objv[3], NULL))) + return TCL_ERROR; + if(!(server = Tcl_GetStringFromObj(objv[4], NULL))) + return TCL_ERROR; + if(!(path = Tcl_GetStringFromObj(objv[5], NULL))) + return TCL_ERROR; + if(!(view = Tcl_GetStringFromObj(objv[6], NULL))) + return TCL_ERROR; + removing_leading_and_trailing_white_space(nick); + removing_leading_and_trailing_white_space(server); + removing_leading_and_trailing_white_space(path); + removing_leading_and_trailing_white_space(view); + if(strchr(nick, ' ')) + quotes_needed = 1; + if(strlen(nick)+strlen(server)+strlen(path)+strlen(view) > + MAILTMPLEN * 4 - 20) { /* for good measure */ + Tcl_SetResult(interp, "info too long", TCL_VOLATILE); + return TCL_ERROR; + } + if(3 + strlen(nick) + strlen(server) + strlen(path) + + strlen(view) > MAILTMPLEN + 4){ + Tcl_SetResult(interp, "collection fields too long", TCL_VOLATILE); + return(TCL_OK); + } + snprintf(context_buf, sizeof(context_buf), "%s%s%s%s%s%s[%s]", quotes_needed ? + "\"" : "", nick, quotes_needed ? "\"" : "", + strlen(nick) ? " " : "", + server, path, view); + if(add) { + vtmp = &ps_global->vars[V_NEWS_SPEC]; + if(!(vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[0]) + : (vtmp->current_val.l && vtmp->current_val.l[0]))) + vtmp = &ps_global->vars[V_FOLDER_SPEC]; + for(i = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i]); i++); + newn = i + 1; + newl = (char **)fs_get((newn + 1)*sizeof(char *)); + for(i = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i]); i++) + newl[i] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[i] + : vtmp->current_val.l[i]); + newl[i++] = cpystr(context_buf); + newl[i] = NULL; + } + else { + vtmp = &ps_global->vars[V_FOLDER_SPEC]; + for(i = 0; i < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i])); i++); + if(!(i == cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[i]) + : (vtmp->current_val.l && vtmp->current_val.l[i])))){ + vtmp = &ps_global->vars[V_NEWS_SPEC]; + for(j = 0; i + j < cl && (vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j])); + j++); + if(!(vtmp->is_changed_val + ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j]))) + return(TCL_ERROR); + i = j; + } + for(j = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j]); j++); + newl = (char **)fs_get(j * sizeof(char *)); + for(j = 0; vtmp->is_changed_val ? (vtmp->changed_val.l && vtmp->changed_val.l[j]) + : (vtmp->current_val.l && vtmp->current_val.l[j]); j++){ + if(j == i) + newl[j] = cpystr(context_buf); + else + newl[j] = cpystr(vtmp->is_changed_val ? vtmp->changed_val.l[j] + : vtmp->current_val.l[j]); + } + newl[j] = NULL; + } + vtmp->is_changed_val = 1; + for(j = 0; vtmp->changed_val.l && vtmp->changed_val.l[j]; j++) + fs_give((void **)&vtmp->changed_val.l[j]); + if(vtmp->changed_val.l) fs_give((void **)&vtmp->changed_val.l); + vtmp->changed_val.l = newl; + return TCL_OK; + } + } + else + err = "PEInfo: Too many arguments"; + } + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +int +peWriteSig(Tcl_Interp *interp, char *file, Tcl_Obj **objv) +{ + int try_cache, e, i, n, nSig; + char datebuf[200], *sig, *line; + FILE *fp; + REMDATA_S *rd; + Tcl_Obj **objSig; + + if(!(file && IS_REMOTE(file))){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote signature file: %s", + file ? file : "<null>"); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + /* + * We could parse the name here to find what type it is. So far we + * only have type RemImap. + */ + rd = rd_create_remote(RemImap, file, (void *)REMOTE_SIG_SUBTYPE, + NULL, "Error: ", "Can't fetch remote signature."); + if(!rd){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Can't create stream for sig file: %s", file); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + try_cache = rd_read_metadata(rd); + + if(rd->access == MaybeRorW){ + if(rd->read_status == 'R') + rd->access = ReadOnly; + else + rd->access = ReadWrite; + } + + if(rd->access != NoExists){ + + rd_check_remvalid(rd, 1L); + + /* + * If the cached info says it is readonly but + * it looks like it's been fixed now, change it to readwrite. + */ + if(rd->read_status == 'R'){ + /* + * We go to this trouble since readonly sigfiles + * are likely a mistake. They are usually supposed to be + * readwrite so we open it and check if it's been fixed. + */ + rd_check_readonly_access(rd); + if(rd->read_status == 'W'){ + rd->access = ReadWrite; + rd->flags |= REM_OUTOFDATE; + } + else{ + rd_close_remdata(&rd); + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Readonly sig file: %s", file); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + + if(rd->flags & REM_OUTOFDATE){ + if(rd_update_local(rd) != 0){ + + dprint((1, "pinerc_remote_open: rd_update_local failed")); + /* + * Don't give up altogether. We still may be + * able to use a cached copy. + */ + } + else{ + dprint((7, "%s: copied remote to local (%ld)", + rd->rn, (long)rd->last_use)); + } + } + + if(rd->access == ReadWrite) + rd->flags |= DO_REMTRIM; + } + + /* If we couldn't get to remote folder, try using the cached copy */ + if(rd->access == NoExists || rd->flags & REM_OUTOFDATE){ + rd_close_remdata(&rd); + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Unavailable sig file: %s", file); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + unlink(rd->lf); + + sig = NULL; + tmp_20k_buf[0] = '\0'; + if(objv){ + Tcl_ListObjGetElements(interp, objv[0], &nSig, &objSig); + for(i = 0; i < nSig && i < SIG_MAX_LINES; i++){ + if((line = Tcl_GetStringFromObj(objSig[i], NULL)) != NULL) + snprintf(tmp_20k_buf + strlen(tmp_20k_buf), SIZEOF_20KBUF - strlen(tmp_20k_buf), "%.*s\n", + SIG_MAX_COLS, line); + } + } + else if(peTSig){ + for(i = 0; peTSig[i] && i < SIG_MAX_LINES; i++) { + snprintf(tmp_20k_buf + strlen(tmp_20k_buf), SIZEOF_20KBUF - strlen(tmp_20k_buf), "%.*s\n", + SIG_MAX_COLS, peTSig[i]); + } + for(i = 0; peTSig[i]; i++) + fs_give((void **)&peTSig[i]); + fs_give((void **)&peTSig); + } + else + return(TCL_ERROR); + + sig = cpystr(tmp_20k_buf); + + if((fp = fopen(rd->lf, "w")) != NULL) + n = fwrite(sig, strlen(sig), 1, fp); + + fs_give((void **) &sig); + + if(fp){ + if(n != 1){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sig copy failure1: %s: %s", + rd->lf, error_description(errno)); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + rd_close_remdata(&rd); + } + + fclose(fp); + if(n != 1) + return(TCL_ERROR); + } + else { + rd_close_remdata(&rd); + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sig copy open failure2: %s: %s", + rd->lf, error_description(errno)); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + datebuf[0] = '\0'; + + if(!rd->t.i.stream){ + long retflags = 0; + + rd->t.i.stream = context_open(NULL, NULL, rd->rn, 0L, &retflags); + } + + if((e = rd_update_remote(rd, datebuf)) != 0){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Sig update failure: %s: %s", + rd->lf, error_description(errno)); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + rd_close_remdata(&rd); + return(TCL_ERROR); + } + + rd_update_metadata(rd, datebuf); + rd->read_status = 'W'; + rd_close_remdata(&rd); + return(TCL_OK); +} + + + +NAMEVAL_S *sort_key_rules(index) + int index; +{ + static NAMEVAL_S is_rules[] = { + {"Arrival", 0}, + {"Date", 0}, + {"Subject", 0}, + {"Cc", 0}, + {"From", 0}, + {"To", 0}, + {"size", 0}, + {"OrderedSubj", 0}, + {"tHread", 0}, + {"Arrival/Reverse", 0}, + {"Date/Reverse", 0}, + {"Subject/Reverse", 0}, + {"Cc/Reverse", 0}, + {"From/Reverse", 0}, + {"To/Reverse", 0}, + {"size/Reverse", 0}, + {"tHread/Reverse", 0}, + {"OrderedSubj/Reverse", 0} + }; + + return((index >= 0 && index < (sizeof(is_rules)/sizeof(is_rules[0]))) + ? &is_rules[index] : NULL); +} + +NAMEVAL_S *wp_indexheight_rules(index) + int index; +{ + static NAMEVAL_S is_rules[] = { + {"normal font", "24", 0}, + {"smallest font", "20", 0}, + {"small font", "22", 0}, + {"large font", "28", 0}, + {"largest font", "30", 0} + }; + + return((index >= 0 && index < (sizeof(is_rules)/sizeof(is_rules[0]))) + ? &is_rules[index] : NULL); +} + + +/* + * PEDebugCmd - turn on/off and set various debugging options + */ +int +PEDebugCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *s; + + if(!--objc){ /* only one arg? */ + Tcl_WrongNumArgs(interp, 1, objv, "?args?"); + } + else if((s = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + if(!strucmp(s, "level")){ + if(objc == 2){ + int level; + + if(Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) + return(TCL_ERROR); + + if(level > 0){ + if(level > 10) + level = 10; + + debug = level; + dprint((1, "Debug level %d", level)); + } + else{ + dprint((1, "PEDebug ending")); + debug = 0; + } + } + + Tcl_SetResult(interp, int2string(debug), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(s, "write")){ + if(objc == 2 && (s = Tcl_GetStringFromObj(objv[2], NULL))){ + /* + * script debugging has a high priority since + * statements can be added/removed on the fly + * AND are NOT present by default + */ + dprint((SYSDBG_INFO, "SCRIPT: %s", s)); + } + + return(TCL_OK); + } + else if(!strucmp(s, "imap")){ + int level; + + if(Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) + return(TCL_ERROR); + + if(level == 0){ + if(ps_global){ + ps_global->debug_imap = 0; + if(ps_global->mail_stream) + mail_nodebug(ps_global->mail_stream); + } + } + else if(level > 0 && level < 5){ + if(ps_global){ + ps_global->debug_imap = level; + if(ps_global->mail_stream) + mail_debug(ps_global->mail_stream); + } + } + + return(TCL_OK); + } + else + Tcl_SetResult(interp, "Unknown PEDebug request", TCL_STATIC); + } + + return(TCL_ERROR); +} + + +/* + * PESessionCmd - Export TCL Session-wide command set + */ +int +PESessionCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *op, *err = "Unknown PESession option"; + char *pe_user, *pe_host; + int pe_alt, l; + + dprint((2, "PESessionCmd")); + + if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + if(!strcmp(op, "open")){ + char *s, *pinerc, *pineconf = NULL; + + /* + * CMD: open user remote-pinerc local-default-config + * + * Initiate a session + * + * Returns: error string on error, nothing otherwise + */ + + if(objc < 4 || objc > 5){ + Tcl_WrongNumArgs(interp, 1, objv, "user password pinerc"); + return(TCL_ERROR); + } + + if(!(s = Tcl_GetStringFromObj(objv[2], &l))){ + Tcl_SetResult(interp, "Unknown User", TCL_STATIC); + return(TCL_ERROR); + } + else{ + int rv; + + pe_user = cpystr(s); + +#if defined(HAVE_SETENV) + rv = setenv("WPUSER", pe_user, 1); +#elif defined(HAVE_PUTENV) + { + static char putenvbuf[PUTENV_MAX]; + + if(l + 8 < PUTENV_MAX){ + if(putenvbuf[0]) /* only called once, but you never know */ + snprintf(putenvbuf + 7, PUTENV_MAX - 7, "%s", pe_user); + else + snprintf(putenvbuf, PUTENV_MAX, "WPUSER=%s", pe_user); + + rv = putenv(putenvbuf); + } + else + rv = 1; + } +#endif + + if(rv){ + fs_give((void **) &pe_user); + Tcl_SetResult(interp, (errno == ENOMEM) + ? "Insufficient Environment Space" + : "Cannot set WPUSER in environment", TCL_STATIC); + return(TCL_ERROR); + } + } + + if((pinerc = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + NETMBX mb; + + if(mail_valid_net_parse(pinerc, &mb)){ + pe_host = cpystr(mb.host); + pe_alt = (mb.sslflag || mb.tlsflag); + } + else { + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote Config: %s", pinerc); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + else { + Tcl_SetResult(interp, "Unknown config location", TCL_STATIC); + return(TCL_ERROR); + } + + if(objc == 5 && !(pineconf = Tcl_GetStringFromObj(objv[4], NULL))){ + Tcl_SetResult(interp, "Can't determine global config", TCL_STATIC); + return(TCL_ERROR); + } + + dprint((SYSDBG_INFO, "session (%s) %s - %s", + pe_user, pinerc, pineconf ? pineconf : "<none>")); + + /* credential cache MUST already be seeded */ + + /* destroy old user context */ + if(ps_global){ + /* destroy open stream */ + peDestroyStream(ps_global); + + /* destroy old user context */ + peDestroyUserContext(&ps_global); + } + + /* Establish a user context */ + if((s = peCreateUserContext(interp, pe_user, pinerc, pineconf)) != NULL){ + Tcl_SetResult(interp, s, TCL_VOLATILE); + return(TCL_ERROR); + } + + fs_give((void **) &pe_user); + fs_give((void **) &pe_host); + + return(TCL_OK); + } + else if(!strcmp(op, "close")){ + if(ps_global){ + /* destroy any open stream */ + peDestroyStream(ps_global); + + /* destroy user context */ + peDestroyUserContext(&ps_global); + } + + Tcl_SetResult(interp, "BYE", TCL_STATIC); + return(TCL_OK); + } + else if(!strcmp(op, "creds")){ + char *folder; + int colid; + + if(objc < 4){ + err = "creds: insufficient args"; + } + else if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR + && (folder = Tcl_GetStringFromObj(objv[3], NULL))){ + int i; + CONTEXT_S *cp; + + /* + * CMD: creds <collection-index> <folder> [user passwd] + * + * Test for valid credentials to access given folder + * + * Returns: 1 if so, 0 otherwise + */ + + for(i = 0, cp = ps_global ? ps_global->context_list : NULL; + i < 1 || cp != NULL ; + i++, cp = cp->next) + if(i == colid){ + int rv = 0; + char tmp[MAILTMPLEN], *p; + + if(cp){ + if(folder[0] == '\0'){ + if(cp->use & CNTXT_INCMNG) + rv = 1; + else + folder = "fake-fake"; + } + else if((cp->use & CNTXT_INCMNG) + && (p = folder_is_nick(folder, FOLDERS(cp), FN_NONE))) + folder = p; + } + + if(!rv && context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))){ + NETMBX mb; + + if(mail_valid_net_parse(tmp, &mb)){ + if(objc == 4){ /* check creds */ + if(!*mb.user && (p = alpine_get_user(mb.host, (mb.sslflag || mb.tlsflag)))) + strcpy(mb.user, p); + + if(alpine_have_passwd(mb.user, mb.host, (mb.sslflag || mb.tlsflag))) + rv = 1; + } + else if(objc == 6){ /* set creds */ + char *user, *passwd; + + if((user = Tcl_GetStringFromObj(objv[4], NULL)) + && (passwd = Tcl_GetStringFromObj(objv[5], NULL))){ + if(*mb.user && strcmp(mb.user, user)){ + err = "creds: mismatched user names"; + break; + } + + alpine_set_passwd(user, passwd, mb.host, + mb.sslflag + || mb.tlsflag + || (ps_global ? F_ON(F_PREFER_ALT_AUTH, ps_global) : 0)); + rv = 1; + } + else { + err = "creds: unable to read credentials"; + break; + } + } + else{ + err = "creds: invalid args"; + break; + } + } + } + + (void) Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewIntObj(rv)); + return(TCL_OK); + } + + err = "creds: Unrecognized collection ID"; + } + else + err = "creds: failure to acquire folder and collection ID"; + } + else if(!strcmp(op, "nocred")){ + char *folder; + int colid; + + if(!ps_global){ + err = "No Session active"; + } + else if(objc != 4){ + err = "nocred: wrong number of args"; + } + else if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR + && (folder = Tcl_GetStringFromObj(objv[3], NULL))){ + int i; + CONTEXT_S *cp; + + /* + * CMD: nocred <collection-index> <folder> + * + * Test for valid credentials to access given folder + * + * Returns: 1 if so, 0 otherwise + */ + + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + int rv = 0; + char tmp[MAILTMPLEN], *p; + + if((cp->use & CNTXT_INCMNG) + && (p = folder_is_nick(folder, FOLDERS(cp), FN_NONE))) + folder = p; + + if(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp)))){ + NETMBX mb; + + if(mail_valid_net_parse(tmp, &mb)){ + if(!*mb.user && (p = alpine_get_user(mb.host, (mb.sslflag || mb.tlsflag)))) + strcpy(mb.user, p); + + alpine_clear_passwd(mb.user, mb.host); + } + } + + (void) Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewIntObj(rv)); + return(TCL_OK); + } + + err = "creds: Unrecognized collection ID"; + } + else + err = "creds: failure to acquire folder and collection ID"; + } + else if(!strcmp(op, "acceptcert")){ + char *certhost; + STRLIST_S **p; + + if((certhost = Tcl_GetStringFromObj(objv[2], NULL))){ + for(p = &peCertHosts; *p; p = &(*p)->next) + ; + + *p = new_strlist(certhost); + } + + err = "PESession: no server name"; + } + else if(!strcmp(op, "random")){ + if(objc != 3){ + err = "PESession: random <length>"; + } else { + char s[1025]; + int l; + + if(Tcl_GetIntFromObj(interp,objv[2],&l) != TCL_ERROR){ + if(l <= 1024){ + Tcl_SetResult(interp, peRandomString(s,l,PRS_MIXED_CASE), TCL_STATIC); + return(TCL_OK); + } + else + err = "PESession: random length too long"; + } + else + err = "PESession: can't get random length"; + } + } + else if(!strcmp(op, "authdriver")){ + if(objc != 4){ + err = "PESession: authdriver {add | remove} drivername"; + } else { + char *cmd, *driver; + + if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if((driver = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + if(!strcmp(cmd,"enable")){ + err = "PESession: authdriver enable disabled for the nonce"; + } + else if(!strcmp(cmd,"disable")){ + if(mail_parameters(NULL, DISABLE_AUTHENTICATOR, (void *) driver)){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Authentication driver %.30s disabled", driver); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_OK); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "PESession: Can't disable %.30s", driver); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + else + err = "PESession: unknown authdriver operation"; + } + else + err = "PESession: Can't read driver name"; + } + else + err = "PESesions: Can't read authdriver operation"; + } + } + else if(!strcmp(op, "abandon")){ + /* + * CMD: abandon [timeout] + * + * Returns: nothing + */ + + if(objc != 3){ + err = "PESession: abandon [timeout]"; + } else { + long t; + + if(Tcl_GetLongFromObj(interp, objv[2], &t) == TCL_OK){ + /* ten second minimum and max of default */ + if(t > 0 && t <= PE_INPUT_TIMEOUT){ + gPEAbandonTimeout = t; + return(TCL_OK); + } + else + err = "unrecognized timeout"; + } + else + err = "Can't read timeout"; + } + } + else if(!strcmp(op, "noexpunge")){ + /* + * CMD: noexpunge <state> + * + * Returns: nothing + */ + + if(objc != 3){ + err = "PESession: noexpunge <state>"; + } else { + int onoff; + + if(Tcl_GetIntFromObj(interp, objv[2], &onoff) == TCL_OK){ + if(onoff == 0 || onoff == 1){ + ps_global->noexpunge_on_close = onoff; + return(TCL_OK); + } + + err = "unrecognized on/off state"; + } + else + err = "Can't read on/off state"; + } + } + else if(!strcmp(op, "setpassphrase")){ +#ifdef SMIME + char *passphrase; + + if(objc != 3){ + err = "PESession: setpassphrase <state>"; + } + else if((passphrase = Tcl_GetStringFromObj(objv[2], NULL))){ + if(ps_global && ps_global->smime){ + strncpy((char *) ps_global->smime->passphrase, passphrase, + sizeof(ps_global->smime->passphrase)); + ps_global->smime->passphrase[sizeof(ps_global->smime->passphrase)-1] = '\0'; + ps_global->smime->entered_passphrase = 1; + ps_global->smime->need_passphrase = 0; + peED.uid = 0; + return(TCL_OK); + } + } +#else + err = "S/MIME not configured for this server"; +#endif /* SMIME */ + } + else if(!strcmp(op, "expungecheck")) { + /* + * Return open folders and how many deleted messages they have + * + * return looks something like a list of these: + * {folder-name number-deleted isinbox isincoming} + */ + char *type; + long delete_count; + Tcl_Obj *resObj; + + if(objc != 3){ + err = "PESession: expungecheck <type>"; + } + else { + type = Tcl_GetStringFromObj(objv[2], NULL); + if(type && (strcmp(type, "current") == 0 || strcmp(type, "quit") == 0)){ + + if(ps_global->mail_stream != sp_inbox_stream() + || strcmp(type, "current") == 0){ + delete_count = count_flagged(ps_global->mail_stream, F_DEL); + resObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(pretty_fn(ps_global->cur_folder), -1)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj(delete_count)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj((ps_global->mail_stream + == sp_inbox_stream()) + ? 1 : 0)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj((ps_global->context_current->use & CNTXT_INCMNG) + ? 1 : 0)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + resObj); + } + if(strcmp(type, "quit") == 0){ + delete_count = count_flagged(sp_inbox_stream(), F_DEL); + resObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj("INBOX", -1)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj(delete_count)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj(1)); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewIntObj(1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), resObj); + } + return(TCL_OK); + } + else + err = "PESession: expungecheck unknown type"; + } + } + else if(!strcmp(op, "mailcheck")) { + /* + * CMD: mailcheck + * + * ARGS: reload -- "1" if we're reloading + * (vs. just checking newmail as a side effect + * of building a new page) + * + * Return list of folders with new or expunged messages + * + * return looks something like a list of these: + * {new-count newest-uid announcement-msg} + */ + int reload, force = UFU_NONE, rv; + time_t now = time(0); + + if(objc <= 3){ + if(objc < 3 || Tcl_GetIntFromObj(interp, objv[2], &reload) == TCL_ERROR) + reload = 0; + + /* minimum 10 second between IMAP pings */ + if(!time_of_last_input() || now - time_of_last_input() > 10){ + force = UFU_FORCE; + if(!reload) + peMarkInputTime(); + } + + peED.interp = interp; + + /* check for new mail */ + new_mail(force, reload ? GoodTime : VeryBadTime, NM_STATUS_MSG); + + if(!reload){ /* announced */ + zero_new_mail_count(); + } + + return(TCL_OK); + } + else + err = "PESession: mailcheck <reload>"; + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + + +/* + * PEFolderChange - create context's directory chain + * corresponding to list of given obj's + * + * NOTE: caller should call reset_context_folders(cp) to + * clean up data structures this creates before returning + */ +int +PEFolderChange(Tcl_Interp *interp, CONTEXT_S *cp, int objc, Tcl_Obj *CONST objv[]) +{ + int i; + FDIR_S *fp; + char *folder; + + for(i = 0; i < objc; i++) { + folder = Tcl_GetStringFromObj(objv[i], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolderChange: Can't read folder", TCL_VOLATILE); + reset_context_folders(cp); + return(TCL_ERROR); + } + + fp = next_folder_dir(cp, folder, 0, NULL); /* BUG: mail_stream? */ + fp->desc = folder_lister_desc(cp, fp); + fp->delim = cp->dir->delim; + fp->prev = cp->dir; + fp->status |= CNTXT_SUBDIR; + cp->dir = fp; + } + + return(TCL_OK); +} + +/* + * PEMakeFolderString: + */ +int +PEMakeFolderString(Tcl_Interp *interp, CONTEXT_S *cp, int objc, Tcl_Obj *CONST objv[], char **ppath) +{ + int i; + unsigned long size,len; + char *portion,*path; + + size = 0; + for(i = 0; i < objc; i++) { + portion = Tcl_GetStringFromObj(objv[i], NULL); + if(!portion) { + Tcl_SetResult(interp, "PEMakeFolderString: Can't read folder", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(i) size++; + size += strlen(portion); + } + + path = (char*) fs_get(size + 1); + size = 0; + for(i = 0; i < objc; i++) { + portion = Tcl_GetStringFromObj(objv[i], NULL); + len = strlen(portion); + if(i) path[size++] = cp->dir->delim; + memcpy(path + size, portion, len); + size += len; + } + path[size] = '\0'; + if(ppath) *ppath = path; else fs_give((void**) &path); + return(TCL_OK); +} + + +/* + * PEFolderCmd - export various bits of folder information + */ +int +PEFolderCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *op, errbuf[256], *err = "Unknown PEFolder request"; + + dprint((2, "PEFolderCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + if(ps_global){ + if(objc == 2){ + if(!strcmp(op, "current")){ + CONTEXT_S *cp; + int i; + + /* + * CMD: current + * + * Returns: string representing the name of the + * current mailbox + */ + + for(i = 0, cp = ps_global->context_list; cp && cp != ps_global->context_current; i++, cp = cp->next) + ; + + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewIntObj(cp ? i : 0)) == TCL_OK + && Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(ps_global->cur_folder,-1)) == TCL_OK) + return(TCL_OK); + + return(TCL_ERROR); + } + else if(!strcmp(op, "collections")){ + CONTEXT_S *cp; + int i; + + /* + * CMD: collections + * + * Returns: List of currently configured collections + */ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next){ + Tcl_Obj *objv[3]; + + objv[0] = Tcl_NewIntObj(i); + objv[1] = Tcl_NewStringObj(cp->nickname ? cp->nickname : "", -1); + objv[2] = Tcl_NewStringObj(cp->label ? cp->label : "", -1); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(3, objv)); + } + + return(TCL_OK); + } + else if(!strcmp(op, "defaultcollection")){ + int i; + CONTEXT_S *cp; + + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(cp->use & CNTXT_SAVEDFLT){ + Tcl_SetResult(interp, int2string(i), TCL_STATIC); + return(TCL_OK); + } + + err = "PEFolder: isincoming: Invalid collection ID"; + } + else if(!strcmp(op, "clextended")){ + CONTEXT_S *cp; + int i; + char tpath[MAILTMPLEN], *p; + + /* + * CMD: clextended + * + * Returns: Extended list of current collections + * + * Format: + * 0) Collection Number + * 1) Nickname + * 2) Label + * 3) Basically this is a flag to say if we can edit + * 4) Server + * 5) Path + * 6) View + */ + /* + * had to get rid of this cause the args are changed + * + * if(strcmp("extended", + * Tcl_GetStringFromObj(objv[2], NULL))){ + * Tcl_SetResult(interp, "invalid argument", TCL_VOLATILE); + * return(TCL_ERROR); + * } + */ + for(i = 0, cp = ps_global->context_list; cp ; + i++, cp = cp->next){ + Tcl_Obj *objv[7]; + + objv[0] = Tcl_NewIntObj(i); + objv[1] = Tcl_NewStringObj(cp->nickname ? + cp->nickname : "", -1); + objv[2] = Tcl_NewStringObj(cp->label ? + cp->label : "", -1); + objv[3] = Tcl_NewIntObj(cp->var.v ? 1 : 0); + objv[4] = Tcl_NewStringObj(cp->server ? + cp->server : "", -1); + tpath[0] = '\0'; + if(cp->context){ + strncpy(tpath, (cp->context[0] == '{' + && (p = strchr(cp->context, '}'))) + ? ++p + : cp->context, sizeof(tpath)); + tpath[sizeof(tpath)-1] = '\0'; + if((p = strstr(tpath, "%s")) != NULL) + *p = '\0'; + } + objv[5] = Tcl_NewStringObj(tpath, -1); + objv[6] = Tcl_NewStringObj(cp->dir && + cp->dir->view.user ? + cp->dir->view.user : + "", -1); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewListObj(7, objv)); + } + + return(TCL_OK); + } + } + else if(objc == 3 && !strcmp(op, "delimiter")){ + int colid, i; + char delim[2] = {'\0', '\0'}; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + if(cp->dir && cp->dir->delim) + delim[0] = cp->dir->delim; + + break; + } + + Tcl_SetResult(interp, delim[0] ? delim : "/", TCL_VOLATILE); + return(TCL_OK); + } + else + err = "PEFolder: delimiter: Can't read collection ID"; + } + else if(objc == 3 && !strcmp(op, "isincoming")){ + int colid, i; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + Tcl_SetResult(interp, int2string(((cp->use & CNTXT_INCMNG) != 0)), TCL_STATIC); + return(TCL_OK); + } + + err = "PEFolder: isincoming: Invalid collection ID"; + } + else + err = "PEFolder: isincoming: Can't read collection ID"; + } + else if(objc == 4 && !strcmp(op, "unread")){ + char *folder, tmp[MAILTMPLEN]; + MAILSTREAM *mstream; + CONTEXT_S *cp; + long colid, i, count = 0, flags = (F_UNSEEN | F_UNDEL); + int our_stream = 0; + /* + * CMD: unread + * + * Returns: number of unread messages in given + * folder + */ + if(Tcl_GetLongFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) + break; + + if(cp){ + if((folder = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + /* short circuit INBOX */ + if(colid == 0 && !strucmp(folder, "inbox")){ + count = count_flagged(sp_inbox_stream(), flags); + } + else{ + /* + * BUG: some sort of caching to prevent open() fore each call? + * does stream cache offset this? + */ + if(!(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp))) + && (mstream = same_stream_and_mailbox(tmp, ps_global->mail_stream)))){ + long retflags = 0; + + ps_global->noshow_error = 1; + our_stream = 1; + mstream = context_open(cp, NULL, folder, + SP_USEPOOL | SP_TEMPUSE| OP_READONLY | OP_SHORTCACHE, + &retflags); + ps_global->noshow_error = 0; + } + + count = count_flagged(mstream, flags); + + if(our_stream) + pine_mail_close(mstream); + } + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + } + else + err = "PEFolder: unread: Invalid collection ID"; + } + else + err = "PEFolder: unread: Can't read collection ID"; + } + else if(objc == 5 && !strcmp(op, "empty")){ + /* + * CMD: empty + * + * Returns: number of expunge messages + * + * Arguments: <colnum> <folder> <what> + * where <what> is either <uid>, 'selected', or 'all' + */ + CONTEXT_S *cp; + MAILSTREAM *stream = NULL; + MESSAGECACHE *mc; + MSGNO_S *msgmap; + int colid, i, our_stream = 0; + long uid, raw, count = 0L; + char *errstr = NULL, *what, *folder, *p, tmp[MAILTMPLEN]; + + if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) break; + } + + if(cp){ + if((folder = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + if((what = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){ + /* need to open? */ + if(!((context_allowed(context_apply(tmp, cp, folder, sizeof(tmp))) + && (stream = same_stream_and_mailbox(tmp, ps_global->mail_stream))) + || (stream = same_stream_and_mailbox(tmp, sp_inbox_stream())))){ + long retflags = 0; + + our_stream = 1; + stream = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE | OP_SHORTCACHE, &retflags); + } + + if(stream){ + msgmap = sp_msgmap(stream); + + if(!strucmp(what, "all")){ + if(mn_get_total(msgmap)){ + agg_select_all(stream, msgmap, NULL, 1); + errstr = peApplyFlag(stream, msgmap, 'd', 0, &count); + if(!errstr) + (void) cmd_expunge_work(stream, msgmap); + } + } + else{ + /* little complicated since we don't display deleted state and + * don't want to expunge what's not intended. + * remember what's deleted and restore state on the ones left + * when we're done. shouldn't happen much. + * NOTE: "uid" is NOT a UID in this loop + */ + for(uid = 1L; uid <= mn_get_total(msgmap); uid++){ + raw = mn_m2raw(msgmap, uid); + if(!get_lflag(stream, msgmap, uid, MN_EXLD) + && (mc = mail_elt(stream, raw)) != NULL + && mc->deleted){ + set_lflag(stream, msgmap, uid, MN_STMP, 1); + mail_flag(stream, long2string(raw), "\\DELETED", 0L); + } + else + set_lflag(stream, msgmap, uid, MN_STMP, 0); + } + + if(!strucmp(what,"selected")){ + if(any_lflagged(msgmap, MN_SLCT)){ + if(!(errstr = peApplyFlag(stream, msgmap, 'd', 0, &count))) + (void) cmd_expunge_work(stream, msgmap); + } + else + count = 0L; + } + else{ + uid = 0; + for(p = what; *p; p++) + if(isdigit((unsigned char) *p)){ + uid = (uid * 10) + (*p - '0'); + } + else{ + errstr = "Invalid uid value"; + break; + } + + if(!errstr && uid){ + /* uid is a UID here */ + mail_flag(stream, long2string(uid), "\\DELETED", ST_SET | ST_UID); + (void) cmd_expunge_work(stream, msgmap); + count = 1L; + } + } + + /* restore deleted on what didn't get expunged */ + for(uid = 1L; uid <= mn_get_total(msgmap); uid++){ + raw = mn_m2raw(msgmap, uid); + if(get_lflag(stream, msgmap, uid, MN_STMP)){ + set_lflag(stream, msgmap, uid, MN_STMP, 0); + mail_flag(stream, long2string(raw), "\\DELETED", ST_SET); + } + } + } + + if(our_stream) + pine_mail_close(stream); + } + else + errstr = "no stream"; + } + else + errstr = "Cannot get which "; + } + else + errstr = "Cannot get folder"; + } + else + errstr = "Invalid collection"; + + if(errstr){ + Tcl_SetResult(interp, errstr, TCL_VOLATILE); + return(TCL_ERROR); + } + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "export")){ + /* + * CMD: export + * + * Returns: success or failure after writing given + * folder to given local file. + * + * Format: + * 0) Collection Number + * 1) Folder + * 2) Destination file + */ + if(objc == 5){ + CONTEXT_S *cp; + MAILSTREAM *src; + APPEND_PKG pkg; + STRING msg; + long colid, i; + char *folder, *dfile, seq[64], tmp[MAILTMPLEN]; + int our_stream = 0; + + if(Tcl_GetLongFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) + break; + + if(cp){ + if((folder = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + if((dfile = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){ + if(mail_parameters(NULL, ENABLE_DRIVER, "unix")){ + + snprintf(tmp, sizeof(tmp), "#driver.unix/%s", dfile); + + if(pine_mail_create(NULL, tmp)){ + + err = NULL; /* reset error condition */ + + /* + * if not current folder, open a stream, setup the + * stuff to write the raw header/text by hand + * with berkeley delimiters since we don't want + * a local mailbox driver lunk in. + * + * comments: + * - BUG: what about logins? + * + */ + if(!(context_allowed(context_apply(tmp, cp, folder, sizeof(tmp))) + && (src = same_stream_and_mailbox(tmp, ps_global->mail_stream)))){ + long retflags = 0; + + our_stream = 1; + src = context_open(cp, NULL, folder, + SP_USEPOOL | SP_TEMPUSE | OP_READONLY | OP_SHORTCACHE, + &retflags); + } + + if(src && src->nmsgs){ + /* Go to work...*/ + pkg.stream = src; + pkg.msgno = 0; + pkg.msgmax = src->nmsgs; + pkg.flags = pkg.date = NIL; + pkg.message = &msg; + + snprintf (seq,sizeof(seq),"1:%lu",src->nmsgs); + mail_fetchfast (src, seq); + + ps_global->noshow_error = 1; + if(!mail_append_multiple (NULL, dfile, + peAppendMsg, (void *) &pkg)){ + snprintf(err = errbuf, sizeof(errbuf), "PEFolder: export: %.200s", + ps_global->c_client_error); + } + + ps_global->noshow_error = 0; + + if(our_stream) + pine_mail_close(src); + } + else + err = "PEFolder: export: can't open mail folder"; + + if(!err) + return(TCL_OK); + } + else + err = "PEFolder: export: can't create destination"; + + if(!mail_parameters(NULL, DISABLE_DRIVER, "unix")) + err = "PEFolder: export: can't disable driver"; + } + else + err = "PEFolder: export: can't enable driver"; + } + else + err = "PEFolder: export: can't read file name"; + } + else + err = "PEFolder: export: can't read folder name"; + } + else + err = "PEFolder: export: Invalid collection ID"; + } + else + err = "PEFolder:export: Can't read collection ID"; + } + else + err = "PEFolder: export <colid> <folder> <file>"; + } + else if(!strcmp(op, "import")){ + /* + * CMD: import + * + * Returns: success or failure after writing given + * folder to given local file. + * + * Format: + * 0) source file + * 1) destination collection number + * 2) destination folder + */ + if(objc == 5){ + CONTEXT_S *cp; + MAILSTREAM *src, *dst; + APPEND_PKG pkg; + STRING msg; + long colid, i; + char *folder, *sfile, seq[64]; + + /* get source file with a little sanity check */ + if((sfile = Tcl_GetStringFromObj(objv[2], NULL)) + && *sfile == '/' && !strstr(sfile, "..")){ + if(mail_parameters(NULL, ENABLE_DRIVER, "unix")){ + + ps_global->noshow_error = 1; /* don't queue error msg */ + err = NULL; /* reset error condition */ + + /* make sure sfile contains valid mail */ + if((src = mail_open(NULL, sfile, 0L)) != NULL){ + + if(Tcl_GetLongFromObj(interp,objv[3],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) + break; + + if(cp){ + if((folder = Tcl_GetStringFromObj(objv[4], NULL)) != NULL){ + long retflags = 0; + + if(context_create(cp, NULL, folder) + && (dst = context_open(cp, NULL, folder, SP_USEPOOL | SP_TEMPUSE, &retflags))){ + + if(src->nmsgs){ + /* Go to work...*/ + pkg.stream = src; + pkg.msgno = 0; + pkg.msgmax = src->nmsgs; + pkg.flags = pkg.date = NIL; + pkg.message = &msg; + + snprintf (seq,sizeof(seq),"1:%lu",src->nmsgs); + mail_fetchfast (src, seq); + + if(!context_append_multiple(cp, dst, folder, + peAppendMsg, (void *) &pkg, + ps_global->mail_stream)){ + snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s", + ps_global->c_client_error); + } + + } + + pine_mail_close(dst); + } + else + snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s", + ps_global->c_client_error); + } + else + err = "PEFolder: import: can't read folder name"; + } + else + err = "PEFolder:import: invalid collection id"; + } + else + err = "PEFolder: import: can't read collection id"; + + mail_close(src); + + } + else + snprintf(err = errbuf, sizeof(errbuf), "PEFolder: import: %.200s", + ps_global->c_client_error); + + ps_global->noshow_error = 0; + + if(!mail_parameters(NULL, DISABLE_DRIVER, "unix") && !err) + err = "PEFolder: import: can't disable driver"; + + if(!err) + return(TCL_OK); + } + else + err = "PEFolder: import: can't enable driver"; + } + else + err = "PEFolder: import: can't read file name"; + } + else + err = "PEFolder: import <file> <colid> <folder>"; + } + else { + int i, colid; + char *aes, *colstr; + CONTEXT_S *cp; + + /* + * 3 or more arguments, 3rd is the collection ID, rest + * are a folder name + */ + + if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){ + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) break; + } + else if((colstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(!strcmp("default", colstr)) + cp = default_save_context(ps_global->context_list); + else + cp = NULL; + } + else + cp = NULL; + + if(cp){ + if(!strcmp(op, "list")){ + int i, fcount, bflags = BFL_NONE; + + if(PEFolderChange(interp, cp, objc - 3, objv + 3) == TCL_ERROR) + return TCL_ERROR; + + if(cp->use & CNTXT_NEWS) + bflags |= BFL_LSUB; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + + pePrepareForAuthException(); + + build_folder_list(NULL, cp, "*", NULL, bflags); + + if((aes = peAuthException()) != NULL){ + Tcl_SetResult(interp, aes, TCL_VOLATILE); + reset_context_folders(cp); + return(TCL_ERROR); + } + + if((fcount = folder_total(FOLDERS(cp))) != 0){ + for(i = 0; i < fcount; i++){ + char type[3], *p; + FOLDER_S *f = folder_entry(i, FOLDERS(cp)); + + p = type; + if(f->isdir){ + *p++ = 'D'; + + if(f->hasnochildren && !f->haschildren) + *p++ = 'E'; + } + + if(f->isfolder + || f->nickname + || (cp->use & CNTXT_INCMNG)) + *p++ = 'F'; + + *p = '\0'; + + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", type, + f->nickname ? f->nickname : f->name); + } + } + + reset_context_folders(cp); + return(TCL_OK); + } + else if(!strucmp(op, "exists")){ + char *folder, *errstr = NULL; + int rv; + + if(objc < 4) { + Tcl_SetResult(interp, "PEFolder exists: No folder specified", TCL_VOLATILE); + return(TCL_ERROR); + } + folder = Tcl_GetStringFromObj(objv[objc - 1], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolder exists: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR) + return TCL_ERROR; + + ps_global->c_client_error[0] = '\0'; + pePrepareForAuthException(); + + rv = folder_name_exists(cp, folder, NULL); + + if(rv & FEX_ERROR){ + if((errstr = peAuthException()) == NULL){ + if(ps_global->c_client_error[0]) + errstr = ps_global->c_client_error; + else + errstr = "Indeterminate Error"; + } + } + + Tcl_SetResult(interp, errstr ? errstr : int2string((int)(rv & FEX_ISFILE)), TCL_VOLATILE); + return(errstr ? TCL_ERROR : TCL_OK); + } + else if(!strucmp(op, "fullname")){ + char *folder, *fullname; + + if(objc < 4) { + Tcl_SetResult(interp, "PEFolder fullname: No folder specified", TCL_VOLATILE); + return(TCL_ERROR); + } + folder = Tcl_GetStringFromObj(objv[objc - 1], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolder fullname: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR) + return TCL_ERROR; + +#if 0 + Tcl_Obj *obj = Tcl_NewStringObj((fullname = folder_is_nick(folder, FOLDERS(cp))) + ? fullname : folder, -1); + (void) Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + obj); +#else + Tcl_SetResult(interp, + (fullname = folder_is_nick(folder, FOLDERS(cp), FN_NONE)) ? fullname : folder, + TCL_VOLATILE); +#endif + + return(TCL_OK); + } + else if(!strucmp(op, "create")){ + char *aes, *folder; + + folder = Tcl_GetStringFromObj(objv[objc - 1], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolder create: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR) + return TCL_ERROR; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + pePrepareForAuthException(); + + if(!context_create(cp, NULL, folder)){ + if((aes = peAuthException()) != NULL){ + Tcl_SetResult(interp, aes, TCL_VOLATILE); + } + else{ + Tcl_SetResult(interp, + (ps_global->last_error[0]) + ? ps_global->last_error + : (ps_global->c_client_error[0]) + ? ps_global->c_client_error + : "Unable to create folder", + TCL_VOLATILE); + } + + reset_context_folders(cp); + return(TCL_ERROR); + } + + Tcl_SetResult(interp, "OK", TCL_STATIC); + reset_context_folders(cp); + return(TCL_OK); + } + else if(!strucmp(op, "delete")){ + int fi, readonly, close_opened = 0; + char *folder, *fnamep, *target = NULL, *aes; + MAILSTREAM *del_stream = NULL, *strm = NULL; + EditWhich ew; + PINERC_S *prc = NULL; + FOLDER_S *fp; + + folder = Tcl_GetStringFromObj(objv[objc - 1], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolder delete: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(PEFolderChange(interp, cp, objc - 4, objv + 3) == TCL_ERROR) + return TCL_ERROR; + + /* so we can check for folder's various properties */ + build_folder_list(NULL, cp, folder, NULL, BFL_NONE); + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + + pePrepareForAuthException(); + + /* close open folder, then delete */ + + if((fi = folder_index(folder, cp, FI_FOLDER)) < 0 + || (fp = folder_entry(fi, FOLDERS(cp))) == NULL){ + Tcl_SetResult(interp, "Cannot find folder to delete", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + + if(!((cp->use & CNTXT_INCMNG) && fp->name + && check_for_move_mbox(fp->name, NULL, 0, &target))){ + target = NULL; + } + + dprint((4, "=== delete_folder(%s) ===\n", folder ? folder : "?")); + + ew = config_containing_inc_fldr(fp); + if(ps_global->restricted) + readonly = 1; + else{ + switch(ew){ + case Main: + prc = ps_global->prc; + break; + case Post: + prc = ps_global->post_prc; + break; + case None: + break; + } + + readonly = prc ? prc->readonly : 1; + } + + if(prc && prc->quit_to_edit && (cp->use & CNTXT_INCMNG)){ + Tcl_SetResult(interp, "Must Exit Alpine to Change Configuration", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + + if(cp == ps_global->context_list + && !(cp->dir && cp->dir->ref) + && strucmp(folder, ps_global->inbox_name) == 0){ + Tcl_SetResult(interp, "Cannot delete special folder", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + else if(readonly && (cp->use & CNTXT_INCMNG)){ + Tcl_SetResult(interp, "Folder not in editable config file", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + else if((fp->name + && (strm=context_already_open_stream(cp,fp->name,AOS_NONE))) + || + (target + && (strm=context_already_open_stream(NULL,target,AOS_NONE)))){ + if(strm == ps_global->mail_stream) + close_opened++; + } + else if(fp->isdir || fp->isdual){ /* NO DELETE if directory isn't EMPTY */ + FDIR_S *fdirp = next_folder_dir(cp,folder,TRUE,NULL); + int ret; + + if(fp->haschildren) + ret = 1; + else if(fp->hasnochildren) + ret = 0; + else{ + ret = folder_total(fdirp->folders) > 0; + free_fdir(&fdirp, 1); + } + + if(ret){ + Tcl_SetResult(interp, "Cannot delete non-empty directory", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + + /* + * Folder by the same name exist, so delete both... + if(fp->isdual){ + Tcl_SetResult(interp, "Cannot delete: folder is also a directory", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + */ + } + + if(cp->use & CNTXT_INCMNG){ + Tcl_SetResult(interp, "Cannot delete incoming folder", TCL_STATIC); + reset_context_folders(cp); + return(TCL_ERROR); + } + + dprint((2,"deleting \"%s\" (%s) in context \"%s\"\n", + fp->name ? fp->name : "?", + fp->nickname ? fp->nickname : "", + cp->context ? cp->context : "?")); + if(strm){ + /* + * Close it, NULL the pointer, and let do_broach_folder fixup + * the rest... + */ + pine_mail_actually_close(strm); + if(close_opened){ + do_broach_folder(ps_global->inbox_name, + ps_global->context_list, + NULL, DB_INBOXWOCNTXT); + } + } + + /* + * Use fp->name since "folder" may be a nickname... + */ + if(ps_global->mail_stream + && context_same_stream(cp, fp->name, ps_global->mail_stream)) + del_stream = ps_global->mail_stream; + + fnamep = fp->name; + + if(!context_delete(cp, del_stream, fnamep)){ + if((aes = peAuthException()) != NULL){ + Tcl_SetResult(interp, aes, TCL_VOLATILE); + } + else{ + Tcl_SetResult(interp, + (ps_global->last_error[0]) + ? ps_global->last_error + : (ps_global->c_client_error[0]) + ? ps_global->c_client_error + : "Unable to delete folder", + TCL_VOLATILE); + } + + reset_context_folders(cp); + return(TCL_ERROR); + } + + + Tcl_SetResult(interp, "OK", TCL_STATIC); + reset_context_folders(cp); + return(TCL_OK); + } + /* + * must be at least 5 arguments for the next set of commands + */ + else if(objc < 5) { + Tcl_SetResult(interp, "PEFolder: not enough arguments", TCL_VOLATILE); + return(TCL_ERROR); + } + else if(!strucmp(op, "rename")){ + char *folder,*newfolder, *aes; + + folder = Tcl_GetStringFromObj(objv[objc - 2], NULL); + if(!folder) { + Tcl_SetResult(interp, "PEFolder rename: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + newfolder = Tcl_GetStringFromObj(objv[objc - 1], NULL); + if(!newfolder) { + Tcl_SetResult(interp, "PEFolder rename: Can't read folder", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(PEFolderChange(interp, cp, objc - 5, objv + 3) == TCL_ERROR) + return TCL_ERROR; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + pePrepareForAuthException(); + + if(!context_rename(cp, NULL, folder, newfolder)){ + if((aes = peAuthException()) != NULL){ + Tcl_SetResult(interp, aes, TCL_VOLATILE); + } + else{ + Tcl_SetResult(interp, + (ps_global->last_error[0]) + ? ps_global->last_error + : (ps_global->c_client_error[0]) + ? ps_global->c_client_error + : "Unable to rename folder", + TCL_VOLATILE); + } + reset_context_folders(cp); + return(TCL_ERROR); + } + Tcl_SetResult(interp, "OK", TCL_STATIC); + reset_context_folders(cp); + return(TCL_OK); + } + } + else + err = "PEFolder: Unrecognized collection ID"; + } + } + else + err = "No User Context Established"; + } + + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); +} + + +/* + * PEMailboxCmd - export various bits of mailbox information + */ +int +PEMailboxCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *op, errbuf[256], *err = "Unknown PEMailbox operation"; + + dprint((5, "PEMailboxCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + if(!strucmp(op, "open")){ + int i, colid; + char *folder; + CONTEXT_S *cp; + + peED.uid = 0; /* forget cached embedded data */ + + /* + * CMD: open <context-index> <folder> + * + * + */ + if(objc == 2){ + Tcl_SetResult(interp, (!sp_dead_stream(ps_global->mail_stream)) ? "0" : "1", TCL_VOLATILE); + return(TCL_OK); + } + + if(Tcl_GetIntFromObj(interp,objv[2],&colid) != TCL_ERROR){ + if((folder = Tcl_GetStringFromObj(objv[objc - 1], NULL)) != NULL) { + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) { + if(PEMakeFolderString(interp, cp, objc - 3, objv + 3, + &folder)) + return TCL_ERROR; + + dprint((1, "* PEMailbox open dir=%s folder=%s",cp->dir->ref,folder)); + + return(peCreateStream(interp, cp, folder, FALSE)); + } + + err = "open: Unrecognized collection ID"; + } + else + err = "open: Can't read folder"; + } + else + err = "open: Can't get collection ID"; + } + else if(!strcmp(op, "indexformat")){ + /* + * CMD: indexformat + * + * Returns: list of lists where: + * * the first element is the name of the + * field which may be "From", "Subject" + * "Date" or the emtpy string. + * * the second element which is either + * the percentage width or empty string + */ + if(objc == 2) + return(peIndexFormat(interp)); + } + else if(ps_global && ps_global->mail_stream){ + if(!strcmp(op, "select")){ + return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SLCT)); + } + else if(!strcmp(op, "search")){ + return(peSelect(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SRCH)); + } + else if(!strucmp(op, "apply")){ + return(peApply(interp, objc - 2, &((Tcl_Obj **) objv)[2])); + } + else if(!strcmp(op, "expunge")){ + /* + * CMD: expunge + * + * Returns: OK after having removed deleted messages + */ + char *streamstr = NULL; + MAILSTREAM *stream; + MSGNO_S *msgmap; + + if(objc == 3) streamstr = Tcl_GetStringFromObj(objv[2], NULL); + if(!streamstr + || (streamstr && (strcmp(streamstr, "current") == 0))){ + stream = ps_global->mail_stream; + msgmap = sp_msgmap(stream); + } + else if(streamstr && (strcmp(streamstr, "inbox") == 0)){ + stream = sp_inbox_stream(); + msgmap = sp_msgmap(stream); + } + else return(TCL_ERROR); + ps_global->last_error[0] = '\0'; + if(IS_NEWS(stream) + && stream->rdonly){ + msgno_exclude_deleted(stream, msgmap); + clear_index_cache(sp_inbox_stream(), 0); + + /* + * This is kind of surprising at first. For most sort + * orders, if the whole set is sorted, then any subset + * is also sorted. Not so for OrderedSubject sort. + * If you exclude the first message of a subject group + * then you change the date that group is to be sorted on. + */ + if(mn_get_sort(msgmap) == SortSubject2) + refresh_sort(ps_global->mail_stream, msgmap, FALSE); + } + else + (void) cmd_expunge_work(stream, msgmap); + + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "trashdeleted")){ + /* + * CMD: trashdeleted + * + * Returns: OK after moving deleted messages to Trash and expunging + */ + MAILSTREAM *stream; + MESSAGECACHE *mc; + CONTEXT_S *cp; + MSGNO_S *msgmap; + char *streamstr = NULL, tmp[MAILTMPLEN]; + long n, tomove = 0L; + + if(objc == 3) streamstr = Tcl_GetStringFromObj(objv[2], NULL); + if(!streamstr + || (streamstr && (strcmp(streamstr, "current") == 0))){ + stream = ps_global->mail_stream; + msgmap = sp_msgmap(stream); + } + else if(streamstr && (strcmp(streamstr, "inbox") == 0)){ + stream = sp_inbox_stream(); + msgmap = sp_msgmap(stream); + } + else return(TCL_ERROR); + + ps_global->last_error[0] = '\0'; + if(IS_NEWS(stream) && stream->rdonly){ + msgno_exclude_deleted(stream, msgmap); + clear_index_cache(sp_inbox_stream(), 0); + + /* + * This is kind of surprising at first. For most sort + * orders, if the whole set is sorted, then any subset + * is also sorted. Not so for OrderedSubject sort. + * If you exclude the first message of a subject group + * then you change the date that group is to be sorted on. + */ + if(mn_get_sort(msgmap) == SortSubject2) + refresh_sort(ps_global->mail_stream, msgmap, FALSE); + } + else{ + if(!(cp = default_save_context(ps_global->context_list))) + cp = ps_global->context_list; + + /* copy to trash if we're not in trash */ + if(ps_global->VAR_TRASH_FOLDER + && ps_global->VAR_TRASH_FOLDER[0] + && context_allowed(context_apply(tmp, cp, ps_global->VAR_TRASH_FOLDER, sizeof(tmp))) + && !same_stream_and_mailbox(tmp, stream)){ + + /* save real selected set, and */ + for(n = 1L; n <= mn_get_total(msgmap); n++){ + set_lflag(stream, msgmap, n, MN_STMP, get_lflag(stream, msgmap, n, MN_SLCT)); + /* select deleted */ + if(!get_lflag(stream, msgmap, n, MN_EXLD) + && (mc = mail_elt(stream, mn_m2raw(msgmap,n))) != NULL && mc->deleted){ + tomove++; + set_lflag(stream, msgmap, n, MN_SLCT, 1); + } + else + set_lflag(stream, msgmap, n, MN_SLCT, 0); + } + + if(tomove && pseudo_selected(stream, msgmap)){ + + /* save delted to Trash */ + n = save(ps_global, stream, + cp, ps_global->VAR_TRASH_FOLDER, + msgmap, SV_FOR_FILT | SV_FIX_DELS); + + /* then remove them */ + if(n == tomove){ + (void) cmd_expunge_work(stream, msgmap); + } + + restore_selected(msgmap); + } + + /* restore selected set */ + for(n = 1L; n <= mn_get_total(msgmap); n++) + set_lflag(stream, msgmap, n, MN_SLCT, + get_lflag(stream, msgmap, n, MN_STMP)); + } + } + + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "nextvector")){ + long msgno, count, countdown; + int i, aObjN = 0; + char *errstr = NULL, *s; + Tcl_Obj *rvObj, *vObj, *avObj, **aObj; + + /* + * CMD: nextvector + * + * ARGS: msgno - message number "next" is relative to + * count - how many msgno slots to return + * attrib - (optional) attributes to be returned with each message in vector + * + * Returns: vector containing next <count> messagenumbers (and optional attributes) + */ + if(objc == 4 || objc == 5){ + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) == TCL_OK){ + if(Tcl_GetLongFromObj(interp, objv[3], &count) == TCL_OK){ + + /* set index range for efficiency */ + if(msgno > 0L && msgno <= mn_get_total(sp_msgmap(ps_global->mail_stream))){ + gPeITop = msgno; + gPeICount = count; + } + + if(objc == 4 || Tcl_ListObjGetElements(interp, objv[4], &aObjN, &aObj) == TCL_OK){ + + if((rvObj = Tcl_NewListObj(0, NULL)) != NULL && count > 0 + && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(ps_global->mail_stream)))){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno); + + for(countdown = count; countdown > 0; countdown--){ + imapuid_t uid = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), msgno)); + int fetched = 0; + + if((vObj = Tcl_NewListObj(0, NULL)) != NULL){ + Tcl_ListObjAppendElement(interp, vObj, Tcl_NewLongObj(msgno)); + peAppListF(interp, vObj, "%lu", uid); + + if(aObjN){ + if((avObj = Tcl_NewListObj(0, NULL)) != NULL){ + for(i = 0; i < aObjN; i++){ + if((s = Tcl_GetStringFromObj(aObj[i], NULL)) != NULL){ + if(!strcmp(s, "statusbits")){ + char *s = peMsgStatBitString(ps_global, ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), peMessageNumber(uid), + gPeITop, gPeICount, &fetched); + Tcl_ListObjAppendElement(interp, avObj, Tcl_NewStringObj(s, -1)); + } + else if(!strcmp(s, "statuslist")){ + Tcl_Obj *nObj = peMsgStatNameList(interp, ps_global, ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), peMessageNumber(uid), + gPeITop, gPeICount, &fetched); + Tcl_ListObjAppendElement(interp, avObj, nObj); + } + else if(!strcmp(s, "status")){ + long raw; + char stat[3]; + MESSAGECACHE *mc; + + raw = peSequenceNumber(uid); + + if(!((mc = mail_elt(ps_global->mail_stream, raw)) && mc->valid)){ + mail_fetch_flags(ps_global->mail_stream, + ulong2string(uid), FT_UID); + mc = mail_elt(ps_global->mail_stream, raw); + } + + stat[0] = mc->deleted ? '1' : '0'; + stat[1] = mc->recent ? '1' : '0'; + stat[2] = mc->seen ? '1' : '0'; + + Tcl_ListObjAppendElement(interp, avObj, Tcl_NewStringObj(stat,3)); + } + else if(!strcmp(s, "indexparts")){ + Tcl_Obj *iObj; + + if((iObj = Tcl_NewListObj(0, NULL)) != NULL + && peAppendIndexParts(interp, uid, iObj, &fetched) == TCL_OK + && Tcl_ListObjAppendElement(interp, avObj, iObj) == TCL_OK){ + } + else + return(TCL_ERROR); + } + else if(!strucmp(s, "indexcolor")){ + if(peAppendIndexColor(interp, uid, avObj, &fetched) != TCL_OK) + return(TCL_ERROR); + } + } + else{ + errstr = "nextvector: can't read attributes"; + break; + } + } + + Tcl_ListObjAppendElement(interp, vObj, avObj); + } + else{ + errstr = "nextvector: can't allocate attribute return vector"; + break; + } + } + } + else{ + errstr = "nextvector: can't allocate new vector"; + break; + } + + Tcl_ListObjAppendElement(interp, rvObj, vObj); + + for(++msgno; msgno <= mn_get_total(sp_msgmap(ps_global->mail_stream)) && msgline_hidden(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_NONE); msgno++) + ; + + if(msgno > mn_get_total(sp_msgmap(ps_global->mail_stream))) + break; + } + } + + if(!errstr){ + /* append result vector */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), rvObj); + /* Everything is coerced to UTF-8 */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("UTF-8", -1)); + return(TCL_OK); + } + } + else + errstr = "nextvector: can't read attribute list"; + } + else + errstr = "nextvector: can't read count"; + } + else + errstr = "nextvector: can't read message number"; + } + else + errstr = "nextvector: Incorrect number of arguments"; + + if(errstr) + Tcl_SetResult(interp, errstr, TCL_STATIC); + + return(TCL_ERROR); + } + else if(objc == 2){ + if(!strcmp(op, "messagecount")){ + /* + * CMD: messagecount + * + * Returns: count of messsages in open mailbox + */ + Tcl_SetResult(interp, + long2string(mn_get_total(sp_msgmap(ps_global->mail_stream))), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "firstinteresting")){ + /* + * CMD: firstinteresting + * + * Returns: message number associated with + * "incoming-startup-rule" which had better + * be the "current" message since it was set + * in do_broach_folder and shouldn't have been + * changed otherwise (expunged screw us?) + */ + Tcl_SetResult(interp, + long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "selected")){ + /* + * CMD: selected + * + * Returns: count of selected messsages in open mailbox + */ + + Tcl_SetResult(interp, + long2string(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT)), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "searched")){ + /* + * CMD: searched + * + * Returns: count of searched messsages in open mailbox + */ + + Tcl_SetResult(interp, + long2string(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH)), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "mailboxname")){ + /* + * CMD: name + * + * Returns: string representing the name of the + * current mailbox + */ + Tcl_SetResult(interp, ps_global->cur_folder, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "close")){ + /* + * CMD: close + * + * Returns: with global mail_stream closed + */ + peDestroyStream(ps_global); + return(TCL_OK); + } + else if(!strcmp(op, "newmailreset")){ + sml_seen(); + zero_new_mail_count(); + sp_set_mail_box_changed(ps_global->mail_stream, 0); + sp_set_expunge_count(ps_global->mail_stream, 0L); + peMarkInputTime(); + return(TCL_OK); + } + else if(!strcmp(op, "newmailstatmsg")){ + long newest, count; + char subject[500], subjtxt[500], from[500], intro[500], *s = ""; + + /* + * CMD: newmailstatmsg + * + * ARGS: none + * + * Returns: text for new mail message + * + */ + + if(sp_mail_box_changed(ps_global->mail_stream) + && (count = sp_mail_since_cmd(ps_global->mail_stream))){ + + for(newest = ps_global->mail_stream->nmsgs; newest > 1L; newest--) + if(!get_lflag(ps_global->mail_stream, NULL, newest, MN_EXLD)) + break; + + if(newest){ + format_new_mail_msg(NULL, count, + pine_mail_fetchstructure(ps_global->mail_stream, + newest, NULL), + intro, from, subject, subjtxt, sizeof(subject)); + + snprintf(s = tmp_20k_buf, SIZEOF_20KBUF, "%s %s %s", intro, from, subjtxt); + } + } + + Tcl_SetResult(interp, s, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "savedefault")){ + return(peSaveDefault(interp, 0L, 0, NULL)); + } + else if(!strcmp(op, "gotodefault")){ + return(peGotoDefault(interp, 0L, NULL)); + } + else if(!strcmp(op, "zoom")){ + Tcl_SetResult(interp, + long2string((any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L) + ? any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT) : 0L), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "focus")){ + Tcl_SetResult(interp, + long2string((any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L) + ? any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH) : 0L), + TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "first")){ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)){ + long n; + + for(n = 1L; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++) + if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)){ + Tcl_SetResult(interp, long2string(n), TCL_VOLATILE); + return(TCL_OK); + } + + unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream)); + + } + + Tcl_SetResult(interp, int2string(1), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(op, "current")){ + long n = 0; + unsigned long u = 0; + + /* + * CMD: current + * + * ARGS: + * + * Returns: list of current msg {<sequence> <uid>} + */ + + if(mn_total_cur(sp_msgmap(ps_global->mail_stream)) <= 0 + || ((n = mn_get_cur(sp_msgmap(ps_global->mail_stream))) > 0 + && (u = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), n))) > 0)){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(ulong2string(u), -1)); + return(TCL_OK); + } + else + err = "Cannot get current"; + } + else if(!strcmp(op, "last")){ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)){ + long n; + + for(n = mn_get_total(sp_msgmap(ps_global->mail_stream)); n > 0L; n--) + if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)){ + Tcl_SetResult(interp, long2string(n), TCL_VOLATILE); + return(TCL_OK); + } + } + else{ + Tcl_SetResult(interp, long2string(mn_get_total(sp_msgmap(ps_global->mail_stream))), TCL_VOLATILE); + return(TCL_OK); + } + + Tcl_SetResult(interp, "Can't set last message number", TCL_STATIC); + return(TCL_ERROR); + } + else if(!strucmp(op, "sortstyles")){ + int i; + /* + * CMD: sortstyles + * + * Returns: list of supported sort styles + */ + + for(i = 0; ps_global->sort_types[i] != EndofList; i++) + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(sort_name(ps_global->sort_types[i]), -1)) != TCL_OK) + return(TCL_ERROR); + + return(TCL_OK); + } + else if(!strucmp(op, "sort")){ + return(peAppendCurrentSort(interp)); + } + else if(!strucmp(op, "state")){ + if(!ps_global->mail_stream || sp_dead_stream(ps_global->mail_stream)) + Tcl_SetResult(interp, "closed", TCL_STATIC); + else if(ps_global->mail_stream->rdonly && !IS_NEWS(ps_global->mail_stream)) + Tcl_SetResult(interp, "readonly", TCL_STATIC); + else + Tcl_SetResult(interp, "ok", TCL_STATIC); + + return(TCL_OK); + } + else if(!strucmp(op, "excludedeleted")){ + msgno_exclude_deleted(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream)); + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(op, "uid")){ + long msgno, raw; + + /* + * Return uid of given message number + * + * CMD: uid <msgnumber> + */ + + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_OK) + return(TCL_ERROR); /* conversion problem? */ + + if((raw = mn_m2raw(sp_msgmap(ps_global->mail_stream), msgno)) > 0L){ + raw = mail_uid(ps_global->mail_stream, raw); + Tcl_SetResult(interp, long2string(raw), TCL_VOLATILE); + return(TCL_OK); + } + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Invalid UID for message %ld", msgno); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + else if(!strcmp(op, "newmail")){ + int reload, force = UFU_NONE, rv; + time_t now = time(0); + + /* + * CMD: newmail + * + * ARGS: reload -- "1" if we're reloading + * (vs. just checking newmail as a side effect + * of building a new page) + * + * Returns: count - + * mostrecent - + */ + if(Tcl_GetIntFromObj(interp, objv[2], &reload) == TCL_ERROR) + reload = 0; + + /* minimum 10 second between IMAP pings */ + if(!time_of_last_input() || now - time_of_last_input() > 10){ + force = UFU_FORCE; + peMarkInputTime(); + } + + /* check for new mail */ + new_mail(force, reload ? GoodTime : VeryBadTime, NM_NONE); + + rv = peNewMailResult(interp); + + if(!reload) /* announced */ + zero_new_mail_count(); + + return(rv); + } + else if(!strcmp(op, "flagcount")){ + char *flag; + long count = 0L; + long flags = 0L; + int objlc; + Tcl_Obj **objlv; + + + /* + * CMD: flagcount + * + * ARGS: flags - + * + * Returns: count - number of message thusly flagged + * mostrecent - + */ + if(Tcl_ListObjGetElements(interp, objv[2], &objlc, &objlv) == TCL_OK){ + while(objlc--) + if((flag = Tcl_GetStringFromObj(*objlv++, NULL)) != NULL){ + if(!strucmp(flag, "deleted")){ + flags |= F_DEL; + } + if(!strucmp(flag, "undeleted")){ + flags |= F_UNDEL; + } + else if(!strucmp(flag, "seen")){ + flags |= F_SEEN; + } + else if(!strucmp(flag, "unseen")){ + flags |= F_UNSEEN; + } + else if(!strucmp(flag, "flagged")){ + flags |= F_FLAG; + } + else if(!strucmp(flag, "unflagged")){ + flags |= F_UNFLAG; + } + else if(!strucmp(flag, "answered")){ + flags |= F_ANS; + } + else if(!strucmp(flag, "unanswered")){ + flags |= F_UNANS; + } + else if(!strucmp(flag, "recent")){ + flags |= F_RECENT; + } + else if(!strucmp(flag, "unrecent")){ + flags |= F_UNRECENT; + } + } + + if(flags) + count = count_flagged(ps_global->mail_stream, flags); + } + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "zoom")){ + int newstate; + long n, zoomed = 0L; + + /* + * CMD: zoom + * + * Set/clear HID bits of non SLCT messages as requested. + * PEMailbox [first | last | next] are senstive to these flags. + * + * ARGS: newstate - 1 or 0 + * + * Returns: count of zoomed messages + */ + + if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){ + if(newstate > 0){ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(ps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT)))){ + zoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MN_SLCT); + zoomed = n; + } + } + else{ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)) + unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream)); + } + } + + Tcl_SetResult(interp, long2string(zoomed), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "focus")){ + int newstate; + long n, zoomed = 0L; + + /* + * CMD: focus + * + * Set/clear HID bits of non MN_SRCH messages as requested. + * PEMailbox [first | last | next] are senstive to MN_HIDE flag + * + * ARGS: newstate - 1 or 0 + * + * Returns: count of zoomed messages + */ + + if(Tcl_GetIntFromObj(interp, objv[2], &newstate) != TCL_ERROR){ + if(newstate > 0){ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) != (mn_get_total(sp_msgmap(ps_global->mail_stream)) - (n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SRCH)))) + zoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MN_SRCH); + + zoomed = n; + } + else{ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)) + unzoom_index(ps_global, ps_global->mail_stream, sp_msgmap(ps_global->mail_stream)); + } + } + + Tcl_SetResult(interp, long2string(zoomed), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(op, "next")){ + long msgno; + + /* + * CMD: next <msgno> + * + * ARGS: msgno - message number "next" is relative to + * + * Returns: previous state + */ + + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno); + mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE); + Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), TCL_VOLATILE); + return(TCL_OK); + } + + Tcl_SetResult(interp, "next can't read message number", TCL_STATIC); + return(TCL_ERROR); + } + } + else if(objc == 4){ + if(!strucmp(op, "sort")){ + int i, reversed = 0; + char *sort; + + /* + * CMD: sort sortstyle reversed + * + * Returns: OK with the side-effect of message + * numbers now reflecting the requested + * sort order. + */ + + if((sort = Tcl_GetStringFromObj(objv[2], NULL)) + && Tcl_GetIntFromObj(interp, objv[3], &reversed) != TCL_ERROR){ + /* convert sort string into */ + for(i = 0; ps_global->sort_types[i] != EndofList; i++) + if(strucmp(sort_name(ps_global->sort_types[i]), sort) == 0){ + if(sp_unsorted_newmail(ps_global->mail_stream) + || !(ps_global->sort_types[i] == mn_get_sort(sp_msgmap(ps_global->mail_stream)) + && mn_get_revsort(sp_msgmap(ps_global->mail_stream)) == reversed)) + sort_folder(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), + ps_global->sort_types[i], + reversed, 0); + + break; + } + } + + return(peAppendCurrentSort(interp)); + } + else if(!strucmp(op, "selected")){ + return(peSelected(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SLCT)); + } + else if(!strucmp(op, "searched")){ + return(peSelected(interp, objc - 2, &((Tcl_Obj **) objv)[2], MN_SRCH)); + } + else if(!strcmp(op, "next")){ + long msgno, count; + + /* + * CMD: next + * + * ARGS: msgno - message number "next" is relative to + * count - how many to increment it + * + * Returns: previous state + */ + + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR + && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno); + while(count) + if(count > 0){ + mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE); + count--; + } + else{ + mn_dec_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE); + count++; + } + + Tcl_SetResult(interp, long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), TCL_VOLATILE); + return(TCL_OK); + } + + Tcl_SetResult(interp, "next can't read message number", TCL_STATIC); + return(TCL_ERROR); + } + else if(!strcmp(op, "x-nextvector")){ + long msgno, count; + + /* + * CMD: nextvector + * + * ARGS: msgno - message number "next" is relative to + * count - how many msgno slots to return + * + * Returns: vector containing next <count> messagenumbers + */ + + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR + && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){ + if(count > 0 && !(msgno < 1L || msgno > mn_get_total(sp_msgmap(ps_global->mail_stream)))){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno); + + while(count--){ + long n = mn_get_cur(sp_msgmap(ps_global->mail_stream)); + + if(peAppListF(interp, Tcl_GetObjResult(interp), + "%l%l", n, mail_uid(ps_global->mail_stream, + mn_m2raw(sp_msgmap(ps_global->mail_stream), n))) != TCL_OK) + return(TCL_ERROR); + + mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE); + + if(n == mn_get_cur(sp_msgmap(ps_global->mail_stream))) + break; + } + } + + return(TCL_OK); + } + + Tcl_SetResult(interp, "next can't read message number", TCL_STATIC); + return(TCL_ERROR); + } + else if(!strcmp(op, "messagecount")){ + char *relative; + long msgno, n, count = 0L; + + /* + * CMD: messagecount + * + * ARGS: [before | after] relative to + * msgno + * + * Returns: count of messsages before or after given message number + */ + + if((relative = Tcl_GetStringFromObj(objv[2], NULL)) + && Tcl_GetLongFromObj(interp, objv[3], &msgno) != TCL_ERROR){ + if(msgno < 1L || msgno > mn_get_total(sp_msgmap(ps_global->mail_stream))){ + Tcl_SetResult(interp, "relative msgno out of range", TCL_STATIC); + return(TCL_ERROR); + } + + if(!strucmp(relative, "before")){ + for(n = msgno - 1; n > 0L; n--) + if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)) + count++; + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(relative, "after")){ + for(n = msgno + 1; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++) + if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_HIDE)) + count++; + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + } + + Tcl_SetResult(interp, "can't read range for count", TCL_STATIC); + return(TCL_ERROR); + } + else if(!strcmp(op, "selectvector")){ + long msgno, count; + + /* + * CMD: selectvector + * + * ARGS: msgno - message number "next" is relative to + * count - how many msgno slots to return + * + * Returns: vector containing next <count> messagenumbers + */ + + if(Tcl_GetLongFromObj(interp, objv[2], &msgno) != TCL_ERROR + && Tcl_GetLongFromObj(interp, objv[3], &count) != TCL_ERROR){ + if(msgno > 0L){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), msgno); + while(count--){ + msgno = mn_get_cur(sp_msgmap(ps_global->mail_stream)); + + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_SLCT)) + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewLongObj((long) mail_uid(ps_global->mail_stream, msgno))) != TCL_OK) + return(TCL_ERROR); + + mn_inc_cur(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), MH_NONE); + + if(msgno == mn_get_cur(sp_msgmap(ps_global->mail_stream))) + break; + } + } + + return(TCL_OK); + } + + Tcl_SetResult(interp, "selectvector: no message number", TCL_STATIC); + return(TCL_ERROR); + } + else if(!strucmp(op, "current")){ + char *which; + long x, n = 0, u = 0; + + /* + * CMD: current + * + * ARGS: (number|uid) <msgno> + * + * Returns: list of current msg {<sequence> <uid>} + */ + if((which = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(Tcl_GetLongFromObj(interp, objv[3], &x) == TCL_OK){ + if(!strucmp(which,"uid")){ + u = x; + n = peMessageNumber(u); + } + else if(!strucmp(which,"number")){ + n = x; + u = mail_uid(ps_global->mail_stream, mn_m2raw(sp_msgmap(ps_global->mail_stream), n)); + } + + if(n && u){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), n); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(n), -1)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(long2string(u), -1)); + return(TCL_OK); + } + else + err = "PEMailbox current: invalid number/uid"; + } + else + err = "PEMailbox current: cannot get number"; + } + else + err = "PEMailbox current: cannot get which"; + } + } + else + err = "PEMailbox: Too many arguments"; + } + else if(!strucmp(op, "name") || !strcmp(op, "close")){ + Tcl_SetResult(interp, "", TCL_STATIC); + return(TCL_OK); + } + else + snprintf(err = errbuf, sizeof(errbuf), "%s: %s: No open mailbox", + Tcl_GetStringFromObj(objv[0], NULL), op); + } + + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); +} + + +int +peAppendCurrentSort(Tcl_Interp *interp) +{ + return((Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(sort_name(mn_get_sort(sp_msgmap(ps_global->mail_stream))), -1)) == TCL_OK + && Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(mn_get_revsort(sp_msgmap(ps_global->mail_stream)) ? "1" : "0", 1)) == TCL_OK) + ? TCL_OK : TCL_ERROR); +} + + +int +peAppendDefaultSort(Tcl_Interp *interp) +{ + return((Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(sort_name(ps_global->def_sort), -1)) == TCL_OK + && Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ps_global->def_sort_rev ? "1" : "0", 1)) == TCL_OK) + ? TCL_OK : TCL_ERROR); +} + + +int +peSelect(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + char *subcmd; + long n, i, diff, msgno; + int narrow, hidden; + MESSAGECACHE *mc; + extern MAILSTREAM *mm_search_stream; + extern long mm_search_count; + + hidden = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE) > 0L; + mm_search_stream = ps_global->mail_stream; + mm_search_count = 0L; + + for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++) + if((mc = mail_elt(ps_global->mail_stream, n)) != NULL){ + mc->searched = 0; + mc->spare7 = 1; + } + + /* + * CMD: select + * + * ARGS: subcmd subcmdargs + * + * Returns: flip "matchflag" private bit on all or none + * of the messages in the mailbox + */ + if((subcmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){ + if(!strucmp(subcmd, "all")){ + /* + * Args: <none> + */ + if(matchflag & MN_SLCT){ + if(objc != 1) + return(peSelectError(interp, subcmd)); + + agg_select_all(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), NULL, 1); + } + else if(matchflag & MN_SRCH){ + for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++) + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, matchflag, 1); + } + + Tcl_SetResult(interp, "All", TCL_VOLATILE); + } + else if(!strucmp(subcmd, "none")){ + /* + * Args: <none> + */ + n = 0L; + + if(matchflag & MN_SLCT){ + if(objc != 1) + return(peSelectError(interp, subcmd)); + + agg_select_all(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), &n, 0); + } + else if(matchflag & MN_SRCH){ + for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++) + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, matchflag, 0); + } + + Tcl_SetResult(interp, long2string(n), TCL_VOLATILE); + } + else if(!strucmp(subcmd, "searched")){ + /* + * Args: <none> + */ + for(n = 1L, i = 0; n <= ps_global->mail_stream->nmsgs; n++) + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SRCH)){ + i++; + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SLCT, 1); + } + + Tcl_SetResult(interp, long2string(i), TCL_VOLATILE); + } + else if(!strucmp(subcmd, "unsearched")){ + /* + * Args: <none> + */ + for(n = 1L, i = 0; n <= ps_global->mail_stream->nmsgs; n++) + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SRCH)){ + i++; + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), n, MN_SLCT, 0); + } + + Tcl_SetResult(interp, long2string(i), TCL_VOLATILE); + } + else{ + if(!strucmp(subcmd, "narrow")) + narrow = 1; + else if(!strucmp(subcmd, "broad")) + narrow = 0; + else + return(peSelectError(interp, "invalid scope request")); + + if(!(subcmd = Tcl_GetStringFromObj(objv[1], NULL))) + return(peSelectError(interp, "missing subcommand")); + + if(!strucmp(subcmd, "num")){ + if((i = peSelectNumber(interp, objc - 2, &objv[2], matchflag)) != TCL_OK) + return(i); + } + else if(!strucmp(subcmd, "date")){ + if((i = peSelectDate(interp, objc - 2, &objv[2], matchflag)) != TCL_OK) + return(i); + } + else if(!strucmp(subcmd, "text")){ + if((i = peSelectText(interp, objc - 2, &objv[2], matchflag)) != TCL_OK) + return(i); + } + else if(!strucmp(subcmd, "status")){ + if((i = peSelectStatus(interp, objc - 2, &objv[2], matchflag)) != TCL_OK) + return(i); + } + else if(!strucmp(subcmd, "compound")){ + char *s; + int nSearchList, nSearch; + Tcl_Obj **oSearchList, **oSearch; + + /* BUG: should set up one SEARCHPGM to fit criteria and issue single search */ + + if(Tcl_ListObjGetElements(interp, objv[2], &nSearchList, &oSearchList) == TCL_OK){ + for(i = 0; i < nSearchList; i++){ + if(Tcl_ListObjGetElements(interp, oSearchList[i], &nSearch, &oSearch) == TCL_OK){ + if((s = Tcl_GetStringFromObj(oSearch[0], NULL)) != NULL){ + if(!strucmp(s,"date")){ + if((n = peSelectDate(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK) + return(n); + } + else if(!strucmp(s,"text")){ + if((n = peSelectText(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK) + return(n); + } + else if(!strucmp(s,"status")){ + if((n = peSelectStatus(interp, nSearch - 1, &oSearch[1], matchflag)) != TCL_OK) + return(n); + } + else + return(peSelectError(interp, "unknown compound search")); + + /* logical AND the results */ + mm_search_count = 0L; + for(n = 1L; n <= ps_global->mail_stream->nmsgs; n++) + if((mc = mail_elt(ps_global->mail_stream, n)) != NULL){ + if(mc->searched && mc->spare7) + mm_search_count++; + else + mc->searched = mc->spare7 = 0; + } + } + else + return(peSelectError(interp, "malformed compound search")); + } + else + return(peSelectError(interp, "malformed compound search")); + } + } + else + return(peSelectError(interp, "malformed compound search")); + } + else + return(peSelectError(interp, "cmd cmdargs")); + + /* + * at this point all interesting messages should + * have searched bit lit + */ + + if(narrow) /* make sure something was selected */ + for(i = 1L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++) + if(mail_elt(ps_global->mail_stream, + mn_m2raw(sp_msgmap(ps_global->mail_stream), i))->searched){ + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)) + break; + else + mm_search_count--; + } + + diff = 0L; + if(mm_search_count){ + /* + * loop thru all the messages, adjusting local flag bits + * based on their "searched" bit... + */ + for(i = 1L, msgno = 0L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++) + if(narrow){ + /* turning OFF selectedness if the "searched" bit isn't lit. */ + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){ + if(!mail_elt(ps_global->mail_stream, + mn_m2raw(sp_msgmap(ps_global->mail_stream), i))->searched){ + diff--; + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag, 0); + if(hidden) + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, MN_HIDE, 1); + } + else if(msgno < mn_get_cur(sp_msgmap(ps_global->mail_stream))) + msgno = i; + } + } + else if(mail_elt(ps_global->mail_stream,mn_m2raw(sp_msgmap(ps_global->mail_stream),i))->searched){ + /* turn ON selectedness if "searched" bit is lit. */ + if(!get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){ + diff++; + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag, 1); + if(hidden) + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, MN_HIDE, 0); + } + } + + /* if we're zoomed and the current message was unselected */ + if(narrow && msgno + && get_lflag(ps_global->mail_stream,sp_msgmap(ps_global->mail_stream),mn_get_cur(sp_msgmap(ps_global->mail_stream)),MN_HIDE)) + mn_reset_cur(sp_msgmap(ps_global->mail_stream), msgno); + } + + Tcl_SetResult(interp, long2string(diff), TCL_VOLATILE); + } + + return(TCL_OK); + } + + Tcl_SetResult(interp, "Can't read select option", TCL_STATIC); + return(TCL_ERROR); +} + +int +peSelectNumber(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + /* + * Args: [broad | narrow] firstnumber lastnumber + */ + + long first = 0L, last = 0L, n; + + if(objc == 2){ + if(Tcl_GetLongFromObj(interp, objv[0], &first) == TCL_OK + && Tcl_GetLongFromObj(interp, objv[1], &last) == TCL_OK){ + if(last && last < first){ + n = last; + last = first; + first = n; + } + + if(first >= 1L && first <= mn_get_total(sp_msgmap(ps_global->mail_stream))){ + if(last){ + if(last >= 1L && last <= mn_get_total(sp_msgmap(ps_global->mail_stream))){ + for(n = first; n <= last; n++) + mm_searched(ps_global->mail_stream, + mn_m2raw(sp_msgmap(ps_global->mail_stream), n)); + } + else + return(peSelectError(interp, "last out of range")); + } + else{ + mm_searched(ps_global->mail_stream, + mn_m2raw(sp_msgmap(ps_global->mail_stream), first)); + } + } + else + return(peSelectError(interp, "first out of range")); + } + else + return(peSelectError(interp, "can't read first/last")); + } + else + return(peSelectError(interp, "num first last")); + + return(TCL_OK); +} + +int +peSelectDate(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + /* + * Args: [broad | narrow] + * tense - "on", "since", "before" + * year - 4 digit year + * month - abbreviated month "jan", "feb"... + * day - day number + */ + + char *tense, *year, *month, *day, buf[256]; + + if(objc == 4){ + if((tense = peSelValTense(objv[0])) != NULL){ + if((year = peSelValYear(objv[1])) != NULL){ + if((month = peSelValMonth(objv[2])) != NULL){ + if((day = peSelValDay(objv[3])) != NULL){ + snprintf(buf, sizeof(buf), "%s %s-%s-%s", tense, day, month, year); + pine_mail_search_full(ps_global->mail_stream, NULL, + mail_criteria(buf), + SE_NOPREFETCH | SE_FREE); + } + else + return(peSelectError(interp, "<with valid day>")); + } + else + return(peSelectError(interp, "<with valid month>")); + } + else + return(peSelectError(interp, "<with valid year>")); + } + else + return(peSelectError(interp, "<with valid tense>")); + } + else + return(peSelectError(interp, "date tense year monthabbrev daynum")); + + return(TCL_OK); +} + +int +peSelectText(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + /* + * Args: [broad | narrow] + * case - in not + * field - to from cc recip partic subj any + * text - free text search string + */ + int not; + char field, *text; + + if(objc == 3){ + if((not = peSelValCase(objv[0])) >= 0){ + if((field = peSelValField(objv[1])) != '\0'){ + if((text = Tcl_GetStringFromObj(objv[2], NULL)) + && strlen(text) < 1024){ + /* BUG: fix charset not to be NULL below */ + if(agg_text_select(ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), + field, NULL, not, 0, text, NULL, NULL)) + /* BUG: plug in "charset" above? */ + return(peSelectError(interp, "programmer botch")); + } + else + return(peSelectError(interp, "<with search string < 1024>")); + } + else + return(peSelectError(interp, "<with valid field>")); + } + else + return(peSelectError(interp, "<with valid case>")); + } + else + return(peSelectError(interp, "text case field text")); + + return(TCL_OK); +} + +int +peSelectStatus(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + /* + * Args: [broad | narrow] + * case - on not + * status - imp new ans del + */ + int not; + char flag; + + if(objc == 2){ + if((not = peSelValCase(objv[0])) >= 0){ + if((flag = peSelValFlag(objv[1])) != '\0'){ + if(agg_flag_select(ps_global->mail_stream, not, flag, NULL)) + return(peSelectError(interp, "programmer botch")); + } + else + return(peSelectError(interp, "<with valid flag>")); + } + else + return(peSelectError(interp, "<with valid case>")); + } + else + return(peSelectError(interp, "status focus case flag")); + + return(TCL_OK); +} + +char * +peSelValTense(Tcl_Obj *objp) +{ + char *tense, **pp; + + if((tense = Tcl_GetStringFromObj(objp, NULL)) != NULL){ + static char *tenses[] = {"on", "since", "before", NULL}; + + for(pp = tenses; *pp; pp++) + if(!strucmp(*pp, tense)) + return(tense); + } + + return(NULL); +} + + +char * +peSelValYear(Tcl_Obj *objp) +{ + char *year; + + return((year = Tcl_GetStringFromObj(objp, NULL)) + && strlen(year) == 4 + && isdigit((unsigned char) year[0]) + && isdigit((unsigned char) year[0]) + && isdigit((unsigned char) year[0]) + ? year + : NULL); +} + + +char * +peSelValMonth(Tcl_Obj *objp) +{ + char *month, **pp; + static char *mons[] = {"jan","feb","mar","apr", + "may","jun","jul","aug", + "sep","oct","nov","dec", NULL}; + + if((month = Tcl_GetStringFromObj(objp, NULL)) && strlen(month) == 3) + for(pp = mons; *pp; pp++) + if(!strucmp(month, *pp)) + return(*pp); + + return(NULL); +} + + +char * +peSelValDay(Tcl_Obj *objp) +{ + char *day; + + return(((day = Tcl_GetStringFromObj(objp, NULL)) + && (day[0] == '0' || day[0] == '1' + || day[0] == '2' || day[0] == '3') + && isdigit((unsigned char) day[1]) + && day[2] == '\0') + ? day + : NULL); +} + + +int +peSelValCase(Tcl_Obj *objp) +{ + char *not; + + if((not = Tcl_GetStringFromObj(objp, NULL)) != NULL){ + if(!strucmp(not, "ton")) + return(0); + else if(!strucmp(not, "not")) + return(1); + } + + return(-1); +} + + +int +peSelValField(Tcl_Obj *objp) +{ + char *field; + int i; + static struct { + char *field; + int type; + } fields[] = {{"from", 'f'}, + {"to", 't'}, + {"cc", 'c'}, + {"subj", 's'}, + {"any", 'a'}, + {"recip", 'r'}, + {"partic", 'p'}, + {"body", 'b'}, + {NULL,0}}; + + if((field = Tcl_GetStringFromObj(objp, NULL)) != NULL) + for(i = 0; fields[i].field ; i++) + if(!strucmp(fields[i].field, field)) + return(fields[i].type); + + return(0); +} + + +int +peSelValFlag(Tcl_Obj *objp) +{ + char *flag; + int i; + static struct { + char *flag; + int type; + } flags[] = {{"imp", '*'}, + {"new", 'n'}, + {"ans", 'a'}, + {"del", 'd'}, + {NULL,0}}; + + if((flag = Tcl_GetStringFromObj(objp, NULL)) != NULL) + for(i = 0; flags[i].flag ; i++) + if(!strucmp(flags[i].flag, flag)) + return(flags[i].type); + + return(0); +} + +int +peSelected(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int matchflag) +{ + int rv = 0; + long i, n; + char *range; + + /* + * CMD: searched [before | after] # + * + * Returns: 1 if criteria is true, 0 otherwise + */ + + if((range = Tcl_GetStringFromObj(objv[0], NULL)) + && Tcl_GetLongFromObj(interp, objv[1], &n) != TCL_ERROR){ + if(!strucmp(range, "before")){ + for(i = 1L; i < n && i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++) + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){ + rv = 1; + break; + } + + Tcl_SetResult(interp, int2string(rv), TCL_STATIC); + return(TCL_OK); + } + else if(!strucmp(range, "after")){ + for(i = n + 1L; i <= mn_get_total(sp_msgmap(ps_global->mail_stream)); i++) + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), i, matchflag)){ + rv = 1; + break; + } + + Tcl_SetResult(interp, int2string(rv), TCL_STATIC); + return(TCL_OK); + } + } + + Tcl_SetResult(interp, "searched test failed", TCL_STATIC); + return(TCL_ERROR); +} + + +int +peSelectError(Tcl_Interp *interp, char *usage) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), "should be select %.128s", usage); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); +} + + +int +peApply(Tcl_Interp *interp, int objc, Tcl_Obj **objv) +{ + char *subcmd; + long n; + + if(!(n = any_lflagged(sp_msgmap(ps_global->mail_stream), MN_SLCT))){ + Tcl_SetResult(interp, "No messages selected", TCL_STATIC); + return(TCL_ERROR); + } + else if((subcmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){ + if(objc == 1){ + if(!strucmp(subcmd, "delete")){ + /* BUG: is CmdWhere arg always right? */ + (void) cmd_delete(ps_global, sp_msgmap(ps_global->mail_stream), MCMD_AGG | MCMD_SILENT, NULL); + Tcl_SetResult(interp, long2string(n), TCL_STATIC); + return(TCL_OK); + } + else if(!strucmp(subcmd, "undelete")){ + (void) cmd_undelete(ps_global, sp_msgmap(ps_global->mail_stream), MCMD_AGG | MCMD_SILENT); + Tcl_SetResult(interp, long2string(n), TCL_STATIC); + return(TCL_OK); + } + } + else if(objc == 2){ + if(!strucmp(subcmd, "count")){ + /* + * Args: flag + */ + char *flagname; + long n, rawno, count = 0; + + if((flagname = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + for(n = 1L; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++){ + rawno = mn_m2raw(sp_msgmap(ps_global->mail_stream), n); + if(get_lflag(ps_global->mail_stream, NULL, rawno, MN_SLCT) + && peIsFlagged(ps_global->mail_stream, + mail_uid(ps_global->mail_stream, rawno), + flagname)){ + count++; + } + } + } + + Tcl_SetResult(interp, long2string(count), TCL_VOLATILE); + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strucmp(subcmd, "flag")){ + /* + * Args: case - on not + * flag - imp new ans del + */ + char flag, *result; + int not; + long flagged; + + if((not = peSelValCase(objv[1])) >= 0){ + if((flag = peSelValFlag(objv[2])) != '\0'){ + result = peApplyFlag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), flag, not, &flagged); + if(!result){ + Tcl_SetResult(interp, int2string(flagged), TCL_VOLATILE); + return(TCL_OK); + } + else + return(peApplyError(interp, result)); + } + else + return(peApplyError(interp, "invalid flag")); + } + else + return(peApplyError(interp, "invalid case")); + } + else if(!strucmp(subcmd, "save")){ + /* + * Args: colid - + * folder - imp new ans del + */ + + int colid, flgs = 0, i; + char *folder, *err; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){ + + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){ + + if(!READONLY_FOLDER(ps_global->mail_stream) + && F_OFF(F_SAVE_WONT_DELETE, ps_global)) + flgs |= SV_DELETE; + + if(colid == 0 && !strucmp(folder, "inbox")) + flgs |= SV_INBOXWOCNTXT; + + i = save(ps_global, ps_global->mail_stream, + cp, folder, sp_msgmap(ps_global->mail_stream), flgs); + + err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem saving"; + + restore_selected(sp_msgmap(ps_global->mail_stream)); + if(err) + return(peApplyError(interp, err)); + + Tcl_SetResult(interp, long2string(i), TCL_VOLATILE); + return(TCL_OK); + } + else + return(peApplyError(interp, "can't select")); + } + else + return(peApplyError(interp, "no folder name")); + } + + return(peApplyError(interp, "bad colid")); + } + else + return(peApplyError(interp, "invalid case")); + } + else if(!strucmp(subcmd, "copy")){ + /* + * Args: colid - + * folder - imp new ans del + */ + + int colid, flgs = 0, i; + char *folder, *err; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){ + + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){ + + if(colid == 0 && !strucmp(folder, "inbox")) + flgs |= SV_INBOXWOCNTXT; + + i = save(ps_global, ps_global->mail_stream, + cp, folder, sp_msgmap(ps_global->mail_stream), flgs); + + err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem copying"; + + restore_selected(sp_msgmap(ps_global->mail_stream)); + if(err) + return(peApplyError(interp, err)); + + Tcl_SetResult(interp, long2string(i), TCL_VOLATILE); + return(TCL_OK); + } + else + return(peApplyError(interp, "can't select")); + } + else + return(peApplyError(interp, "no folder name")); + } + + return(peApplyError(interp, "bad colid")); + } + else + return(peApplyError(interp, "invalid case")); + } + else if(!strucmp(subcmd, "move")){ + /* + * Args: colid - + * folder - imp new ans del + */ + + int colid, flgs = 0, i; + char *folder, *err; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp, objv[1], &colid) != TCL_ERROR){ + + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid){ + if((folder = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(pseudo_selected(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream))){ + + flgs = SV_DELETE; + + if(colid == 0 && !strucmp(folder, "inbox")) + flgs |= SV_INBOXWOCNTXT; + + i = save(ps_global, ps_global->mail_stream, + cp, folder, sp_msgmap(ps_global->mail_stream), flgs); + + err = (i == mn_total_cur(sp_msgmap(ps_global->mail_stream))) ? NULL : "problem moving"; + + restore_selected(sp_msgmap(ps_global->mail_stream)); + if(err) + return(peApplyError(interp, err)); + + Tcl_SetResult(interp, long2string(i), TCL_VOLATILE); + return(TCL_OK); + } + else + return(peApplyError(interp, "can't select")); + } + else + return(peApplyError(interp, "no folder name")); + } + + return(peApplyError(interp, "bad colid")); + } + else + return(peApplyError(interp, "invalid case")); + } + else if(!strucmp(subcmd, "spam")){ + /* + * Args: spamaddr - + * spamsubj - + */ + char *spamaddr, *spamsubj = NULL; + long n, rawno; + + if((spamaddr = Tcl_GetStringFromObj(objv[1], NULL)) + && (spamsubj = Tcl_GetStringFromObj(objv[2], NULL))){ + for(n = 1L; n <= mn_get_total(sp_msgmap(ps_global->mail_stream)); n++){ + rawno = mn_m2raw(sp_msgmap(ps_global->mail_stream), n); + if(get_lflag(ps_global->mail_stream, NULL, rawno, MN_SLCT)){ + char errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL; + + if((rs = peSendSpamReport(rawno, spamaddr, spamsubj, errbuf)) != NULL){ + Tcl_SetResult(interp, rs, TCL_VOLATILE); + return(TCL_ERROR); + } + } + } + } + + Tcl_SetResult(interp, "OK", TCL_VOLATILE); + return(TCL_OK); + } + } + } + + return(peApplyError(interp, "unknown option")); +} + + +char * +peApplyFlag(MAILSTREAM *stream, MSGNO_S *msgmap, char flag, int not, long *flagged) +{ + char *seq, *flagstr; + long flags, flagid; + + switch (flag) { + case '*' : + flagstr = "\\FLAGGED"; + flags = not ? 0L : ST_SET; + flagid = not ? F_FLAG : F_UNFLAG; + break; + case 'n' : + flagstr = "\\SEEN"; + flags = not ? ST_SET : 0L; + flagid = not ? F_UNSEEN : F_SEEN; + break; + case 'a' : + flagstr = "\\ANSWERED"; + flags = not ? 0L : ST_SET; + flagid = not ? F_ANS : F_UNANS; + break; + case 'd': + flagstr = "\\DELETED"; + flags = not ? 0L : ST_SET; + flagid = not ? F_DEL : F_UNDEL; + break; + default : + return("unknown flag"); + break; + } + + if(pseudo_selected(stream, msgmap)){ + if((seq = currentf_sequence(stream, msgmap, flagid, flagged, 1, NULL, NULL)) != NULL){ + mail_flag(stream, seq, flagstr, flags); + fs_give((void **) &seq); + } + + restore_selected(msgmap); + return(NULL); + } + else + return("can't select"); +} + + +int +peApplyError(Tcl_Interp *interp, char *usage) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), "apply error: %.128s", usage); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); +} + + +/* + * peIndexFormat - Return with interp's result object set to + * represent the index line's format as a list of + * index-field-name, percentage-width pairs + */ +int +peIndexFormat(Tcl_Interp *interp) +{ + INDEX_COL_S *cdesc = NULL; + char *name, wbuf[4], *dname; + + for(cdesc = ps_global->index_disp_format; + cdesc->ctype != iNothing; + cdesc++) { + dname = NULL; + switch(cdesc->ctype){ + case iFStatus: + case iIStatus: + case iSIStatus: + dname = "iStatus"; + case iStatus: + name = "Status"; + break; + + case iMessNo: + name = "Number"; + break; + + case iPrio: + case iPrioAlpha: + case iPrioBang: + name = "Priority"; + break; + + case iDate: case iSDate: case iSTime: case iLDate: + case iS1Date: case iS2Date: case iS3Date: case iS4Date: case iDateIso: + case iDateIsoS: + case iSDateIso: case iSDateIsoS: + case iSDateS1: case iSDateS2: + case iSDateS3: case iSDateS4: + case iSDateTime: + case iSDateTimeIso: case iSDateTimeIsoS: + case iSDateTimeS1: case iSDateTimeS2: + case iSDateTimeS3: case iSDateTimeS4: + case iSDateTime24: + case iSDateTimeIso24: case iSDateTimeIsoS24: + case iSDateTimeS124: case iSDateTimeS224: + case iSDateTimeS324: case iSDateTimeS424: + case iCurDate: case iCurDateIso: case iCurDateIsoS: + case iCurTime24: case iCurTime12: + case iCurPrefDate: + name = "Date"; + break; + + case iCurDay: case iCurDay2Digit: + case iCurDayOfWeek: case iCurDayOfWeekAbb: + name = "Day"; + break; + + case iCurMon: case iCurMon2Digit: + case iCurMonLong: case iCurMonAbb: + name= "Month"; + break; + + case iTime24: case iTime12: case iTimezone: + case iCurPrefTime: + name = "Time"; + break; + + case iDay2Digit: case iDayOfWeek: case iDayOfWeekAbb: + name = "Day"; + break; + + case iMonAbb: case iMon2Digit: + name = "Month"; + break; + + case iYear: case iYear2Digit: + case iCurYear: case iCurYear2Digit: + name = "Year"; + break; + + case iScore : + name = "Score"; + break; + + case iFromTo: + case iFromToNotNews: + case iFrom: + name = "From"; + break; + + case iTo: + case iToAndNews : + name = "To"; + break; + + case iCc: + name = "Cc"; + break; + + case iRecips: + name = "Recipients"; + break; + + case iSender: + name = "Sender"; + break; + + case iSize : + case iSizeComma : + case iSizeNarrow : + case iDescripSize: + case iKSize : + name = "Size"; + break; + + case iAtt: + name = "Attachments"; + break; + + case iAddress : + name = "Address"; + break; + + case iMailbox : + name = "Mailbox"; + break; + + case iSubject : + case iSubjKey : + case iSubjKeyInit : + case iSubjectText : + case iSubjKeyText : + case iSubjKeyInitText : + name = "Subject"; + break; + + case iNews: + case iNewsAndTo : + name = "News"; + break; + + case iNewsAndRecips: + name = "News/Recip"; + break; + + case iRecipsAndNews: + name = "Recip/News"; + break; + + default : + name = ""; + break; + } + + if(cdesc->width > 0){ + int p = ((cdesc->width * 100) / FAKE_SCREEN_WIDTH); + + snprintf(wbuf, sizeof(wbuf), "%d%%", p); + } + else + wbuf[0] = '\0'; + + if(peAppListF(interp, Tcl_GetObjResult(interp), "%s%s%s", name, wbuf, dname) != TCL_OK) + return(TCL_ERROR); + } + + return(TCL_OK); +} + + +int +peNewMailResult(Tcl_Interp *interp) +{ + unsigned long n, uid; + + if(sp_mail_box_changed(ps_global->mail_stream)){ + if((n = sp_mail_since_cmd(ps_global->mail_stream)) != 0L){ + /* first element is count of new messages */ + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewLongObj(n)) != TCL_OK) + return(TCL_ERROR); + + /* second element is UID of most recent message */ + for(uid = ps_global->mail_stream->nmsgs; uid > 1L; uid--) + if(!get_lflag(ps_global->mail_stream, NULL, uid, MN_EXLD)) + break; + + if(!uid){ + Tcl_ResetResult(interp); + Tcl_SetResult(interp, "0 0 0", TCL_STATIC); + return(TCL_ERROR); + } + + uid = mail_uid(ps_global->mail_stream, uid); + + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewLongObj(uid)) != TCL_OK) + return(TCL_ERROR); + } + else { + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewIntObj(0)) != TCL_OK) + return(TCL_ERROR); + + /* zero is UID of new message */ + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewIntObj(0)) != TCL_OK) + return(TCL_ERROR); + } + + /* third element is expunge count */ + if(Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewLongObj(sp_expunge_count(ps_global->mail_stream) + ? sp_expunge_count(ps_global->mail_stream) + : 0L)) != TCL_OK) + return(TCL_ERROR); + + } + else + Tcl_SetResult(interp, "0 0 0", TCL_STATIC); + + return(TCL_OK); +} + + +/* * * * * * * * Start of Per-Thread/SubThread access functions * * * * * * * */ + + +/* + * PEThreadCmd - access/manipulate various pieces of thread state + */ +int +PEThreadCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err, errbuf[256], *cmd, *op; + imapuid_t uid; + + dprint((2, "PEThreadCmd")); + + snprintf(err = errbuf, sizeof(errbuf), "Unknown %s request", + Tcl_GetStringFromObj(objv[0], NULL)); + + if(!(ps_global && ps_global->mail_stream)){ + snprintf(err = errbuf, sizeof(errbuf), "%s: No open mailbox", + Tcl_GetStringFromObj(objv[0], NULL)); + } + else if(objc < 2){ + Tcl_WrongNumArgs(interp, 1, objv, "uid cmd ?args?"); + } + else if(Tcl_GetLongFromObj(interp, objv[1], &uid) != TCL_OK){ + return(TCL_ERROR); /* conversion problem? */ + } + else if(!peSequenceNumber(uid)){ + snprintf(err = errbuf, sizeof(errbuf), "%s: UID %ld doesn't exist", + Tcl_GetStringFromObj(objv[0], NULL), uid); + } + else if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(objc == 3){ + if(!strucmp(cmd,"info")){ +#define WP_MAX_THRD_PREFIX 256 + long raw; + PINETHRD_S *pthrd; + char tstr[WP_MAX_THRD_PREFIX]; + + if((raw = peSequenceNumber(uid)) != 0L){ + /* + * translate PINETHRD_S data into + */ + if((pthrd = msgno_thread_info(ps_global->mail_stream, raw, NULL, THD_TOP)) != NULL){ + + tstr[0] = '\0'; +/* BUG: build tstr form pthrd */ + + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(tstr, -1)); + } + } + else + Tcl_SetResult(interp, "0", TCL_STATIC); + + return(TCL_OK); + } + + } + else if(objc == 5){ + if(!strucmp(cmd,"flag")){ + if((op = Tcl_GetStringFromObj(objv[3], NULL)) != NULL){ + if(!strucmp(op,"deleted")){ + int value; + + if(Tcl_GetIntFromObj(interp, objv[4], &value) != TCL_ERROR){ + long n; + PINETHRD_S *pthrd; + char *flag; + + while(1){ + if(!(n = peSequenceNumber(uid))){ + Tcl_SetResult(interp, "Unrecognized UID", TCL_STATIC); + return(TCL_ERROR); + } + + flag = cpystr("\\DELETED"); + mail_flag(ps_global->mail_stream, long2string(n), flag, (value ? ST_SET : 0L)); + fs_give((void **) &flag); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(ulong2string(uid), -1)); + + if(++n <= ps_global->mail_stream->nmsgs){ + uid = mail_uid(ps_global->mail_stream, n); + } + else + break; + + if((pthrd = msgno_thread_info(ps_global->mail_stream, n, NULL,THD_TOP)) != NULL){ + } + else + break; + } + } + } + } + } + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + + +/* * * * * * * * Start of Per-Message access functions * * * * * * * */ + + + +static struct _message_cmds { + char *cmd; + int hcount; + struct { + int argcount; + int (*f)(Tcl_Interp *, imapuid_t, int, Tcl_Obj **); + } h[3]; +} message_cmds[] = { + {"size", 1, {{3, peMessageSize}}}, + {"date", 2, {{3, peMessageDate}, {4, peMessageDate}}}, + {"subject", 1, {{3, peMessageSubject}}}, + {"fromaddr", 1, {{3, peMessageFromAddr}}}, + {"toaddr", 1, {{3, peMessageToAddr}}}, + {"ccaddr", 1, {{3, peMessageCcAddr}}}, + {"status", 1, {{3, peMessageStatus}}}, + {"statusbits", 1, {{3, peMessageStatusBits}}}, + {"charset", 1, {{3, peMessageCharset}}}, + {"number", 1, {{3, peMsgnoFromUID}}}, + {"envelope", 0}, + {"rawenvelope", 0}, + {"text", 1, {{3, peMessageText}}}, + {"header", 1, {{3, peMessageHeader}}}, + {"attachments", 1, {{3, peMessageAttachments}}}, + {"body", 3, {{3, peMessageBody}, {4, peMessageBody}}}, + {"cid", 1, {{4, peMessagePartFromCID}}}, + {"flag", 2, {{4, peGetFlag}, {5, peSetFlag}}}, + {"replyheaders", 2, {{3, peReplyHeaders},{4, peReplyHeaders}}}, + {"replytext", 2, {{4, peReplyText}, {5, peReplyText}}}, + {"forwardheaders", 2, {{3, peForwardHeaders}, {4, peForwardHeaders}}}, + {"forwardtext", 2, {{3, peForwardText}, {4, peForwardText}}}, + {"rawbody", 0}, + {"select", 2, {{3, peMsgSelect}, {4, peMsgSelect}}}, + {"detach", 1, {{5, peDetach}}}, + {"attachinfo", 1, {{4, peAttachInfo}}}, + {"savedefault", 1, {{3, peSaveDefault}}}, + {"save", 1, {{5, peSave}}}, + {"copy", 1, {{5, peCopy}}}, + {"move", 1, {{5, peMove}}}, + {"takeaddr", 1, {{3, peTakeaddr}}}, + {"takefrom", 1, {{3, peTakeFrom}}}, + {"replyquote", 1, {{3, peReplyQuote}}}, + {"bounce", 2, {{4, peMessageBounce},{5, peMessageBounce}}}, + {"spam", 1, {{5, peMessageSpamNotice}}}, + {"needpasswd", 1, {{3, peMessageNeedPassphrase}}}, + {NULL, 0} +}; + + + + +/* + * PEMessageCmd - export various bits of message information + * + * NOTE: all exported commands are of the form: + * + * PEMessage <uid> <cmd> <args> + */ +int +PEMessageCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err, errbuf[256], *cmd; + int i, j; + imapuid_t uid; + + dprint((5, "PEMessageCmd")); + + snprintf(err = errbuf, sizeof(errbuf), "Unknown %s request", + Tcl_GetStringFromObj(objv[0], NULL)); + + if(!(ps_global && ps_global->mail_stream)){ + snprintf(err = errbuf, sizeof(errbuf), "%s: No open mailbox", + Tcl_GetStringFromObj(objv[0], NULL)); + } + else if(objc < 3){ + Tcl_WrongNumArgs(interp, 0, objv, "PEMessage <uid> cmd ?args?"); + } + else if(Tcl_GetLongFromObj(interp, objv[1], &uid) != TCL_OK){ + return(TCL_ERROR); /* conversion problem? */ + } + else if(!peMessageNumber(uid)){ + snprintf(err = errbuf, sizeof(errbuf), "%s: UID %ld doesn't exist", + Tcl_GetStringFromObj(objv[0], NULL), uid); + } + else if((cmd = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + for(i = 0; message_cmds[i].cmd; i++) + if(!strcmp(cmd, message_cmds[i].cmd)){ + for(j = 0; j < message_cmds[i].hcount; j++) + if(message_cmds[i].h[j].argcount == objc) + return((*message_cmds[i].h[j].f)(interp, uid, objc - 3, + &((Tcl_Obj **)objv)[3])); + + snprintf(err = errbuf, sizeof(errbuf), + "PEMessage: %s: mismatched argument count", cmd); + break; + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +/* + * return the uid's ordinal number within the CURRENT SORT + */ +long +peMessageNumber(imapuid_t uid) +{ + return(mn_raw2m(sp_msgmap(ps_global->mail_stream), peSequenceNumber(uid))); +} + +/* + * return the uid's RAW message number (for c-client reference, primarily) + */ +long +peSequenceNumber(imapuid_t uid) +{ + return(mail_msgno(ps_global->mail_stream, uid)); +} + + +int +peMessageSize(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + long raw; + + if((raw = peSequenceNumber(uid)) + && pine_mail_fetchstructure(ps_global->mail_stream, raw, NULL)){ + Tcl_SetResult(interp, + long2string(mail_elt(ps_global->mail_stream, + raw)->rfc822_size), + TCL_VOLATILE); + } + else + Tcl_SetResult(interp, "0", TCL_STATIC); + + return(TCL_OK); +} + + +int +peMessageDate(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *cmd; + long raw; + ENVELOPE *env; + MESSAGECACHE mc; + + if((raw = peSequenceNumber(uid)) + && (env = pine_mail_fetchstructure(ps_global->mail_stream, raw, NULL))){ + if(objc == 1 && objv[0]){ + if(mail_parse_date(&mc, env->date)){ + if((cmd = Tcl_GetStringFromObj(objv[0], NULL)) != NULL){ + if(!strucmp(cmd,"day")){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%02d", mc.day); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(cmd,"month")){ + Tcl_SetResult(interp, month_abbrev(mc.month), TCL_VOLATILE); + return(TCL_OK); + } + else if(!strucmp(cmd,"year")){ + Tcl_SetResult(interp, int2string(mc.year + BASEYEAR), TCL_VOLATILE); + return(TCL_OK); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "peMessageDate cmd: %.20s", cmd); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + } + } + else + Tcl_SetResult(interp, "peMessageDate: can't get command", TCL_STATIC); + } + else + Tcl_SetResult(interp, "peMessageDate: can't parse date", TCL_STATIC); + } + else{ + Tcl_SetResult(interp, env->date ? (char *) env->date : "", TCL_VOLATILE); + return(TCL_OK); + } + } + else + Tcl_SetResult(interp, "Can't get message structure", TCL_STATIC); + + return(TCL_ERROR); +} + + +int +peMessageFromAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peMessageField(interp, uid, "from")); +} + + +int +peMessageToAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peMessageField(interp, uid, "to")); +} + + +int +peMessageCcAddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peMessageField(interp, uid, "cc")); +} + + +int +peMessageSubject(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peMessageField(interp, uid, "subject")); +} + + +int +peMessageField(Tcl_Interp *interp, imapuid_t uid, char *field) +{ + long raw; + char *s = ""; + ENVELOPE *env; + + if((raw = peSequenceNumber(uid)) + && (env = pine_mail_fetchstructure(ps_global->mail_stream, raw, NULL))){ + if(!strucmp(field, "from")){ + if(env->from && env->from->mailbox) + snprintf(s = tmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->from->mailbox, + (env->from->host) ? "@" : "", (env->from->host) ? env->from->host : ""); + } + else if(!strucmp(field, "to")){ + if(env->to && env->to->mailbox) + snprintf(s = tmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->to->mailbox, + (env->to->host) ? "@" : "", (env->to->host) ? env->to->host : ""); + } + else if(!strucmp(field, "cc")){ + if(env->cc && env->cc->mailbox) + snprintf(s = tmp_20k_buf, SIZEOF_20KBUF, "%.256s%s%.256s", env->cc->mailbox, + (env->cc->host) ? "@" : "", (env->cc->host) ? env->cc->host : ""); + } + else if(!strucmp(field, "subject")){ + if(env->subject) + snprintf(s = tmp_20k_buf, SIZEOF_20KBUF, "%.256s", env->subject); + } + else{ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Unknown message field: %.20s", field); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + Tcl_SetResult(interp, s, TCL_VOLATILE); + return(TCL_OK); + } + + Tcl_SetResult(interp, "Can't read message envelope", TCL_STATIC); + return(TCL_ERROR); +} + + +int +peMessageStatus(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + long raw; + MESSAGECACHE *mc; + + if((raw = peSequenceNumber(uid)) != 0L){ + if(!((mc = mail_elt(ps_global->mail_stream, raw)) + && mc->valid)){ + mail_fetch_flags(ps_global->mail_stream, + ulong2string(uid), FT_UID); + mc = mail_elt(ps_global->mail_stream, raw); + } + + if (mc->deleted) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj("Deleted", -1)); + + if (mc->answered) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj("Answered", -1)); + + if (!mc->seen) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj("New", -1)); + + if (mc->flagged) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj("Important", -1)); + } + + return(TCL_OK); +} + + +int +peMessageCharset(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + /* everthing coming out of pith better be utf-8 */ + Tcl_SetResult(interp, "UTF-8", TCL_STATIC); + return(TCL_OK); +} + + +int +peMessageNeedPassphrase(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ +#ifdef SMIME + return((ps_global && ps_global->smime && ps_global->smime->need_passphrase) ? TCL_OK : TCL_ERROR); +#else + return(TCL_ERROR); +#endif /* SMIME */ +} + + +int +peMsgnoFromUID(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + Tcl_SetResult(interp, long2string(peMessageNumber(uid)), TCL_VOLATILE); + return(TCL_OK); +} + + +/* + * peInterpWritec - collect filtered output, appending to the + * command's result list on each EOL + */ +int +peInterpWritec(int c) +{ + unsigned char ch = (unsigned char) (0xff & c); + + if(ch == '\n') + return(peInterpFlush() == TCL_OK); + else + so_writec(ch, peED.store); + + return(1); +} + + +/* + * peInterpFlush - write accumulated line to result object mapping + * embedded data into exportable tcl list members + * + */ +int +peInterpFlush(void) +{ + char *line, *p, *tp, *tp2, col1[32], col2[32]; + Tcl_Obj *lobjp, *objColor, *objPair; + + line = (char *) so_text(peED.store); + + if((lobjp = Tcl_NewListObj(0, NULL)) != NULL){ + if((p = strindex(line, TAG_EMBED)) != NULL){ + do{ + *p = '\0'; + + if(p - line) + peAppListF(peED.interp, lobjp, "%s%s", "t", line); + + switch(*++p){ + case TAG_HANDLE : + { + int i, n; + HANDLE_S *h; + + + for(n = 0, i = *++p; i > 0; i--) + n = (n * 10) + (*++p - '0'); + + line = ++p; /* prepare for next section of line */ + + if(!peED.inhandle){ + peED.inhandle = 1; + + if((h = get_handle(peED.handles, n)) != NULL) + switch(h->type){ + case IMG : + { + Tcl_Obj *llObj, *rObj; + + llObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, llObj, Tcl_NewStringObj("img", -1)); + + rObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.img.src ? h->h.img.src : "", -1)); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.img.alt ? h->h.img.alt : "", -1)); + + Tcl_ListObjAppendElement(peED.interp, llObj, rObj); + + Tcl_ListObjAppendElement(peED.interp, lobjp, llObj); + peED.inhandle = 0; + } + + break; + + case URL : + { + Tcl_Obj *llObj, *rObj; + + llObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, llObj, Tcl_NewStringObj("urlstart", -1)); + + rObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.url.path ? h->h.url.path : "", -1)); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.url.name ? h->h.url.name : "", -1)); + + Tcl_ListObjAppendElement(peED.interp, llObj, rObj); + + Tcl_ListObjAppendElement(peED.interp, lobjp, llObj); + } + + break; + + case Attach : + { + Tcl_Obj *alObj, *rObj, *tObj, *stObj, *fnObj, *eObj; + + alObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, alObj, Tcl_NewStringObj("attach", -1)); + + peGetMimeTyping(mail_body(ps_global->mail_stream, + peSequenceNumber(peED.uid), + (unsigned char *) h->h.attach->number), + &tObj, &stObj, &fnObj, &eObj); + + + rObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewLongObj(peED.uid)); + Tcl_ListObjAppendElement(peED.interp, rObj, Tcl_NewStringObj(h->h.attach->number, -1)); + Tcl_ListObjAppendElement(peED.interp, rObj, tObj); + Tcl_ListObjAppendElement(peED.interp, rObj, stObj); + Tcl_ListObjAppendElement(peED.interp, rObj, fnObj); + Tcl_ListObjAppendElement(peED.interp, rObj, eObj); + + Tcl_ListObjAppendElement(peED.interp, alObj, rObj); + + Tcl_ListObjAppendElement(peED.interp, lobjp, alObj); + } + + break; + + default : + break; + } + } + } + + break; + + case TAG_FGCOLOR : + if((tp = peColorStr(++p, col1)) && (strcmp(tp, peED.color.fg) || strcmp(tp, peED.color.fgdef))){ + /* look ahead */ + if(p[11] == TAG_EMBED + && p[12] == TAG_BGCOLOR + && (tp2 = peColorStr(p + 13, col2))){ + objColor = Tcl_NewListObj(0, NULL); + objPair = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp2, -1)); + Tcl_ListObjAppendElement(peED.interp, objColor, objPair); + Tcl_ListObjAppendElement(peED.interp, lobjp, objColor); + strcpy(peED.color.bg, tp2); + p += 13; + } + else if(strcmp(peED.color.bg, peED.color.bgdef)){ + objColor = Tcl_NewListObj(0, NULL); + objPair = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(peED.color.bgdef, -1)); + Tcl_ListObjAppendElement(peED.interp, objColor, objPair); + Tcl_ListObjAppendElement(peED.interp, lobjp, objColor); + strcpy(peED.color.bg, peED.color.bgdef); + } + else + peAppListF(peED.interp, lobjp, "%s%s", "fgcolor", tp); + + strcpy(peED.color.fg, tp); + } + + line = p + 11; + break; + + case TAG_BGCOLOR : + if((tp = peColorStr(++p, col1)) && (strcmp(tp, peED.color.bg) || strcmp(tp, peED.color.bgdef))){ + /* look ahead */ + if(p[11] == TAG_EMBED + && p[12] == TAG_FGCOLOR + && (tp2 = peColorStr(p + 13, col2))){ + objColor = Tcl_NewListObj(0, NULL); + objPair = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp2, -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1)); + Tcl_ListObjAppendElement(peED.interp, objColor, objPair); + Tcl_ListObjAppendElement(peED.interp, lobjp, objColor); + strcpy(peED.color.fg, tp2); + p += 13; + } + else if(strcmp(peED.color.fg, peED.color.fgdef)){ + objColor = Tcl_NewListObj(0, NULL); + objPair = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(peED.interp, objColor, Tcl_NewStringObj("color", -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(peED.color.fgdef, -1)); + Tcl_ListObjAppendElement(peED.interp, objPair, Tcl_NewStringObj(tp, -1)); + Tcl_ListObjAppendElement(peED.interp, objColor, objPair); + Tcl_ListObjAppendElement(peED.interp, lobjp, objColor); + strcpy(peED.color.fg, peED.color.fgdef); + } + else + peAppListF(peED.interp, lobjp, "%s%s", "bgcolor", tp); + + strcpy(peED.color.bg, tp); + } + + line = p + 11; + break; + + case TAG_ITALICON : + peAppListF(peED.interp, lobjp, "%s%s", "italic", "on"); + line = p + 1; + break; + + case TAG_ITALICOFF : + peAppListF(peED.interp, lobjp, "%s%s", "italic", "off"); + line = p + 1; + break; + + case TAG_BOLDON : + peAppListF(peED.interp, lobjp, "%s%s", "bold", "on"); + line = p + 1; + break; + + case TAG_BOLDOFF : + peAppListF(peED.interp, lobjp, "%s%s", "bold", "off"); + line = p + 1; + break; + + case TAG_ULINEON : + peAppListF(peED.interp, lobjp, "%s%s", "underline", "on"); + line = p + 1; + break; + + case TAG_ULINEOFF : + peAppListF(peED.interp, lobjp, "%s%s", "underline", "off"); + line = p + 1; + break; + + case TAG_STRIKEON : + peAppListF(peED.interp, lobjp, "%s%s", "strikethru", "on"); + line = p + 1; + break; + + case TAG_STRIKEOFF : + peAppListF(peED.interp, lobjp, "%s%s", "strikethru", "off"); + line = p + 1; + break; + + case TAG_BIGON : + peAppListF(peED.interp, lobjp, "%s%s", "bigfont", "on"); + line = p + 1; + break; + + case TAG_BIGOFF : + peAppListF(peED.interp, lobjp, "%s%s", "bigfont", "off"); + line = p + 1; + break; + + case TAG_SMALLON : + peAppListF(peED.interp, lobjp, "%s%s", "smallfont", "on"); + line = p + 1; + break; + + case TAG_SMALLOFF : + peAppListF(peED.interp, lobjp, "%s%s", "smallfont", "off"); + line = p + 1; + break; + + case TAG_INVOFF : + case TAG_HANDLEOFF : + if(peED.inhandle){ + peAppListF(peED.interp, lobjp, "%s%s", "urlend", ""); + peED.inhandle = 0; + } + /* fall thru and advance "line" */ + + default : + line = p + 1; + break; + } + + } + while((p = strindex(line, TAG_EMBED)) != NULL); + + if(*line) + peAppListF(peED.interp, lobjp, "%s%s", "t", line); + } + else + peAppListF(peED.interp, lobjp, "%s%s", "t", line); + } + else + peAppListF(peED.interp, lobjp, "%s%s", "t", ""); + + if(Tcl_ListObjAppendElement(peED.interp, peED.obj, lobjp) == TCL_OK){ + so_truncate(peED.store, 0L); + return(TCL_OK); + } + + return(TCL_ERROR); +} + + + +/* + * peInterpWritec - collect filtered output, appending to the + * command's result list on each EOL + */ +int +peNullWritec(int c) +{ + return(1); +} + + +char * +peColorStr(char *s, char *b) +{ + int i, j, color; + + i = 0; + b[0] = '\0'; + while(1){ + color = 0; + for(j = 0; j < 3; j++, s++) + if(isdigit((unsigned char) *s)) + color = (color * 10) + (*s - '0'); + + s++; /* advance past ',' */ + if(color < 256) + sprintf(b + strlen(b), "%2.2x", color); + else + break; + + if(++i == 3) + return(b); + } + + + return(NULL); +} + + +/* + * returns a list of elements + */ +int +peMessageHeader(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + MESSAGECACHE *mc; + HEADER_S h; + int flags, rv = TCL_OK; + long raw; +#if 0 + char *color; +#endif + + /* + * ONLY full header mode (raw) output should get written to the + * writec function we pass format_header. If there's something + * in the store after formatting ,we'll write it to the Tcl result + * then, not as its accumulated + */ + peED.interp = interp; + peED.obj = Tcl_NewStringObj("", -1); + + if(peED.store) + so_seek(peED.store, 0L, 0); + else + peED.store = so_get(CharStar, NULL, EDIT_ACCESS); + + flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED; + +#if 0 + peED.color.fg[0] = '\0'; + if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_FGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.fgdef, peColorStr(color, tmp_20k_buf)); + } + + peED.color.bg[0] = '\0'; + if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_BGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.bgdef, peColorStr(color,tmp_20k_buf)); + } + + peInterpFlush(); +#endif + + raw = peSequenceNumber(uid); + if(peED.uid != uid){ + peED.uid = uid; + peED.body = NULL; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + if(!((peED.env = pine_mail_fetchstructure(ps_global->mail_stream, raw, &peED.body)) + && (mc = mail_elt(ps_global->mail_stream, raw)))){ + char buf[256]; + + snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"); + + dprint((1, "ERROR fetching %s of msg %ld: %s", + peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate")); + + Tcl_SetResult(interp, buf, TCL_VOLATILE); + rv = TCL_ERROR; + } + else{ + zero_atmts(ps_global->atmts); +#ifdef SMIME + if(ps_global && ps_global->smime && ps_global->smime->need_passphrase) + ps_global->smime->need_passphrase = 0; + + fiddle_smime_message(peED.body, raw); +#endif + describe_mime(peED.body, "", 1, 1, 0, flags); + } + } + + /* NO HANDLES init_handles(&peED.handles);*/ + + /* + * Collect header pieces into lists via the passed custom formatter. Collect + * everything else in the storage object passed. The latter should only end up + * with raw header data. + * + * BUG: DEAL WITH COLORS + */ + if(rv == TCL_OK){ + HD_INIT(&h, ps_global->VAR_VIEW_HEADERS, ps_global->view_all_except, FE_DEFAULT); + if(format_header(ps_global->mail_stream, raw, NULL, peED.env, &h, + NULL, NULL, flags, peFormatEnvelope, peInterpWritec) != 0){ + char buf[256]; + + snprintf(buf, sizeof(buf), "Error formatting header %ld", peMessageNumber(uid)); + dprint((1, buf)); + + Tcl_SetResult(interp, buf, TCL_VOLATILE); + rv = TCL_ERROR; + } + } + + peInterpFlush(); + peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%o", "raw", "", peED.obj); + + so_give(&peED.store); + return(rv); +} + +void +peFormatEnvelope(MAILSTREAM *s, long int n, char *sect, ENVELOPE *e, gf_io_t pc, long int which, char *oacs, int flags) +{ + char *p2, buftmp[MAILTMPLEN]; + Tcl_Obj *objHdr; + + if(!e) + return; + + if((which & FE_DATE) && e->date) { + if((objHdr = Tcl_NewListObj(0, NULL)) != NULL){ + snprintf(buftmp, sizeof(buftmp), "%s", (char *) e->date); + buftmp[sizeof(buftmp)-1] = '\0'; + p2 = (char *)rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, buftmp); + peFormatEnvelopeText("Date", p2); + } + /* BUG: how does error feedback bubble back up? */ + } + + if((which & FE_FROM) && e->from) + peFormatEnvelopeAddress(s, n, sect, "From", e->from, flags, oacs, pc); + + if((which & FE_REPLYTO) && e->reply_to && (!e->from || !address_is_same(e->reply_to, e->from))) + peFormatEnvelopeAddress(s, n, sect, "Reply-To", e->reply_to, flags, oacs, pc); + + if((which & FE_TO) && e->to) + peFormatEnvelopeAddress(s, n, sect, "To", e->to, flags, oacs, pc); + + if((which & FE_CC) && e->cc) + peFormatEnvelopeAddress(s, n, sect, "Cc", e->cc, flags, oacs, pc); + + if((which & FE_BCC) && e->bcc) + peFormatEnvelopeAddress(s, n, sect, "Bcc", e->bcc, flags, oacs, pc); + + if((which & FE_RETURNPATH) && e->return_path) + peFormatEnvelopeAddress(s, n, sect, "Return-Path", e->return_path, flags, oacs, pc); + + if((which & FE_NEWSGROUPS) && e->newsgroups) + peFormatEnvelopeNewsgroups("Newsgroups", e->newsgroups, flags, pc); + + if((which & FE_FOLLOWUPTO) && e->followup_to) + peFormatEnvelopeNewsgroups("Followup-To", e->followup_to, flags, pc); + + if((which & FE_SUBJECT) && e->subject && e->subject[0]){ + if((objHdr = Tcl_NewListObj(0, NULL)) != NULL){ + char *freeme = NULL; + + p2 = iutf8ncpy((char *)(tmp_20k_buf+10000), + (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, 10000, e->subject), + SIZEOF_20KBUF-10000); + + if(flags & FM_DISPLAY + && (ps_global->display_keywords_in_subject + || ps_global->display_keywordinits_in_subject)){ + + /* don't bother if no keywords are defined */ + if(some_user_flags_defined(s)) + p2 = freeme = prepend_keyword_subject(s, n, p2, + ps_global->display_keywords_in_subject ? KW : KWInit, + NULL, ps_global->VAR_KW_BRACES); + } + + peFormatEnvelopeText("Subject", p2); + + if(freeme) + fs_give((void **) &freeme); + } + } + + if((which & FE_SENDER) && e->sender && (!e->from || !address_is_same(e->sender, e->from))) + peFormatEnvelopeAddress(s, n, sect, "Sender", e->sender, flags, oacs, pc); + + if((which & FE_MESSAGEID) && e->message_id){ + p2 = iutf8ncpy((char *)(tmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, 10000, e->message_id), SIZEOF_20KBUF-10000); + peFormatEnvelopeText("Message-ID", p2); + } + + if((which & FE_INREPLYTO) && e->in_reply_to){ + p2 = iutf8ncpy((char *)(tmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, 10000, e->in_reply_to), SIZEOF_20KBUF-10000); + peFormatEnvelopeText("In-Reply-To", p2); + } + + if((which & FE_REFERENCES) && e->references) { + p2 = iutf8ncpy((char *)(tmp_20k_buf+10000), (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, 10000, e->references), SIZEOF_20KBUF-10000); + peFormatEnvelopeText("References", p2); + } +} + + +/* + * appends caller's result with: {"text" field_name {field_value}} + */ +void +peFormatEnvelopeText(char *field_name, char *field_value) +{ + peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%s", "text", field_name, field_value); +} + + +/* + * appends caller's result with: {"addr" field_name {{{personal} {mailbox}} ... }} + * {"rawaddr" field_name {{raw_address} ... }} + */ +void +peFormatEnvelopeAddress(MAILSTREAM *stream, long int msgno, char *section, char *field_name, + struct mail_address *addr, int flags, char *oacs, gf_io_t pc) +{ + char *ptmp, *mtmp, *atype = "addr"; + int group = 0; + ADDRESS *atmp; + Tcl_Obj *objAddrList = NULL; + STORE_S *tso; + gf_io_t tpc; + extern const char *rspecials; + extern const char *rspecials_minus_quote_and_dot; + + if(!addr) + return; + + /* + * quickly run down address list to make sure none are patently bogus. + * If so, just blat raw field out. + */ + for(atmp = addr; stream && atmp; atmp = atmp->next) + if(atmp->host && atmp->host[0] == '.'){ + char *field, *fields[2]; + + atype = "rawaddr"; + if((objAddrList = Tcl_NewListObj(0,NULL)) == NULL) + return; /* BUG: handle list creation failure */ + + fields[1] = NULL; + fields[0] = cpystr(field_name); + if((ptmp = strchr(fields[0], ':')) != NULL) + *ptmp = '\0'; + + if((field = pine_fetchheader_lines(stream, msgno, section, fields)) != NULL){ + char *h, *t; + + for(t = h = field; *h ; t++) + if(*t == '\015' && *(t+1) == '\012'){ + *t = '\0'; /* tie off line */ + + Tcl_ListObjAppendElement(peED.interp, objAddrList, Tcl_NewStringObj(h,-1)); + + if(!*(h = (++t) + 1)) /* set new h and skip CRLF */ + break; /* no more to write */ + } + else if(!*t){ /* shouldn't happen much */ + if(h != t) + Tcl_ListObjAppendElement(peED.interp, objAddrList, Tcl_NewStringObj(h,-1)); + + break; + } + + fs_give((void **)&field); + } + + fs_give((void **)&fields[0]); + } + + if(!objAddrList){ + if((objAddrList = Tcl_NewListObj(0,NULL)) == NULL || (tso = so_get(CharStar, NULL, EDIT_ACCESS)) == NULL) + return; /* BUG: handle list creation failure */ + + gf_set_so_writec(&tpc, tso); + + while(addr){ + + atmp = addr->next; /* remember what's next */ + addr->next = NULL; + if(!addr->host && addr->mailbox){ + mtmp = addr->mailbox; + addr->mailbox = cpystr((char *)rfc1522_decode_to_utf8( + (unsigned char *)tmp_20k_buf, + SIZEOF_20KBUF, addr->mailbox)); + } + + ptmp = addr->personal; /* RFC 1522 personal name? */ + addr->personal = iutf8ncpy((char *)tmp_20k_buf, (char *)rfc1522_decode_to_utf8((unsigned char *)(tmp_20k_buf+10000), SIZEOF_20KBUF-10000, addr->personal), 10000); + tmp_20k_buf[10000-1] = '\0'; + + + /* Logic taken from: pine_rfc822_write_address_noquote(addr, pc, &group); */ + if (addr->host) { /* ordinary address? */ + if (!(addr->personal || addr->adl)){ + so_seek(tso, 0L, 0); + pine_rfc822_address (addr, tpc); + peAppListF(peED.interp, objAddrList, "%s%o", "", Tcl_NewStringObj((char *) so_text(tso), so_tell(tso))); + } + else { /* no, must use phrase <route-addr> form */ + Tcl_Obj *objTmp; + + if (addr->personal){ + so_seek(tso, 0L, 0); + pine_rfc822_cat (addr->personal, rspecials_minus_quote_and_dot, tpc); + objTmp = Tcl_NewStringObj((char *) so_text(tso), so_tell(tso)); + } + + so_seek(tso, 0L, 0); + pine_rfc822_address(addr, tpc); + peAppListF(peED.interp, objAddrList, "%o%o", objTmp, Tcl_NewStringObj((char *) so_text(tso), so_tell(tso))); + } + + if(group) + group++; + } + else if (addr->mailbox) { /* start of group? */ + so_seek(tso, 0L, 0); + /* yes, write group name */ + pine_rfc822_cat (addr->mailbox, rspecials, tpc); + peAppListF(peED.interp, objAddrList, "%o%s", Tcl_NewStringObj((char *) so_text(tso), so_tell(tso)), ""); + group = 1; /* in a group */ + } + else if (group) { /* must be end of group (but be paranoid) */ + peAppListF(peED.interp, objAddrList, "%s%s", "", ";"); + group = 0; /* no longer in that group */ + } + + addr->personal = ptmp; /* restore old personal ptr */ + if(!addr->host && addr->mailbox){ + fs_give((void **)&addr->mailbox); + addr->mailbox = mtmp; + } + + addr->next = atmp; + addr = atmp; + } + + gf_clear_so_writec(tso); + so_give(&tso); + } + + peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "%s%s%o", atype, field_name, objAddrList); +} + + +/* + * appends caller's result with: {"news" field_name {{newsgroup1} {newsgroup2} ... }} + */ +void +peFormatEnvelopeNewsgroups(char *field_name, char *newsgrps, int flags, gf_io_t pc) +{ + char buf[MAILTMPLEN]; + int llen; + char *next_ng; + Tcl_Obj *objNewsgroups; + + /* BUG: handle list creation failure */ + if(!newsgrps || !*newsgrps || (objNewsgroups = Tcl_NewListObj(0,NULL)) == NULL) + return; + + llen = strlen(field_name); + while(*newsgrps){ + for(next_ng = newsgrps; *next_ng && *next_ng != ','; next_ng++) + ; + + strncpy(buf, newsgrps, MIN(next_ng - newsgrps, sizeof(buf)-1)); + buf[MIN(next_ng - newsgrps, sizeof(buf)-1)] = '\0'; + + Tcl_ListObjAppendElement(peED.interp, objNewsgroups, Tcl_NewStringObj(buf,-1)); + + newsgrps = next_ng; + if(*newsgrps) + newsgrps++; + } + + peAppListF(peED.interp, Tcl_GetObjResult(peED.interp), "news", field_name, objNewsgroups); +} + + +int +peMessageAttachments(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + MESSAGECACHE *mc; + ATTACH_S *a; + BODY *body; + Tcl_Obj *objAtt, *tObj, *stObj, *fnObj; + int flags, rv = TCL_OK; + long raw; + + peED.interp = interp; + peED.obj = Tcl_GetObjResult(interp); + + flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_HTML | FM_NOHTMLREL | FM_HTMLRELATED | FM_HIDESERVER; + + raw = peSequenceNumber(uid); + + if(peED.uid != uid){ + memset(&peED, 0, sizeof(peED)); + + peED.uid = uid; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + if(!((peED.env = pine_mail_fetchstructure(ps_global->mail_stream, raw, &peED.body)) + && (mc = mail_elt(ps_global->mail_stream, raw)))){ + char buf[256]; + + snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"); + + dprint((1, "ERROR fetching %s of msg %ld: %s", + peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate")); + + Tcl_SetResult(interp, buf, TCL_VOLATILE); + rv = TCL_ERROR; + } + else{ + zero_atmts(ps_global->atmts); +#ifdef SMIME + if(ps_global && ps_global->smime && ps_global->smime->need_passphrase) + ps_global->smime->need_passphrase = 0; + + fiddle_smime_message(peED.body, raw); +#endif + describe_mime(peED.body, "", 1, 1, 0, flags); + } + } + + /* package up attachment list */ + for(a = ps_global->atmts; rv == TCL_OK && a->description != NULL; a++) + if((objAtt = Tcl_NewListObj(0, NULL)) != NULL + && (body = mail_body(ps_global->mail_stream, raw, (unsigned char *) a->number)) != NULL){ + peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL); + + if(!(peAppListF(interp, objAtt, "%s", a->number ? a->number : "") == TCL_OK + && peAppListF(interp, objAtt, "%s", a->shown ? "shown" : "") == TCL_OK + && Tcl_ListObjAppendElement(interp, objAtt, tObj) == TCL_OK + && Tcl_ListObjAppendElement(interp, objAtt, stObj) == TCL_OK + && Tcl_ListObjAppendElement(interp, objAtt, fnObj) == TCL_OK + && peAppListF(interp, objAtt, "%s", a->body->description) == TCL_OK + && Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAtt) == TCL_OK)) + rv = TCL_ERROR; + } + else + rv = TCL_ERROR; + + return(rv); +} + + +int +peMessageBody(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + MESSAGECACHE *mc; + int flags, rv = TCL_OK; + long raw; + char *color; + + peED.interp = interp; + peED.obj = Tcl_GetObjResult(interp); + + if(peED.store) + so_seek(peED.store, 0L, 0); + else + peED.store = so_get(CharStar, NULL, EDIT_ACCESS); + + flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED; + + if(objc == 1 && objv[0]){ /* flags */ + int i, nFlags; + Tcl_Obj **objFlags; + char *flagstr; + + Tcl_ListObjGetElements(interp, objv[0], &nFlags, &objFlags); + for(i = 0; i < nFlags; i++){ + if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){ + rv = TCL_ERROR; + } + + if(!strucmp(flagstr, "html")) + flags |= (FM_HTML | FM_HIDESERVER); + else if(!strucmp(flagstr, "images")) + flags |= (FM_HTMLIMAGES); + } + } + + peED.color.fg[0] = '\0'; + if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_FGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.fgdef, peColorStr(color, tmp_20k_buf)); + } + + peED.color.bg[0] = '\0'; + if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_BGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.bgdef, peColorStr(color,tmp_20k_buf)); + } + + peInterpFlush(); + + init_handles(&peED.handles); + + raw = peSequenceNumber(uid); + + if(peED.uid != uid){ + peED.uid = uid; + peED.body = NULL; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + if(!((peED.env = pine_mail_fetchstructure(ps_global->mail_stream, raw, &peED.body)) + && (mc = mail_elt(ps_global->mail_stream, raw)))){ + char buf[256]; + + snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"); + + dprint((1, "ERROR fetching %s of msg %ld: %s", + peED.env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate")); + + Tcl_SetResult(interp, buf, TCL_VOLATILE); + rv = TCL_ERROR; + } + else{ + zero_atmts(ps_global->atmts); +#ifdef SMIME + if(ps_global && ps_global->smime && ps_global->smime->need_passphrase) + ps_global->smime->need_passphrase = 0; + + fiddle_smime_message(peED.body, raw); +#endif + describe_mime(peED.body, "", 1, 1, 0, flags); + } + } + + /* format message body */ + if(rv == TCL_OK){ + HEADER_S h; + char *errstr; + + HD_INIT(&h, ps_global->VAR_VIEW_HEADERS, ps_global->view_all_except, FE_DEFAULT); +#ifdef SMIME + /* kind of a hack, the description maybe shouldn't be in the editorial stuff */ + if(ps_global->smime && ps_global->smime->need_passphrase) + flags &= ~FM_NOEDITORIAL; +#endif + if((errstr = format_body(raw, peED.body, &peED.handles, &h, flags, FAKE_SCREEN_WIDTH, peInterpWritec)) != NULL){ + gf_puts(errstr, peInterpWritec); + rv = TCL_ERROR; + } + } + + peInterpFlush(); + + so_give(&peED.store); + free_handles(&peED.handles); + return(rv); +} + + +int +peMessageText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + MESSAGECACHE *mc; + ENVELOPE *env; + BODY *body; + int flags; + long raw; + char *color; + + memset(&peED, 0, sizeof(peED)); + peED.interp = interp; + peED.obj = Tcl_GetObjResult(interp); + peED.store = so_get(CharStar, NULL, EDIT_ACCESS); + + peED.color.fg[0] = '\0'; + if((color = pico_get_last_fg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_FGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.fgdef, peColorStr(color, tmp_20k_buf)); + } + + peED.color.bg[0] = '\0'; + if((color = pico_get_last_bg_color()) && (color = color_to_asciirgb(color))){ + peInterpWritec(TAG_EMBED); + peInterpWritec(TAG_BGCOLOR); + gf_puts(color, peInterpWritec); + strcpy(peED.color.bgdef, peColorStr(color,tmp_20k_buf)); + } + + raw = peSequenceNumber(peED.uid = uid); + body = NULL; + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + if(!((env = pine_mail_fetchstructure(ps_global->mail_stream, raw, &body)) + && (mc = mail_elt(ps_global->mail_stream, raw)))){ + char buf[256]; + + snprintf(buf, sizeof(buf), "Error getting message %ld: %s", peMessageNumber(uid), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate"); + + dprint((1, "ERROR fetching %s of msg %ld: %s", + env ? "elt" : "env", mn_get_cur(sp_msgmap(ps_global->mail_stream)), + ps_global->last_error[0] ? ps_global->last_error : "Indeterminate")); + + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + flags = FM_DISPLAY | FM_NEW_MESS | FM_NOEDITORIAL | FM_NOHTMLREL | FM_HTMLRELATED; + + init_handles(&peED.handles); + + (void) format_message(raw, env, body, &peED.handles, flags, peInterpWritec); + + peInterpFlush(); + + so_give(&peED.store); + free_handles(&peED.handles); + return(TCL_OK); +} + + +/* + * peMessagePartFromCID - return part number assoc'd with given uid and CID + */ +int +peMessagePartFromCID(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *cid, sect_buf[256]; + long raw; + ENVELOPE *env; + BODY *body; + + raw = peSequenceNumber(peED.uid = uid); + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + + if(objv[0] && (cid = Tcl_GetStringFromObj(objv[0], NULL)) && *cid != '\0'){ + if((env = pine_mail_fetchstructure(ps_global->mail_stream, raw, &body)) != NULL){ + sect_buf[0] = '\0'; + if(peLocateBodyByCID(cid, sect_buf, body)){ + Tcl_SetResult(interp, sect_buf, TCL_VOLATILE); + } + } + else{ + Tcl_SetResult(interp, ps_global->last_error[0] ? ps_global->last_error : "Error getting CID", TCL_VOLATILE); + return(TCL_ERROR); + } + } + + return(TCL_OK); +} + + +int +peLocateBodyByCID(char *cid, char *section, BODY *body) +{ + if(body->type == TYPEMULTIPART){ + char subsection[256], *subp; + int n; + PART *part = body->nested.part; + + if(!(part = body->nested.part)) + return(0); + + subp = subsection; + if(section && *section){ + for(n = 0; + n < sizeof(subsection)-20 && (*subp = section[n]); n++, subp++) + ; + + *subp++ = '.'; + } + + n = 1; + do { + sprintf(subp, "%d", n++); + if(peLocateBodyByCID(cid, subsection, &part->body)){ + strcpy(section, subsection); + return(1); + } + } + while((part = part->next) != NULL); + + return(0); + } + + return((body && body->id) ? !strcmp(cid, body->id) : 0); +} + + +/* + * peGetFlag - Return 1 or 0 based on requested flags current state + * + * Params: argv[0] == flagname + */ +int +peGetFlag(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *flagname; + + Tcl_SetResult(interp, + int2string(((flagname = Tcl_GetStringFromObj(objv[0], NULL)) != NULL) + ? peIsFlagged(ps_global->mail_stream, uid, flagname) + : 0), + TCL_VOLATILE); + return(TCL_OK); +} + + +int +peIsFlagged(MAILSTREAM *stream, imapuid_t uid, char *flagname) +{ + MESSAGECACHE *mc; + long raw = peSequenceNumber(uid); + + if(!((mc = mail_elt(stream, raw)) && mc->valid)){ + mail_fetch_flags(stream, ulong2string(uid), FT_UID); + mc = mail_elt(stream, raw); + } + + if(!strucmp(flagname, "deleted")) + return(mc->deleted); + + if(!strucmp(flagname, "new")) + return(!mc->seen); + + if(!strucmp(flagname, "important")) + return(mc->flagged); + + if(!strucmp(flagname, "answered")) + return(mc->answered); + + if(!strucmp(flagname, "recent")) + return(mc->recent); + + return(0); +} + + +/* + * peSetFlag - Set requested flags value to 1 or 0 + * + * Params: abjv[0] == flagname + * objv[1] == newvalue + */ +int +peSetFlag(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *flagname, *flagstr = NULL; + int value; + + if((flagname = Tcl_GetStringFromObj(objv[0], NULL)) + && Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_ERROR){ + if(!strucmp(flagname, "deleted")){ + flagstr = "\\DELETED"; + } + else if(!strucmp(flagname, "new")){ + flagstr = "\\SEEN"; + value = !value; + } + else if(!strucmp(flagname, "important")){ + flagstr = "\\FLAGGED"; + } + else if(!strucmp(flagname, "answered")){ + flagstr = "\\ANSWERED"; + } + else if(!strucmp(flagname, "recent")){ + flagstr = "\\RECENT"; + } + + if(flagstr){ + ps_global->c_client_error[0] = '\0'; + mail_flag(ps_global->mail_stream, + ulong2string(uid), + flagstr, (value ? ST_SET : 0L) | ST_UID); + if(ps_global->c_client_error[0] != '\0'){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "peSetFlag: %.40s", + ps_global->c_client_error); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + } + + Tcl_SetResult(interp, value ? "1" : "0", TCL_STATIC); + return(TCL_OK); +} + + +/* + * peMsgSelect - Return 1 or 0 based on whether given UID is selected + * + * Params: argv[0] == selected + */ +int +peMsgSelect(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + int value; + + if(objc == 1 && objv[0]){ + if(Tcl_GetIntFromObj(interp, objv[0], &value) != TCL_ERROR){ + if(value){ + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), + peMessageNumber(uid), MN_SLCT, 1); + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), + peMessageNumber(uid), MN_HIDE, 0); + } else { + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), + peMessageNumber(uid), MN_SLCT, 0); + /* if zoomed, lite hidden bit */ + if(any_lflagged(sp_msgmap(ps_global->mail_stream), MN_HIDE)) + set_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), + peMessageNumber(uid), MN_HIDE, 1); + + } + } + else{ + Tcl_SetResult(interp, "peMsgSelect: can't get value", TCL_STATIC); + return(TCL_ERROR); + } + } + + Tcl_SetResult(interp, + (get_lflag(ps_global->mail_stream, NULL, + peSequenceNumber(uid), + MN_SLCT)) + ? "1" : "0", + TCL_VOLATILE); + return(TCL_OK); +} + + +/* + * peAppendIndexParts - append list of digested index pieces to given object + * + * Params: + * + */ +int +peAppendIndexParts(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj *aObj, int *fetched) +{ + Tcl_Obj *objField, *objElement, *objp; + ICE_S *h; + IFIELD_S *f; + IELEM_S *ie; + + + if((h = build_header_work(ps_global, ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), peMessageNumber(uid), + gPeITop, gPeICount, fetched)) != NULL){ + for(f = h->ifield; f; f = f->next){ + + if((objField = Tcl_NewListObj(0, NULL)) == NULL) + return(TCL_ERROR); + + for(ie = f->ielem; ie ; ie = ie->next){ + + if((objElement = Tcl_NewListObj(0, NULL)) == NULL) + return(TCL_ERROR); + + if(ie->datalen){ + /* FIRST: DATA */ +#if INTERNAL_INDEX_TRUNCATE + char *ep; + + ep = (char *) fs_get((ie->datalen + 1) * sizeof(char)); + sprintf(ep, "%.*s", ie->wid, ie->data); + + /* and other stuff to pack trunc'd element into a new object */ +#endif + + objp = Tcl_NewStringObj(ie->data, ie->datalen); + } + else + objp = Tcl_NewStringObj("", -1); + + if(Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK) + return(TCL_ERROR); + + if(ie->color){ + Tcl_Obj *objColor; + char hexcolor[32]; + + if((objp = Tcl_NewListObj(0, NULL)) == NULL) + return(TCL_ERROR); + + hex_colorstr(hexcolor, ie->color->fg); + objColor = Tcl_NewStringObj(hexcolor, -1); + if(Tcl_ListObjAppendElement(interp, objp, objColor) != TCL_OK) + return(TCL_ERROR); + + hex_colorstr(hexcolor, ie->color->bg); + objColor = Tcl_NewStringObj(hexcolor, -1); + if(Tcl_ListObjAppendElement(interp, objp, objColor) != TCL_OK) + return(TCL_ERROR); + } + else + objp = Tcl_NewStringObj("", -1); + + if(Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK) + return(TCL_ERROR); + + /* + * IF we ever want to map the thread characters into nice + * graphical symbols or take advantage of features like clicking + * on a thread element to collapse and such, we need to have + * element tagging. That's what the object creation and append + * are placeholders for + */ + switch(ie->type){ + case eThreadInfo : + objp = Tcl_NewStringObj("threadinfo", -1); + break; + case eText : + objp = NULL; + break; + default : + objp = Tcl_NewStringObj(int2string(ie->type), -1); + break; + } + + if(objp && Tcl_ListObjAppendElement(interp, objElement, objp) != TCL_OK) + return(TCL_ERROR); + + if(Tcl_ListObjAppendElement(interp, objField, objElement) != TCL_OK) + return(TCL_ERROR); + } + + if(Tcl_ListObjAppendElement(interp, aObj, objField) != TCL_OK){ + return(TCL_ERROR); + } + } + } + + return(TCL_OK); +} + + +/* + * peAppendIndexColor - append index line's foreground/background color + * + * Params: + * + */ +int +peAppendIndexColor(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj *aObj, int *fetched) +{ + char hexfg[32], hexbg[32]; + ICE_S *h; + + if((h = build_header_work(ps_global, ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), peMessageNumber(uid), + gPeITop, gPeICount, fetched)) + && h->color_lookup_done + && h->linecolor){ + + hex_colorstr(hexfg, h->linecolor->fg); + hex_colorstr(hexbg, h->linecolor->bg); + + return(peAppListF(interp, aObj, "%s%s", hexfg, hexbg)); + } + + return(peAppListF(interp, aObj, "%s", "")); +} + + +/* + * peMessageStatusBits - return list flags indicating pine status bits + * + * Params: + * + * Returns: list of lists where: + * * the first element is the list of + * field elements data + * * the second element is a two element + * list containing the lines foreground + * and background colors + */ +int +peMessageStatusBits(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + Tcl_SetResult(interp, + peMsgStatBitString(ps_global, ps_global->mail_stream, + sp_msgmap(ps_global->mail_stream), peMessageNumber(uid), + gPeITop, gPeICount, NULL), + TCL_STATIC); + return(TCL_OK); +} + + +char * +peMsgStatBitString(struct pine *state, + MAILSTREAM *stream, + MSGNO_S *msgmap, + long msgno, + long top_msgno, + long msgcount, + int *fetched) +{ + static char buf[36]; + int i; + long raw; + MESSAGECACHE *mc; + ICE_S *h; + + raw = mn_m2raw(msgmap, msgno); + if((h = build_header_work(state, stream, msgmap, + msgno, top_msgno, msgcount, fetched)) + && (mc = mail_elt(stream, raw))){ + /* return a string representing a bit field where: + index meaning + ----- ------- + 0 "New" + 1 deleted + 2 answered + 3 flagged + 4 to us + 5 cc us + 6 recent + 7 forwarded + 8 attachments + */ + i = 0; + buf[i++] = (mc->seen) ? '0' : '1'; + buf[i++] = (mc->deleted) ? '1' : '0'; + buf[i++] = (mc->answered) ? '1' : '0'; + buf[i++] = (mc->flagged) ? '1' : '0'; + buf[i++] = (h->to_us) ? '1' : '0'; + buf[i++] = (h->cc_us) ? '1' : '0'; + buf[i++] = (mc->recent) ? '1' : '0'; + buf[i++] = (user_flag_is_set(stream, raw, FORWARDED_FLAG)) ? '1' : '0'; + buf[i++] = '0'; + buf[i++] = '\0'; + + return(buf); + } + + return("100000000"); +} + + +Tcl_Obj * +peMsgStatNameList(Tcl_Interp *interp, + struct pine *state, + MAILSTREAM *stream, + MSGNO_S *msgmap, + long msgno, + long top_msgno, + long msgcount, + int *fetched) +{ + Tcl_Obj *objList; + long raw; + MESSAGECACHE *mc; + ICE_S *h; + + objList = Tcl_NewListObj(0, NULL); + raw = mn_m2raw(msgmap, msgno); + if((h = build_header_work(state, stream, msgmap, + msgno, top_msgno, msgcount, fetched)) + && (mc = mail_elt(stream, raw))){ + if(!mc->seen) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("new", -1)); + + if(mc->deleted) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("deleted", -1)); + + if(mc->answered) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("answered", -1)); + + if(mc->flagged) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("flagged", -1)); + + if(h->to_us) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("to_us", -1)); + + if(h->cc_us) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("cc_us", -1)); + + if(mc->recent) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("recent", -1)); + + if(user_flag_is_set(stream, raw, FORWARDED_FLAG)) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("forwarded", -1)); + + if(get_lflag(ps_global->mail_stream, sp_msgmap(ps_global->mail_stream), msgno, MN_SLCT)) + Tcl_ListObjAppendElement(interp, objList, Tcl_NewStringObj("selected", -1)); + } + + return(objList); +} + + +/* + * peReplyHeaders - return subject used in reply to given message + * + * Params: + * + * Returns: list of header value pairs where headers are: + * In-Reply-To:, Subject:, Cc: + * + */ +int +peReplyHeaders(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + long raw; + int flags = RSF_FORCE_REPLY_TO | RSF_FORCE_REPLY_ALL, err = FALSE; + char *errmsg = NULL, *fcc = NULL, *sect = NULL; + ENVELOPE *env, *outgoing; + BODY *body = NULL; + ADDRESS *saved_from, *saved_to, *saved_cc, *saved_resent; + + saved_from = (ADDRESS *) NULL; + saved_to = (ADDRESS *) NULL; + saved_cc = (ADDRESS *) NULL; + saved_resent = (ADDRESS *) NULL; + + raw = peSequenceNumber(uid); + + /* if we're given a valid section number that + * corresponds to a valid msg/rfc822 body part + * then set up headers in attached message. + */ + if(objc == 1 && objv[0] + && (sect = Tcl_GetStringFromObj(objv[0], NULL)) && *sect != '\0' + && (body = mail_body(ps_global->mail_stream, raw, (unsigned char *) sect)) + && body->type == TYPEMESSAGE + && !strucmp(body->subtype, "rfc822")){ + env = body->nested.msg->env; + } + else{ + sect = NULL; + env = mail_fetchstructure(ps_global->mail_stream, raw, NULL); + } + + if(env){ + if(!reply_harvest(ps_global, raw, sect, env, + &saved_from, &saved_to, &saved_cc, + &saved_resent, &flags)){ + + Tcl_SetResult(interp, "", TCL_STATIC); + return(TCL_ERROR); + } + + outgoing = mail_newenvelope(); + + reply_seed(ps_global, outgoing, env, + saved_from, saved_to, saved_cc, saved_resent, + &fcc, flags, &errmsg); + if(errmsg){ + if(*errmsg){ + q_status_message1(SM_ORDER, 3, 3, "%.200s", errmsg); + } + + fs_give((void **)&errmsg); + } + + env = pine_mail_fetchstructure(ps_global->mail_stream, raw, NULL); + + outgoing->subject = reply_subject(env->subject, NULL, 0); + outgoing->in_reply_to = reply_in_reply_to(env); + + err = !(peAppListF(interp, Tcl_GetObjResult(interp), + "%s%a", "to", outgoing->to) == TCL_OK + && peAppListF(interp, Tcl_GetObjResult(interp), + "%s%a", "cc", outgoing->cc) == TCL_OK + && peAppListF(interp, Tcl_GetObjResult(interp), + "%s%s", "in-reply-to", outgoing->in_reply_to) == TCL_OK + && peAppListF(interp, Tcl_GetObjResult(interp), + "%s%s", "subject", + rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, + SIZEOF_20KBUF, outgoing->subject)) == TCL_OK + && (fcc ? peFccAppend(interp, Tcl_GetObjResult(interp), fcc, -1) : TRUE)); + + + /* Fill in x-reply-uid data and append it */ + if(!err && ps_global->mail_stream->uid_validity){ + char *prefix = reply_quote_str(env); + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "(%d %s)(1 %lu %lu)%s", + strlen(prefix), prefix, + ps_global->mail_stream->uid_validity, uid, + ps_global->mail_stream->mailbox); + + fs_give((void **) &prefix); + + err = peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", + "x-reply-uid", tmp_20k_buf) != TCL_OK; + } + + mail_free_envelope(&outgoing); + + if(err) + return(TCL_ERROR); + } + else + Tcl_SetResult(interp, "", TCL_VOLATILE); + + return(TCL_OK); +} + + + +/* + * peReplyText - return subject used in reply to given message + * + * Params: + * + * Returns: + * + */ +int +peReplyText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + long msgno; + char *prefix, *sect = NULL; + int rv = TCL_OK; + ENVELOPE *env; + BODY *body = NULL, *orig_body; + STORE_S *msgtext; + REDRAFT_POS_S *redraft_pos = NULL; + Tcl_Obj *objBody = NULL, *objAttach = NULL; + + msgno = peSequenceNumber(uid); + + if((msgtext = (void *) so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){ + Tcl_SetResult(interp, "Unable to create storage for reply text", TCL_VOLATILE); + return(TCL_ERROR); + } + + /*--- Grab current envelope ---*/ + /* if we're given a valid section number that + * corresponds to a valid msg/rfc822 body part + * then set up to reply the attached message's + * text. + */ + if(objc == 2 && objv[1] + && (sect = Tcl_GetStringFromObj(objv[1], NULL)) && *sect != '\0' + && (body = mail_body(ps_global->mail_stream, msgno, (unsigned char *) sect)) + && body->type == TYPEMESSAGE + && !strucmp(body->subtype, "rfc822")){ + env = body->nested.msg->env; + orig_body = body->nested.msg->body; + } + else{ + sect = NULL; + env = mail_fetchstructure(ps_global->mail_stream, msgno, &orig_body); + if(!(env && orig_body)){ + Tcl_SetResult(interp, "Unable to fetch message parts", TCL_VOLATILE); + return(TCL_ERROR); + } + } + + if((prefix = Tcl_GetStringFromObj(objv[0], NULL)) != NULL) + prefix = cpystr(prefix); + else + prefix = reply_quote_str(env); + + /* + * BUG? Should there be some way to signal to reply_bddy + * that we'd like it to produced format=flowed body text? + * right now it's hardwired to in pine/reply.c + */ + + if((body = reply_body(ps_global->mail_stream, env, orig_body, + msgno, sect, msgtext, prefix, + TRUE, NULL, TRUE, &redraft_pos)) != NULL){ + + objBody = Tcl_NewListObj(0, NULL); + + peSoStrToList(interp, objBody, msgtext); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBody); + + /* sniff for attachments */ + objAttach = peMsgAttachCollector(interp, body); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach); + + + pine_free_body(&body); + } + else{ + Tcl_SetResult(interp, "Can't create body text", TCL_VOLATILE); + rv = TCL_ERROR; + } + + fs_give((void **) &prefix); + + return(rv); +} + + +int +peSoStrToList(Tcl_Interp *interp, Tcl_Obj *obj, STORE_S *so) +{ + char *sp, *ep; + Tcl_Obj *objp; + + for(ep = (char *) so_text(so); *ep; ep++){ + sp = ep; + + while(*ep && *ep != '\n') + ep++; + + objp = Tcl_NewStringObj(sp, ep - sp); + + if(Tcl_ListObjAppendElement(interp, obj, objp) != TCL_OK) + return(FALSE); + } + + return(TRUE); +} + + +/* + * peForwardHeaders - return subject used in forward of given message + * + * Params: + * + * Returns: + * + */ +int +peForwardHeaders(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + + int result; + long raw; + char *tmp, *sect = NULL; + ENVELOPE *env; + BODY *body; + + raw = peSequenceNumber(uid); + + /* if we're given a valid section number that + * corresponds to a valid msg/rfc822 body part + * then set up headers in attached message. + */ + if(objc == 1 && objv[0] + && (sect = Tcl_GetStringFromObj(objv[0], NULL)) && *sect != '\0' + && (body = mail_body(ps_global->mail_stream, raw, (unsigned char *) sect)) + && body->type == TYPEMESSAGE + && !strucmp(body->subtype, "rfc822")){ + env = body->nested.msg->env; + } + else{ + sect = NULL; + env = mail_fetchstructure(ps_global->mail_stream, raw, NULL); + } + + if(env){ + tmp = forward_subject(env, FS_NONE); + result = peAppListF(interp, Tcl_GetObjResult(interp), + "%s%s", "subject", tmp); + fs_give((void **) &tmp); + + /* Fill in x-reply-uid data and append it */ + if(result == TCL_OK && ps_global->mail_stream->uid_validity){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "()(1 %lu %lu)%s", + ps_global->mail_stream->uid_validity, uid, + ps_global->mail_stream->mailbox); + result = peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", + "x-reply-uid", tmp_20k_buf) != TCL_OK; + } + + return(result); + } + + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_ERROR); +} + + + +/* + * peForwardText - return body of message used in + * forward of given message + * + * Params: + * + * Returns: + * + */ +int +peForwardText(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + long msgno; + char *bodtext, *p, *sect = NULL; + int rv = TCL_OK; + ENVELOPE *env; + BODY *body, *orig_body; + STORE_S *msgtext; + Tcl_Obj *objBody = NULL, *objAttach = NULL; + + msgno = peSequenceNumber(uid); + + if(objc == 1 && objv[0]) + sect = Tcl_GetStringFromObj(objv[0], NULL); + + if((msgtext = (void *) so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){ + Tcl_SetResult(interp, "Unable to create storage for forward text", TCL_VOLATILE); + return(TCL_ERROR); + } + + + if(F_ON(F_FORWARD_AS_ATTACHMENT, ps_global)){ + PART **pp; + long totalsize = 0L; + + /*---- New Body to start with ----*/ + body = mail_newbody(); + body->type = TYPEMULTIPART; + + /*---- The TEXT part/body ----*/ + body->nested.part = mail_newbody_part(); + body->nested.part->body.type = TYPETEXT; + body->nested.part->body.contents.text.data = (unsigned char *) msgtext; + + pp = &(body->nested.part->next); + + /*---- The Message body subparts ----*/ + env = pine_mail_fetchstructure(ps_global->mail_stream, msgno, NULL); + + if(forward_mime_msg(ps_global->mail_stream, msgno, + (sect && *sect != '\0') ? sect : NULL, env, pp, msgtext)){ + totalsize = (*pp)->body.size.bytes; + pp = &((*pp)->next); + } + } + else{ + /*--- Grab current envelope ---*/ + /* if we're given a valid section number that + * corresponds to a valid msg/rfc822 body part + * then set up to forward the attached message's + * text. + */ + + if(sect && *sect != '\0' + && (body = mail_body(ps_global->mail_stream, msgno, (unsigned char *) sect)) + && body->type == TYPEMESSAGE + && !strucmp(body->subtype, "rfc822")){ + env = body->nested.msg->env; + orig_body = body->nested.msg->body; + } + else{ + sect = NULL; + env = mail_fetchstructure(ps_global->mail_stream, msgno, &orig_body); + if(!(env && orig_body)){ + Tcl_SetResult(interp, "Unable to fetch message parts", TCL_VOLATILE); + return(TCL_ERROR); + } + } + + body = forward_body(ps_global->mail_stream, env, orig_body, + msgno, sect, msgtext, FWD_NONE); + } + + if(body){ + bodtext = (char *) so_text(msgtext); + + objBody = Tcl_NewListObj(0, NULL); + + for(p = bodtext; *p; p++){ + Tcl_Obj *objp; + + bodtext = p; + while(*p && *p != '\n') + p++; + + objp = Tcl_NewStringObj(bodtext, p - bodtext); + + Tcl_ListObjAppendElement(interp, objBody, objp); + } + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBody); + + /* sniff for attachments */ + objAttach = peMsgAttachCollector(interp, body); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach); + + pine_free_body(&body); + } + else{ + Tcl_SetResult(interp, "Can't create body text", TCL_VOLATILE); + rv = TCL_ERROR; + } + + return(rv); +} + + + +/* + * peDetach - + * + * Params: argv[0] == attachment part number + * argv[1] == directory to hold tmp file + * + * Returns: list containing: + * + * 0) response: OK or ERROR + * if OK + * 1) attachment's mime type + * 2) attachment's mime sub-type + * 3) attachment's size in bytes (decoded) + * 4) attachment's given file name (if any) + * 5) tmp file holding raw attachment data + */ +int +peDetach(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *part, *err, *tfd, *tfn = NULL, *filename; + long raw; + gf_io_t pc; + BODY *body; + STORE_S *store; + Tcl_Obj *rvobj, *tObj, *stObj, *fnObj; + + if((part = Tcl_GetStringFromObj(objv[0], NULL)) + && (raw = peSequenceNumber(uid)) + && (body = mail_body(ps_global->mail_stream, raw, (unsigned char *) part))){ + + peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL); + + err = NULL; + if(!(tfd = Tcl_GetStringFromObj(objv[1], NULL)) || *tfd == '\0'){ + tfn = temp_nam(tfd = NULL, "pd"); + } + else if(is_writable_dir(tfd) == 0){ + tfn = temp_nam(tfd, "pd"); + } + else + tfn = tfd; + + filename = Tcl_GetStringFromObj(fnObj, NULL); + dprint((5, "PEDetach(name: %s, tmpfile: %s)", + filename ? filename : "<null>", tfn)); + + if((store = so_get(FileStar, tfn, WRITE_ACCESS|OWNER_ONLY)) != NULL){ + gf_set_so_writec(&pc, store); + err = detach(ps_global->mail_stream, raw, part, 0L, NULL, pc, NULL, 0); + gf_clear_so_writec(store); + so_give(&store); + } + else + err = "Can't allocate internal storage"; + } + else + err = "Can't get message data"; + + if(err){ + if(tfn) + unlink(tfn); + + dprint((1, "PEDetach FAIL: %d: %s", errno, err)); + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Detach (%d): %s", errno, err); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); + } + + /* package up response */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(1, &tObj)); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(1, &stObj)); + + rvobj = Tcl_NewLongObj(name_file_size(tfn)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(1, &rvobj)); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(1, &fnObj)); + rvobj = Tcl_NewStringObj(tfn, -1); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(1, &rvobj)); + + return(TCL_OK); +} + + +/* + * peAttachInfo - + * + * Params: argv[0] == attachment part number + * + * Returns: list containing: + * + * 0) response: OK or ERROR + * if OK + * 1) attachment's mime type + * 2) attachment's mime sub-type + * 3) attachment's size in bytes (decoded) + * 4) attachment's given file name (if any) + * 5) tmp file holding raw attachment data + */ +int +peAttachInfo(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *part; + long raw; + BODY *body; + PARMLIST_S *plist; + Tcl_Obj *tObj, *stObj, *fnObj; + + if((part = Tcl_GetStringFromObj(objv[0], NULL)) + && (raw = peSequenceNumber(uid)) + && (body = mail_body(ps_global->mail_stream, raw, (unsigned char *) part))){ + + peGetMimeTyping(body, &tObj, &stObj, &fnObj, NULL); + } + else{ + Tcl_SetResult(interp, "Can't get message data", TCL_STATIC); + return(TCL_ERROR); + } + + /* package up response */ + + /* filename */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), fnObj); + + /* type */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), tObj); + + /* subtype */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), stObj); + + /* encoding */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj((body->encoding < ENCMAX) + ? body_encodings[body->encoding] + : "Unknown", -1)); + + /* parameters */ + if((plist = rfc2231_newparmlist(body->parameter)) != NULL){ + Tcl_Obj *lObj = Tcl_NewListObj(0, NULL); + Tcl_Obj *pObj[2]; + + while(rfc2231_list_params(plist)){ + pObj[0] = Tcl_NewStringObj(plist->attrib, -1); + pObj[1] = Tcl_NewStringObj(plist->value, -1); + Tcl_ListObjAppendElement(interp, lObj, + Tcl_NewListObj(2, pObj)); + } + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), lObj); + rfc2231_free_parmlist(&plist); + } + + /* size guesstimate */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(comatose((body->encoding == ENCBASE64) + ? ((body->size.bytes * 3)/4) + : body->size.bytes), -1)); + + return(TCL_OK); +} + + +/* + * peSaveDefault - Default saved file name for the given message + * specified collection/folder + * + * Params: + * + * Returns: name of saved message folder or empty string + * + */ +int +peSaveDefault(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *folder; + CONTEXT_S *cntxt, *cp; + int colid; + long rawno; + ENVELOPE *env; + + if(uid){ + if(!(env = pine_mail_fetchstructure(ps_global->mail_stream, + rawno = peSequenceNumber(uid), + NULL))){ + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_ERROR); + } + } + else + env = NULL; + + if(!(folder = save_get_default(ps_global, env, rawno, NULL, &cntxt))){ + Tcl_SetResult(interp, "Message expunged!", TCL_VOLATILE); + return(TCL_ERROR); /* message expunged! */ + } + + for(colid = 0, cp = ps_global->context_list; cp && cp != cntxt ; colid++, cp = cp->next) + ; + + if(!cp) + colid = 0; + + (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(colid)); + (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(folder, -1)); + return(TCL_OK); +} + + +/* + * peSaveWork - Save message with given UID in current folder to + * specified collection/folder + * + * Params: argv[0] == destination context number + * argv[1] == testination foldername + * + * + */ +int +peSaveWork(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv, long sflags) +{ + int flgs = 0, i, colid; + char *folder, *err = NULL; + CONTEXT_S *cp; + + if(Tcl_GetIntFromObj(interp, objv[0], &colid) != TCL_ERROR){ + if((folder = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + mn_set_cur(sp_msgmap(ps_global->mail_stream), peMessageNumber(uid)); + for(i = 0, cp = ps_global->context_list; cp ; i++, cp = cp->next) + if(i == colid) + break; + + if(cp){ + if(!READONLY_FOLDER(ps_global->mail_stream) + && (sflags & PSW_COPY) != PSW_COPY + && ((sflags & PSW_MOVE) == PSW_MOVE || F_OFF(F_SAVE_WONT_DELETE, ps_global))) + flgs |= SV_DELETE; + + if(colid == 0 && !strucmp(folder, "inbox")) + flgs |= SV_INBOXWOCNTXT; + + if(sflags & (PSW_COPY | PSW_MOVE)) + flgs |= SV_FIX_DELS; + + i = save(ps_global, ps_global->mail_stream, + cp, folder, sp_msgmap(ps_global->mail_stream), flgs); + + if(i == mn_total_cur(sp_msgmap(ps_global->mail_stream))){ + if(mn_total_cur(sp_msgmap(ps_global->mail_stream)) <= 1L){ + if(ps_global->context_list->next + && context_isambig(folder)){ + char *tag = (cp->nickname && strlen(cp->nickname)) ? cp->nickname : (cp->label && strlen(cp->label)) ? cp->label : "Folders"; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, + "Message %s %s to \"%.15s%s\" in <%.15s%s>", + long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), + (sflags & PSW_MOVE) ? "moved" : "copied", + folder, + (strlen(folder) > 15) ? "..." : "", + tag, + (strlen(tag) > 15) ? "..." : ""); + } + else + snprintf(tmp_20k_buf, SIZEOF_20KBUF, + "Message %s %s to folder \"%.27s%s\"", + long2string(mn_get_cur(sp_msgmap(ps_global->mail_stream))), + (sflags & PSW_MOVE) ? "moved" : "copied", + folder, + (strlen(folder) > 27) ? "..." : ""); + } + else{ + /* with mn_set_cur above, this *should not* happen */ + Tcl_SetResult(interp, "TOO MANY MESSAGES COPIED", TCL_VOLATILE); + return(TCL_ERROR); + } + + if(sflags == PSW_NONE && (flgs & SV_DELETE)){ + strncat(tmp_20k_buf, " and deleted", SIZEOF_20KBUF-strlen(tmp_20k_buf)-1); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + } + + q_status_message(SM_ORDER, 0, 3, tmp_20k_buf); + return(TCL_OK); + } + + err = ps_global->last_error; + } + else + err = "open: Unrecognized collection ID"; + } + else + err = "open: Can't read folder"; + } + else + err = "open: Can't get collection ID"; + + Tcl_SetResult(interp, err, TCL_VOLATILE); + return(TCL_ERROR); +} + +/* + * peSave - Save message with given UID in current folder to + * specified collection/folder + * + * Params: argv[0] == destination context number + * argv[1] == testination foldername + * + * NOTE: just a wrapper around peSaveWork + */ +int +peSave(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peSaveWork(interp, uid, objc, objv, PSW_NONE)); +} + + +/* + * peCopy - Copy message with given UID in current folder to + * specified collection/folder + * + * Params: argv[0] == destination context number + * argv[1] == testination foldername + * + * NOTE: just a wrapper around peSaveWork that makes sure + * delete-on-save is NOT set + */ +int +peCopy(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peSaveWork(interp, uid, objc, objv, PSW_COPY)); +} + + +/* + * peMove - Move message with given UID in current folder to + * specified collection/folder + * + * Params: argv[0] == destination context number + * argv[1] == testination foldername + * + * NOTE: just a wrapper around peSaveWork that makes sure + * delete-on-save IS set so it can be expunged + */ +int +peMove(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + return(peSaveWork(interp, uid, objc, objv, PSW_MOVE)); +} + + +/* + * peGotoDefault - Default Goto command file name for the given message + * specified collection/folder + * + * Params: + * + * Returns: name of Goto command default folder or empty string + * + */ +int +peGotoDefault(Tcl_Interp *interp, imapuid_t uid, Tcl_Obj **objv) +{ + char *folder = NULL; + CONTEXT_S *cntxt, *cp; + int colid, inbox; + + cntxt = broach_get_folder(ps_global->context_current, &inbox, &folder); + + for(colid = 0, cp = ps_global->context_list; cp != cntxt ; colid++, cp = cp->next) + ; + + if(!cp) + colid = 0; + + (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(colid)); + (void) Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(folder ? folder : "", -1)); + return(TCL_OK); +} + + +/* + * peReplyQuote - + * + * Params: argv[0] == attachment part number + * + * Returns: list containing: + * + */ +int +peReplyQuote(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *quote; + ENVELOPE *env; + + if(uid){ + if((env = pine_mail_fetchstructure(ps_global->mail_stream, peSequenceNumber(uid), NULL)) != NULL){ + quote = reply_quote_str(env); + Tcl_SetResult(interp, quote, TCL_VOLATILE); + fs_give((void **) "e); + } + else{ + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_ERROR); + } + } + else + Tcl_SetResult(interp, "> ", TCL_VOLATILE); + + return(TCL_OK); +} + + +void +peGetMimeTyping(BODY *body, Tcl_Obj **tObjp, Tcl_Obj **stObjp, Tcl_Obj **fnObjp, Tcl_Obj **extObjp) +{ + char *ptype = NULL, *psubtype = NULL, *pfile = NULL; + + /*------- Figure out suggested file name ----*/ + if(body){ + if((pfile = get_filename_parameter(NULL, 0, body, NULL)) != NULL){ + /* + * if part is generic, see if we can get anything + * more from the suggested filename's extension... + */ + if(body->type == TYPEAPPLICATION + && (!body->subtype + || !strucmp(body->subtype, "octet-stream"))){ + BODY *fakebody = mail_newbody(); + + if(set_mime_type_by_extension(fakebody, pfile)){ + ptype = body_type_names(fakebody->type); + psubtype = cpystr(fakebody->subtype); + } + + mail_free_body(&fakebody); + } + } + + if(!ptype) { + ptype = body_type_names(body->type); + psubtype = cpystr(body->subtype + ? body->subtype + : (body->type == TYPETEXT) + ? "plain" + : (body->type == TYPEAPPLICATION) + ? "octet-stream" + : ""); + } + } + else{ + ptype = body_type_names(TYPETEXT); + psubtype = cpystr("plain"); + } + + if(extObjp){ + *extObjp = Tcl_NewStringObj("", 0); + + if(ptype && psubtype && pfile){ + size_t l; + char *mtype; + char extbuf[32]; /* mailcap.c limits to three */ + + l = strlen(ptype) + strlen(psubtype) + 1; + mtype = (char *) fs_get((l+1) * sizeof(char)); + + snprintf(mtype, l+1, "%s/%s", ptype, psubtype); + + if(!set_mime_extension_by_type(extbuf, mtype)){ + char *dotp, *p; + + for(dotp = NULL, p = pfile; *p; p++) + if(*p == '.') + dotp = p + 1; + + if(dotp) + Tcl_SetStringObj(*extObjp, dotp, -1); + } + else + Tcl_SetStringObj(*extObjp, extbuf, -1); + + fs_give((void **) &mtype); + } + } + + if(tObjp) + *tObjp = Tcl_NewStringObj(ptype, -1); + + if(psubtype){ + if(stObjp) + *stObjp = Tcl_NewStringObj(psubtype, -1); + + fs_give((void **) &psubtype); + } + else if(stObjp) + *stObjp = Tcl_NewStringObj("", 0); + + if(pfile){ + if(fnObjp) + *fnObjp = Tcl_NewStringObj(pfile, -1); + + fs_give((void **) &pfile); + } + else if(fnObjp) + *fnObjp = Tcl_NewStringObj("", 0); +} + + +/* + * peAppListF - generate a list of elements based on fmt string, + * then append it to the given list object + * + */ +int +peAppListF(Tcl_Interp *interp, Tcl_Obj *lobjp, char *fmt, ...) +{ + va_list args; + char *p, *sval, nbuf[128]; + int ival, err = 0; + unsigned int uval; + long lval; + unsigned long luval; + PATTERN_S *pval; + ADDRESS *aval; + INTVL_S *vval; + Tcl_Obj *lObj = NULL, *sObj; + + if((lObj = Tcl_NewListObj(0, NULL)) != NULL){ + va_start(args, fmt); + for(p = fmt; *p && !err; p++){ + sObj = NULL; + + if(*p == '%') + switch(*++p){ + case 'i' : /* int value */ + ival = va_arg(args, int); + if((sObj = Tcl_NewIntObj(ival)) == NULL) + err++; + + break; + + case 'u' : /* unsigned int value */ + uval = va_arg(args, unsigned int); + snprintf(nbuf, sizeof(nbuf), "%u", uval); + if((sObj = Tcl_NewStringObj(nbuf, -1)) == NULL) + err++; + + break; + + case 'l' : /* long value */ + if(*(p+1) == 'u'){ + p++; + luval = va_arg(args, unsigned long); + snprintf(nbuf, sizeof(nbuf), "%lu", luval); + if((sObj = Tcl_NewStringObj(nbuf, -1)) == NULL) + err++; + } + else{ + lval = va_arg(args, long); + if((sObj = Tcl_NewLongObj(lval)) == NULL) + err++; + } + + break; + + case 's' : /* string value */ + sval = va_arg(args, char *); + sObj = Tcl_NewStringObj(sval ? sval : "", -1); + if(sObj == NULL) + err++; + + break; + + case 'a': /* ADDRESS list */ + aval = va_arg(args, ADDRESS *); + if(aval){ + char *tmp, *p; + RFC822BUFFER rbuf; + size_t len; + + len = est_size(aval); + tmp = (char *) fs_get(len * sizeof(char)); + tmp[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = tmp; + rbuf.cur = tmp; + rbuf.end = tmp+len-1; + rfc822_output_address_list(&rbuf, aval, 0L, NULL); + *rbuf.cur = '\0'; + p = (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, tmp); + sObj = Tcl_NewStringObj(p, strlen(p)); + fs_give((void **) &tmp); + } + else + sObj = Tcl_NewStringObj("", -1); + + break; + + case 'p': /* PATTERN_S * */ + pval = va_arg(args, PATTERN_S *); + sval = pattern_to_string(pval); + sObj = Tcl_NewStringObj(sval ? sval : "", -1); + break; + + case 'v': /* INTVL_S * */ + vval = va_arg(args, INTVL_S *); + if(vval){ + for(; vval != NULL; vval = vval->next){ + peAppListF(interp, sObj, "%l%l", vval->imin, vval->imax); + } + } + else + sObj = Tcl_NewListObj(0, NULL); + + break; + + case 'o': /* Tcl_Obj * */ + sObj = va_arg(args, Tcl_Obj *); + break; + } + + if(sObj) + Tcl_ListObjAppendElement(interp, lObj, sObj); + } + + va_end(args); + } + + return(lObj ? Tcl_ListObjAppendElement(interp, lobjp, lObj) : TCL_ERROR); +} + +/* + * pePatAppendID - append list of pattern identity variables to given object + */ +void +pePatAppendID(Tcl_Interp *interp, Tcl_Obj *patObj, PAT_S *pat) +{ + Tcl_Obj *resObj; + + resObj = Tcl_NewListObj(0, NULL); + peAppListF(interp, resObj, "%s%s", "nickname", pat->patgrp->nick); + peAppListF(interp, resObj, "%s%s", "comment", pat->patgrp->comment); + Tcl_ListObjAppendElement(interp, patObj, resObj); +} + + +/* + * pePatAppendPattern - append list of pattern variables to given object + */ +void +pePatAppendPattern(Tcl_Interp *interp, Tcl_Obj *patObj, PAT_S *pat) +{ + ARBHDR_S *ah; + Tcl_Obj *resObj; + + resObj = Tcl_NewListObj(0, NULL); + peAppListF(interp, resObj, "%s%p", "to", pat->patgrp->to); + peAppListF(interp, resObj, "%s%p", "from", pat->patgrp->from); + peAppListF(interp, resObj, "%s%p", "sender", pat->patgrp->sender); + peAppListF(interp, resObj, "%s%p", "cc", pat->patgrp->cc); + peAppListF(interp, resObj, "%s%p", "recip", pat->patgrp->recip); + peAppListF(interp, resObj, "%s%p", "partic", pat->patgrp->partic); + peAppListF(interp, resObj, "%s%p", "news", pat->patgrp->news); + peAppListF(interp, resObj, "%s%p", "subj", pat->patgrp->subj); + peAppListF(interp, resObj, "%s%p", "alltext", pat->patgrp->alltext); + peAppListF(interp, resObj, "%s%p", "bodytext", pat->patgrp->bodytext); + peAppListF(interp, resObj, "%s%p", "keyword", pat->patgrp->keyword); + peAppListF(interp, resObj, "%s%p", "charset", pat->patgrp->charsets); + + peAppListF(interp, resObj, "%s%v", "score", pat->patgrp->score); + peAppListF(interp, resObj, "%s%v", "age", pat->patgrp->age); + peAppListF(interp, resObj, "%s%v", "size", pat->patgrp->size); + + if((ah = pat->patgrp->arbhdr) != NULL){ + Tcl_Obj *hlObj, *hObj; + + hlObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, hlObj, Tcl_NewStringObj("headers", -1)); + + for(; ah; ah = ah->next){ + hObj = Tcl_NewListObj(0, NULL); + peAppListF(interp, hObj, "%s%p", ah->field ? ah->field : "", ah->p); + Tcl_ListObjAppendElement(interp, hlObj, hObj); + } + + Tcl_ListObjAppendElement(interp, resObj, hlObj); + } + + switch(pat->patgrp->fldr_type){ + case FLDR_ANY: + peAppListF(interp, resObj, "%s%s", "ftype", "any"); + break; + case FLDR_NEWS: + peAppListF(interp, resObj, "%s%s", "ftype", "news"); + break; + case FLDR_EMAIL: + peAppListF(interp, resObj, "%s%s", "ftype", "email"); + break; + case FLDR_SPECIFIC: + peAppListF(interp, resObj, "%s%s", "ftype", "specific"); + break; + } + + peAppListF(interp, resObj, "%s%p", "folder", pat->patgrp->folder); + peAppListF(interp, resObj, "%s%s", "stat_new", pePatStatStr(pat->patgrp->stat_new)); + peAppListF(interp, resObj, "%s%s", "stat_rec", pePatStatStr(pat->patgrp->stat_rec)); + peAppListF(interp, resObj, "%s%s", "stat_del", pePatStatStr(pat->patgrp->stat_del)); + peAppListF(interp, resObj, "%s%s", "stat_imp", pePatStatStr(pat->patgrp->stat_imp)); + peAppListF(interp, resObj, "%s%s", "stat_ans", pePatStatStr(pat->patgrp->stat_ans)); + peAppListF(interp, resObj, "%s%s", "stat_8bitsubj", pePatStatStr(pat->patgrp->stat_8bitsubj)); + peAppListF(interp, resObj, "%s%s", "stat_bom", pePatStatStr(pat->patgrp->stat_bom)); + peAppListF(interp, resObj, "%s%s", "stat_boy", pePatStatStr(pat->patgrp->stat_boy)); + + Tcl_ListObjAppendElement(interp, patObj, resObj); +} + + +char * +pePatStatStr(int value) +{ + switch(value){ + case PAT_STAT_EITHER: + return("either"); + break; + + case PAT_STAT_YES: + return("yes"); + break; + + default : + return("no"); + break; + } +} + + +/* + * peCreateUserContext - create new ps_global and set it up + */ +char * +peCreateUserContext(Tcl_Interp *interp, char *user, char *config, char *defconf) +{ + if(ps_global) + peDestroyUserContext(&ps_global); + + set_collation(1, 1); + + ps_global = new_pine_struct(); + + /*---------------------------------------------------------------------- + Place any necessary constraints on pith processing + ----------------------------------------------------------------------*/ + + /* got thru close procedure without expunging */ + ps_global->noexpunge_on_close = 1; + + /* do NOT let user set path to local executable */ + ps_global->vars[V_SENDMAIL_PATH].is_user = 0; + + + /*---------------------------------------------------------------------- + Proceed with reading acquiring user settings + ----------------------------------------------------------------------*/ + if(ps_global->pinerc) + fs_give((void **) &ps_global->pinerc); + + if(ps_global->prc) + free_pinerc_s(&ps_global->prc); + + if(!IS_REMOTE(config)){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Non-Remote config: %s", config); + return(tmp_20k_buf); + } + + ps_global->prc = new_pinerc_s(config); + + if(defconf){ + if(ps_global->pconf) + free_pinerc_s(&ps_global->pconf); + + ps_global->pconf = new_pinerc_s(defconf); + } + + /* + * Fake up some user information + */ + ps_global->ui.login = cpystr(user); + +#ifdef DEBUG + /* + * Prep for IMAP debugging + */ + setup_imap_debug(); +#endif + + /* CHECK FOR AND PASS BACK ANY INIT ERRORS */ + return(peLoadConfig(ps_global)); +} + + + +void +peDestroyUserContext(struct pine **pps) +{ + + completely_done_with_adrbks(); + + free_pinerc_strings(pps); +#if 0 + imap_flush_passwd_cache(TRUE); +#endif + clear_index_cache(sp_inbox_stream(), 0); + free_newsgrp_cache(); + mailcap_free(); + close_patterns(0L); + free_extra_hdrs(); + free_contexts(&ps_global->context_list); + + pico_endcolor(); + + free_strlist(&peCertHosts); + + free_pine_struct(pps); +} + + +char * +peLoadConfig(struct pine *pine_state) +{ + int rv; + char *s, *db = NULL; + extern void init_signals(void); /* in signal.c */ + + if(!pine_state) + return("No global state present"); + +#if 0 +/*turned off because we don't care about local user*/ + /* need home directory early */ + get_user_info(&pine_state->ui); + + pine_state->home_dir = cpystr((getenv("HOME") != NULL) + ? getenv("HOME") + : pine_state->ui.homedir); +#endif + + init_pinerc(pine_state, &db); + + fs_give((void **) &db); + + /* + * Initial allocation of array of stream pool pointers. + * We do this before init_vars so that we can re-use streams used for + * remote config files. These sizes may get changed later. + */ + ps_global->s_pool.max_remstream = 2; + + ps_global->c_client_error[0] = '\0'; + + pePrepareForAuthException(); + + peInitVars(pine_state); + + if(s = peAuthException()) + return(s); + else if(ps_global->c_client_error[0]) + return(ps_global->c_client_error); + + mail_parameters(NULL, SET_SENDCOMMAND, (void *) pine_imap_cmd_happened); + mail_parameters(NULL, SET_FREESTREAMSPAREP, (void *) sp_free_callback); + mail_parameters(NULL, SET_FREEELTSPAREP, (void *) free_pine_elt); + + /* + * Install callback to handle certificate validation failures, + * allowing the user to continue if they wish. + */ + mail_parameters(NULL, SET_SSLCERTIFICATEQUERY, (void *) alpine_sslcertquery); + mail_parameters(NULL, SET_SSLFAILURE, (void *) alpine_sslfailure); + + /* + * Set up a c-client read timeout and timeout handler. In general, + * it shouldn't happen, but a server crash or dead link can cause + * pine to appear wedged if we don't set this up... + */ + mail_parameters(NULL, SET_OPENTIMEOUT, + (void *)((pine_state->VAR_TCPOPENTIMEO + && (rv = atoi(pine_state->VAR_TCPOPENTIMEO)) > 4) + ? (long) rv : 30L)); + mail_parameters(NULL, SET_TIMEOUT, (void *) alpine_tcptimeout); + + if(pine_state->VAR_RSHOPENTIMEO + && ((rv = atoi(pine_state->VAR_RSHOPENTIMEO)) == 0 || rv > 4)) + mail_parameters(NULL, SET_RSHTIMEOUT, (void *) rv); + + if(pine_state->VAR_SSHOPENTIMEO + && ((rv = atoi(pine_state->VAR_SSHOPENTIMEO)) == 0 || rv > 4)) + mail_parameters(NULL, SET_SSHTIMEOUT, (void *) rv); + + /* + * Tell c-client not to be so aggressive about uid mappings + */ + mail_parameters(NULL, SET_UIDLOOKAHEAD, (void *) 20); + + /* + * Setup referral handling + */ + mail_parameters(NULL, SET_IMAPREFERRAL, (void *) imap_referral); + mail_parameters(NULL, SET_MAILPROXYCOPY, (void *) imap_proxycopy); + + /* + * Install extra headers to fetch along with all the other stuff + * mail_fetch_structure and mail_fetch_overview requests. + */ + calc_extra_hdrs(); + + if(get_extra_hdrs()) + (void) mail_parameters(NULL, SET_IMAPEXTRAHEADERS, (void *) get_extra_hdrs()); + + (void) init_username(pine_state); + + (void) init_hostname(ps_global); + +#ifdef ENABLE_LDAP + (void) init_ldap_pname(ps_global); +#endif /* ENABLE_LDAP */ + + if(ps_global->prc && ps_global->prc->type == Loc && + can_access(ps_global->pinerc, ACCESS_EXISTS) == 0 && + can_access(ps_global->pinerc, EDIT_ACCESS) != 0) + ps_global->readonly_pinerc = 1; + + /* + * c-client needs USR2 and we might as well + * do something sensible with HUP and TERM + */ + init_signals(); + + strncpy(pine_state->inbox_name, INBOX_NAME, sizeof(pine_state->inbox_name)); + pine_state->inbox_name[sizeof(pine_state->inbox_name)-1] = '\0'; + + init_folders(pine_state); /* digest folder spec's */ + + /* + * Various options we want to make sure are set OUR way + */ + F_TURN_ON(F_QUELL_IMAP_ENV_CB, pine_state); + F_TURN_ON(F_SLCTBL_ITEM_NOBOLD, pine_state); + F_TURN_OFF(F_USE_SYSTEM_TRANS, pine_state); + + /* + * Fake screen dimensions for index formatting and + * message display wrap... + */ + ps_global->ttyo = (struct ttyo *) fs_get(sizeof(struct ttyo)); + ps_global->ttyo->screen_rows = FAKE_SCREEN_LENGTH; + ps_global->ttyo->screen_cols = FAKE_SCREEN_WIDTH; + if(ps_global->VAR_WP_COLUMNS){ + int w = atoi(ps_global->VAR_WP_COLUMNS); + if(w >= 20 && w <= 128) + ps_global->ttyo->screen_cols = w; + } + + ps_global->ttyo->header_rows = 0; + ps_global->ttyo->footer_rows = 0; + + + /* init colors */ + if(ps_global->VAR_NORM_FORE_COLOR) + pico_nfcolor(ps_global->VAR_NORM_FORE_COLOR); + + if(ps_global->VAR_NORM_BACK_COLOR) + pico_nbcolor(ps_global->VAR_NORM_BACK_COLOR); + + if(ps_global->VAR_REV_FORE_COLOR) + pico_rfcolor(ps_global->VAR_REV_FORE_COLOR); + + if(ps_global->VAR_REV_BACK_COLOR) + pico_rbcolor(ps_global->VAR_REV_BACK_COLOR); + + pico_set_normal_color(); + + return(NULL); +} + + +int +peCreateStream(Tcl_Interp *interp, CONTEXT_S *context, char *mailbox, int do_inbox) +{ + unsigned long flgs = 0L; + char *s; + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + + pePrepareForAuthException(); + + if(do_inbox) + flgs |= DB_INBOXWOCNTXT; + + if(do_broach_folder(mailbox, context, NULL, flgs) && ps_global->mail_stream){ + dprint((SYSDBG_INFO, "Mailbox open: %s", + ps_global->mail_stream->mailbox ? ps_global->mail_stream->mailbox : "<UNKNOWN>")); + return(TCL_OK); + } + + Tcl_SetResult(interp, + (s = peAuthException()) + ? s + : (*ps_global->last_error) + ? ps_global->last_error + : "Login Error", + TCL_VOLATILE); + return(TCL_ERROR); +} + + +void +peDestroyStream(struct pine *ps) +{ + int cur_is_inbox; + + if(ps){ + cur_is_inbox = (sp_inbox_stream() == ps_global->mail_stream); + + /* clean up open streams */ + if(ps->mail_stream){ + expunge_and_close(ps->mail_stream, NULL, EC_NONE); + ps_global->mail_stream = NULL; + ps_global->cur_folder[0] = '\0'; + } + + if(ps->msgmap) + mn_give(&ps->msgmap); + + if(sp_inbox_stream() && !cur_is_inbox){ + ps->mail_stream = sp_inbox_stream(); + ps->msgmap = sp_msgmap(ps->mail_stream); + sp_set_expunge_count(ps_global->mail_stream, 0L); + expunge_and_close(sp_inbox_stream(), NULL, EC_NONE); + mn_give(&ps->msgmap); + } + } +} + + +/* + * pePrepareForAuthException - set globals to get feedback from bowels of c-client + */ +void +pePrepareForAuthException(void) +{ + peNoPassword = peCredentialError = peCertFailure = peCertQuery = 0; +} + +/* + * pePrepareForAuthException - check globals getting feedback from bowels of c-client + */ +char * +peAuthException() +{ + static char buf[CRED_REQ_SIZE]; + + if(peCertQuery){ + snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_QUERY_STRING, peCredentialRequestor); + return(buf); + } + + if(peCertFailure){ + snprintf(buf, CRED_REQ_SIZE, "%s %s", CERT_FAILURE_STRING, peCredentialRequestor); + return(buf); + } + + if(peNoPassword){ + snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_EMPTY_STRING, peCredentialRequestor); + return(buf); + } + + if(peCredentialError){ + snprintf(buf, CRED_REQ_SIZE, "%s %s", AUTH_FAILURE_STRING, peCredentialRequestor); + return(buf); + } + + return(NULL); +} + + +void +peInitVars(struct pine *ps) +{ + init_vars(ps, NULL); + + /* + * fix display/keyboard-character-set to utf-8 + * + * + */ + + if(ps->display_charmap) + fs_give((void **) &ps->display_charmap); + + ps->display_charmap = cpystr(WP_INTERNAL_CHARSET); + + if(ps->keyboard_charmap) + fs_give((void **) &ps->keyboard_charmap); + + ps->keyboard_charmap = cpystr(WP_INTERNAL_CHARSET); + + (void) setup_for_input_output(FALSE, &ps->display_charmap, &ps->keyboard_charmap, &ps->input_cs, NULL);; +} + + + +int +peMessageBounce(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *errstr = NULL, *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1]; + long rawno; + ENVELOPE *env, *outgoing = NULL; + METAENV *metaenv; + PINEFIELD *custom; + BODY *body = NULL; + + if(uid){ + rawno = peSequenceNumber(uid); + + if(objc > 0 && objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL))){ + if(objc == 2 && objv[1]){ + subj = Tcl_GetStringFromObj(objv[1], NULL); + } + else if((env = mail_fetchstructure(ps_global->mail_stream, rawno, NULL)) != NULL){ + subj = env->subject; + } + else{ + Tcl_SetResult(interp, ps_global->last_error, TCL_VOLATILE); + return(TCL_ERROR); + } + + if((errstr = bounce_msg_body(ps_global->mail_stream, rawno, NULL, + &to, subj, &outgoing, &body, NULL))){ + Tcl_SetResult(interp, errstr, TCL_VOLATILE); + return(TCL_ERROR); + } + + metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs()); + + if(!outgoing->from) + outgoing->from = generate_from(); + + rfc822_date(tmp_20k_buf); + outgoing->date = (unsigned char *) cpystr(tmp_20k_buf); + + outgoing->return_path = rfc822_cpy_adr(outgoing->from); + if(!outgoing->message_id) + outgoing->message_id = generate_message_id(); + + /* NO FCC */ + + if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK) + errstr = errbuf; + + pine_free_body(&body); + + pine_free_env(&metaenv); + + if(custom) + free_customs(custom); + + mail_free_envelope(&outgoing); + pine_free_body(&body); + + } + } + + Tcl_SetResult(interp, (errstr) ? errstr : "OK", TCL_VOLATILE); + return(errstr ? TCL_ERROR : TCL_OK); +} + + +int +peMessageSpamNotice(interp, uid, objc, objv) + Tcl_Interp *interp; + imapuid_t uid; + int objc; + Tcl_Obj **objv; +{ + char *to, *subj = NULL, errbuf[WP_MAX_POST_ERROR + 1], *rs = NULL; + long rawno; + + if(uid){ + rawno = peSequenceNumber(uid); + + if(objv[0] && (to = Tcl_GetStringFromObj(objv[0], NULL)) && strlen(to)){ + + if(objv[1]) + subj = Tcl_GetStringFromObj(objv[1], NULL); + + rs = peSendSpamReport(rawno, to, subj, errbuf); + } + } + + Tcl_SetResult(interp, (rs) ? rs : "OK", TCL_VOLATILE); + return(rs ? TCL_ERROR : TCL_OK); +} + + +char * +peSendSpamReport(long rawno, char *to, char *subj, char *errbuf) +{ + char *errstr = NULL, *tmp_a_string; + ENVELOPE *env, *outgoing; + METAENV *metaenv; + PINEFIELD *custom; + BODY *body; + static char *fakedomain = "@"; + void *msgtext; + + + if((env = mail_fetchstructure(ps_global->mail_stream, rawno, NULL)) == NULL){ + return(ps_global->last_error); + } + + /* empty subject gets "spam" subject */ + if(!(subj && *subj)) + subj = env->subject; + + /*---- New Body to start with ----*/ + body = mail_newbody(); + body->type = TYPEMULTIPART; + + /*---- The TEXT part/body ----*/ + body->nested.part = mail_newbody_part(); + body->nested.part->body.type = TYPETEXT; + + if((msgtext = (void *)so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){ + pine_free_body(&body); + return("peSendSpamReport: Can't allocate text"); + } + else{ + sprintf(tmp_20k_buf, + "The attached message is being reported to <%s> as Spam\n", + to); + so_puts((STORE_S *) msgtext, tmp_20k_buf); + body->nested.part->body.contents.text.data = msgtext; + } + + /*---- Attach the raw message ----*/ + if(forward_mime_msg(ps_global->mail_stream, rawno, NULL, env, + &(body->nested.part->next), msgtext)){ + outgoing = mail_newenvelope(); + metaenv = pine_new_env(outgoing, NULL, NULL, custom = peCustomHdrs()); + } + else{ + pine_free_body(&body); + return("peSendSpamReport: Can't generate forwarded message"); + } + + /* rfc822_parse_adrlist feels free to destroy input so copy */ + tmp_a_string = cpystr(to); + rfc822_parse_adrlist(&outgoing->to, tmp_a_string, + (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)) + ? fakedomain : ps_global->maildomain); + fs_give((void **) &tmp_a_string); + + outgoing->from = generate_from(); + outgoing->subject = cpystr(subj); + outgoing->return_path = rfc822_cpy_adr(outgoing->from); + outgoing->message_id = generate_message_id(); + + rfc822_date(tmp_20k_buf); + outgoing->date = (unsigned char *) cpystr(tmp_20k_buf); + + /* NO FCC for Spam Reporting */ + + if(peDoPost(metaenv, body, NULL, NULL, errbuf) != TCL_OK) + errstr = errbuf; + + pine_free_body(&body); + + pine_free_env(&metaenv); + + if(custom) + free_customs(custom); + + mail_free_envelope(&outgoing); + pine_free_body(&body); + + return(errstr); +} + + +/* * * * * * * * * * * * * Start of Composer Routines * * * * * * * * * * * */ + + +/* + * PEComposeCmd - export various bits of alpine state + */ +int +PEComposeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err = "PECompose: Unknown request"; + + dprint((2, "PEComposeCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else if(!ps_global){ + Tcl_SetResult(interp, "peCompose: no config present", TCL_STATIC); + return(TCL_ERROR); + } + else{ + char *s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(!strcmp(s1, "post")){ + long flags = PMC_NONE; + if(F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)) + flags |= PMC_FORCE_QUAL; + + return(peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPost, flags)); + } + else if(objc == 2){ + if(!strcmp(s1, "userhdrs")){ + int i; + char *p; + PINEFIELD *custom, *cp; + ADDRESS *from; + static char *standard[] = {"To", "Cc", "Bcc", "Fcc", "Attach", "Subject", NULL}; + + custom = peCustomHdrs(); + + for(i = 0; standard[i]; i++){ + p = NULL; + for(cp = custom; cp; cp = cp->next) + if(!strucmp(cp->name, standard[i])) + p = cp->textbuf; + + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", standard[i], p); + } + + for(cp = custom; cp != NULL; cp = cp->next){ + if(!strucmp(cp->name, "from")){ + if(F_OFF(F_ALLOW_CHANGING_FROM, ps_global)) + continue; + + if(cp->textbuf && strlen(cp->textbuf)){ + p = cp->textbuf; + } + else{ + RFC822BUFFER rbuf; + + tmp_20k_buf[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = tmp_20k_buf; + rbuf.cur = tmp_20k_buf; + rbuf.end = tmp_20k_buf+SIZEOF_20KBUF-1; + rfc822_output_address_list(&rbuf, from = generate_from(), 0L, NULL); + *rbuf.cur = '\0'; + mail_free_address(&from); + p = tmp_20k_buf; + } + } + else{ + p = cp->textbuf; + for(i = 0; standard[i]; i++) + if(!strucmp(standard[i], cp->name)) + p = NULL; + + if(!p) + continue; + } + + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", cp->name, p); + } + + if(custom) + free_customs(custom); + + return(TCL_OK); + } + else if(!strcmp(s1, "syshdrs")){ + int i; + static char *extras[] = {"In-Reply-To", "X-Reply-UID", NULL}; + + for(i = 0; extras[i]; i++) + peAppListF(interp, Tcl_GetObjResult(interp), "%s%s", extras[i], NULL); + + return(TCL_OK); + } + else if(!strcmp(s1, "composehdrs")){ + char **p, *q; + + if((p = ps_global->VAR_COMP_HDRS) && *p){ + for(; *p; p++) + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(*p, (q = strchr(*p, ':')) + ? (q - *p) : -1)); + } + else + Tcl_SetResult(interp, "", TCL_STATIC); + + return(TCL_OK); + } + else if(!strcmp(s1, "fccdefault")){ + int ci = 0; + CONTEXT_S *c = default_save_context(ps_global->context_list), *c2; + + for(c2 = ps_global->context_list; c && c != c2; c2 = c2->next) + ci++; + + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewIntObj(ci)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ps_global->VAR_DEFAULT_FCC + ? ps_global->VAR_DEFAULT_FCC + : "", -1)); + return(TCL_OK); + } + else if(!strcmp(s1, "noattach")){ + peFreeAttach(&peCompAttach); + Tcl_SetResult(interp, "OK", TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "from")){ + RFC822BUFFER rbuf; + ADDRESS *from = generate_from(); + tmp_20k_buf[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = tmp_20k_buf; + rbuf.cur = tmp_20k_buf; + rbuf.end = tmp_20k_buf+SIZEOF_20KBUF-1; + rfc822_output_address_list(&rbuf, from, 0L, NULL); + *rbuf.cur = '\0'; + mail_free_address(&from); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_OK); + } + else if(!strcmp(s1, "attachments")){ + COMPATT_S *p; + Tcl_Obj *objAttach; + + for(p = peCompAttach; p; p = p->next) + if(p->file){ + objAttach = Tcl_NewListObj(0, NULL); + + /* id */ + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1)); + + /* file name */ + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->l.f.remote,-1)); + + /* file size */ + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewLongObj(p->l.f.size)); + + /* type/subtype */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", p->l.f.type, p->l.f.subtype); + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(tmp_20k_buf,-1)); + + /* append to list */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach); + } + else if(p->body){ + char *name; + + objAttach = Tcl_NewListObj(0, NULL); + + /* id */ + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(p->id,-1)); + + /* file name */ + if((name = get_filename_parameter(NULL, 0, p->l.b.body, NULL)) != NULL){ + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(name, -1)); + fs_give((void **) &name); + } + else + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj("Unknown", -1)); + + /* file size */ + Tcl_ListObjAppendElement(interp, objAttach, + Tcl_NewLongObj((p->l.b.body->encoding == ENCBASE64) + ? ((p->l.b.body->size.bytes * 3)/4) + : p->l.b.body->size.bytes)); + + /* type/subtype */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", + body_type_names(p->l.b.body->type), + p->l.b.body->subtype ? p->l.b.body->subtype : "Unknown"); + Tcl_ListObjAppendElement(interp, objAttach, Tcl_NewStringObj(tmp_20k_buf, -1)); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach); + } + + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(s1, "unattach")){ + char *id; + + if((id = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(peClearAttachID(id)){ + Tcl_SetResult(interp, "OK", TCL_STATIC); + return(TCL_OK); + } + else + err = "Can't access attachment id"; + } + else + err = "Can't read attachment id"; + } + else if(!strcmp(s1, "attachinfo")){ + COMPATT_S *a; + char *id, *s; + + /* return: remote-filename size "type/subtype" */ + if((id = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if((a = peGetAttachID(id)) != NULL){ + if(a->file){ + /* file name */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(a->l.f.remote,-1)); + + /* file size */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewLongObj(a->l.f.size)); + + /* type/subtype */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", a->l.f.type, a->l.f.subtype); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(tmp_20k_buf,-1)); + + /* description */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj((a->l.f.description) ? a->l.f.description : "",-1)); + return(TCL_OK); + } + else if(a->body){ + char *name; + + /* file name */ + if((name = get_filename_parameter(NULL, 0, a->l.b.body, NULL)) != NULL){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(name, -1)); + fs_give((void **) &name); + } + else + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj("Unknown", -1)); + + /* file size */ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewLongObj((a->l.b.body->encoding == ENCBASE64) + ? ((a->l.b.body->size.bytes * 3)/4) + : a->l.b.body->size.bytes)); + + /* type/subtype */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", + body_type_names(a->l.b.body->type), + a->l.b.body->subtype ? a->l.b.body->subtype : "Unknown"); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(tmp_20k_buf, -1)); + + /* description */ + if(a->l.b.body->description){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, a->l.b.body->description); + } + else if((s = parameter_val(a->l.b.body->parameter, "description")) != NULL){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", 256, s); + fs_give((void **) &s); + } + else + tmp_20k_buf[0] = '\0'; + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), Tcl_NewStringObj(tmp_20k_buf, -1)); + + return(TCL_OK); + } + + err = "Unknown attachment type"; + } + else + err = "Can't access attachment id"; + } + else + err = "Can't read attachment id"; + } + } + else if(objc == 7){ + if(!strcmp(s1, "attach")){ + char *file, *remote, *type, *subtype, *desc; + + if((file = Tcl_GetStringFromObj(objv[2], NULL)) + && (type = Tcl_GetStringFromObj(objv[3], NULL)) + && (subtype = Tcl_GetStringFromObj(objv[4], NULL)) + && (remote = Tcl_GetStringFromObj(objv[5], NULL))){ + int dl; + + desc = Tcl_GetStringFromObj(objv[6], &dl); + + if(desc){ + Tcl_SetResult(interp, peFileAttachID(file, type, subtype, remote, desc, dl), TCL_VOLATILE); + return(TCL_OK); + } + else + err = "Can't read file description"; + } + else + err = "Can't read file name"; + } + } + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +COMPATT_S * +peNewAttach(void) +{ + COMPATT_S *p = (COMPATT_S *) fs_get(sizeof(COMPATT_S)); + memset(p, 0, sizeof(COMPATT_S)); + return(p); +} + + +void +peFreeAttach(COMPATT_S **a) +{ + if(a && *a){ + fs_give((void **) &(*a)->id); + + if((*a)->file){ + if((*a)->l.f.type) + fs_give((void **) &(*a)->l.f.type); + + if((*a)->l.f.subtype) + fs_give((void **) &(*a)->l.f.subtype); + + if((*a)->l.f.remote) + fs_give((void **) &(*a)->l.f.remote); + + if((*a)->l.f.local){ + (void) unlink((*a)->l.f.local); + fs_give((void **) &(*a)->l.f.local); + } + + if((*a)->l.f.description) + fs_give((void **) &(*a)->l.f.description); + } + else if((*a)->body){ + pine_free_body(&(*a)->l.b.body); + } + + peFreeAttach(&(*a)->next); + fs_give((void **) a); + } +} + + +char * +peFileAttachID(char *f, char *t, char *st, char *r, char *d, int dl) +{ + COMPATT_S *ap = peNewAttach(), *p; + long hval; + + ap->file = TRUE; + ap->l.f.local = cpystr(f); + ap->l.f.size = name_file_size(f); + + hval = line_hash(f); + while(1) /* collisions? */ + if(peGetAttachID(ap->id = cpystr(long2string(hval)))){ + fs_give((void **) &ap->id); + hval += 1; + } + else + break; + + ap->l.f.remote = cpystr(r ? r : ""); + ap->l.f.type = cpystr(t ? t : "Text"); + ap->l.f.subtype = cpystr(st ? st : "Plain"); + + ap->l.f.description = fs_get(dl + 1); + snprintf(ap->l.f.description, dl + 1, "%s", d); + + if((p = peCompAttach) != NULL){ + do + if(!p->next){ + p->next = ap; + break; + } + while((p = p->next) != NULL); + } + else + peCompAttach = ap; + + return(ap->id); +} + + +char * +peBodyAttachID(BODY *b) +{ + COMPATT_S *ap = peNewAttach(), *p; + unsigned long hval; + + ap->body = TRUE; + ap->l.b.body = copy_body(NULL, b); + + hval = b->id ? line_hash(b->id) : time(0); + while(1) /* collisions? */ + if(peGetAttachID(ap->id = cpystr(ulong2string(hval)))){ + fs_give((void **) &ap->id); + hval += 1; + } + else + break; + + /* move contents pointer to copy */ + peBodyMoveContents(b, ap->l.b.body); + + if((p = peCompAttach) != NULL){ + do + if(!p->next){ + p->next = ap; + break; + } + while((p = p->next) != NULL); + } + else + peCompAttach = ap; + + return(ap->id); +} + + +void +peBodyMoveContents(BODY *bs, BODY *bd) +{ + if(bs && bd){ + if(bs->type == TYPEMULTIPART && bd->type == TYPEMULTIPART){ + PART *ps = bs->nested.part, + *pd = bd->nested.part; + do /* for each part */ + peBodyMoveContents(&ps->body, &pd->body); + while ((ps = ps->next) && (pd = pd->next)); /* until done */ + } + else if(bs->contents.text.data){ + bd->contents.text.data = bs->contents.text.data; + bs->contents.text.data = NULL; + } + } +} + + + +COMPATT_S * +peGetAttachID(char *h) +{ + COMPATT_S *p; + + for(p = peCompAttach; p; p = p->next) + if(!strcmp(p->id, h)) + return(p); + + return(NULL); +} + + +int +peClearAttachID(char *h) +{ + COMPATT_S *pp, *pt = NULL; + + for(pp = peCompAttach; pp; pp = pp->next){ + if(!strcmp(pp->id, h)){ + if(pt) + pt->next = pp->next; + else + peCompAttach = pp->next; + + pp->next = NULL; + peFreeAttach(&pp); + return(TRUE); + } + + pt = pp; + } + + return(FALSE); +} + + +/* + * peDoPost - handle preparing header and body text for posting, prepare + * for any Fcc, then call the mailer to send it out + */ +int +peDoPost(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp) +{ + int rv = TCL_OK, recipients; + char *s; + + if(commence_fcc(fcc, fcc_cntxtp, TRUE)){ + + ps_global->c_client_error[0] = ps_global->last_error[0] = '\0'; + pePrepareForAuthException(); + + if((recipients = (metaenv->env->to || metaenv->env->cc || metaenv->env->bcc)) + && call_mailer(metaenv, body, NULL, 0, NULL, NULL) < 0){ + if(s = peAuthException()){ + strcpy(errp, s); + } + else if(ps_global->last_error[0]){ + sprintf(errp, "Send Error: %.*s", 64, ps_global->last_error); + } + else if(ps_global->c_client_error[0]){ + sprintf(errp, "Send Error: %.*s", 64, ps_global->c_client_error); + } + else + strcpy(errp, "Sending Failure"); + + rv = TCL_ERROR; + dprint((1, "call_mailer failed!")); + } + else if(fcc && fcc_cntxtp && !wrapup_fcc(fcc, *fcc_cntxtp, recipients ? NULL : metaenv, body)){ + strcpy(errp, "Fcc Failed!. No message saved."); + rv = TCL_ERROR; + dprint((1, "explicit fcc write failed!")); + } + else{ + PINEFIELD *pf; + REPLY_S *reply = NULL; + + /* success, now look for x-reply-uid to flip answered flag for? */ + + for(pf = metaenv->local; pf && pf->name; pf = pf->next) + if(!strucmp(pf->name, "x-reply-uid")){ + if(pf->textbuf){ + if((reply = (REPLY_S *) build_reply_uid(pf->textbuf)) != NULL){ + + update_answered_flags(reply); + + if(reply->mailbox) + fs_give((void **) &reply->mailbox); + + if(reply->prefix) + fs_give((void **) &reply->prefix); + + if(reply->data.uid.msgs) + fs_give((void **) &reply->data.uid.msgs); + + fs_give((void **) &reply); + } + } + + break; + } + } + } + else{ + dprint((1,"can't open fcc, cont")); + + strcpy(errp, "Can't open Fcc"); + rv = TCL_ERROR; + } + + return(rv); +} + + + +/* + * pePostponeCmd - export various bits of alpine state + */ +int +PEPostponeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err = "PEPostpone: unknown request"; + imapuid_t uid; + + dprint((2, "PEPostponeCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else if(!ps_global){ + Tcl_SetResult(interp, "pePostpone: no config present", TCL_STATIC); + return(TCL_ERROR); + } + else{ + char *s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(!strcmp(s1, "extract")){ + if(Tcl_GetLongFromObj(interp, objv[2], &uid) == TCL_OK){ + Tcl_Obj *objHdr = NULL, *objBod = NULL, *objAttach = NULL, *objOpts = NULL; + MAILSTREAM *stream; + BODY *b; + ENVELOPE *env = NULL; + PINEFIELD *custom = NULL, *cp; + REPLY_S *reply = NULL; + ACTION_S *role = NULL; + STORE_S *so; + long n; + int rv = TCL_OK; + char *fcc = NULL, *lcc = NULL; + unsigned flags = REDRAFT_DEL | REDRAFT_PPND; + + if(objc > 3){ /* optional flags */ + int i, nFlags; + Tcl_Obj **objFlags; + char *flagstr; + + Tcl_ListObjGetElements(interp, objv[3], &nFlags, &objFlags); + for(i = 0; i < nFlags; i++){ + if((flagstr = Tcl_GetStringFromObj(objFlags[i], NULL)) == NULL){ + rv = TCL_ERROR; + } + + if(!strucmp(flagstr, "html")) + flags |= REDRAFT_HTML; + } + } + /* BUG: should probably complain if argc > 4 */ + + if(rv == TCL_OK + && postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) + && stream){ + if((so = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + if((n = mail_msgno(stream, uid)) > 0L){ + if(redraft_work(&stream, n, &env, &b, &fcc, &lcc, &reply, + NULL, &custom, &role, /* should role be NULL? */ + flags, so)){ + char *charset = NULL; + + /* prepare to package up for caller */ + objHdr = Tcl_NewListObj(0, NULL); + + /* determine body part's charset */ + if((charset = parameter_val(b->parameter,"charset")) != NULL){ + objOpts = Tcl_NewListObj(0, NULL); + peAppListF(interp, objOpts, "%s%s", "charset", charset); + fs_give((void **) &charset); + } + + /* body part's MIME subtype */ + if(b->subtype && strucmp(b->subtype,"plain")){ + if(!objOpts) + objOpts = Tcl_NewListObj(0, NULL); + + peAppListF(interp, objOpts, "%s%s", "subtype", b->subtype); + } + + peAppListF(interp, objHdr, "%s%a", "from", + role && role->from ? role->from : env->from); + peAppListF(interp, objHdr, "%s%a", "to", env->to); + peAppListF(interp, objHdr, "%s%a", "cc", env->cc); + peAppListF(interp, objHdr, "%s%a", "bcc", env->bcc); + peAppListF(interp, objHdr, "%s%s", "in-reply-to", env->in_reply_to); + peAppListF(interp, objHdr, "%s%s", "subject", + rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, + SIZEOF_20KBUF, env->subject)); + + if(fcc) + peFccAppend(interp, objHdr, fcc, -1); + + for(cp = custom; cp && cp->name; cp = cp->next) + switch(cp->type){ + case Address : + strncpy(tmp_20k_buf, cp->name, SIZEOF_20KBUF); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + peAppListF(interp, objHdr, "%s%a", + lcase((unsigned char *) tmp_20k_buf), *cp->addr); + break; + + case Attachment : + break; + + case Fcc : + case Subject : + break; /* ignored */ + + default : + strncpy(tmp_20k_buf, cp->name, SIZEOF_20KBUF); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + peAppListF(interp, objHdr, "%s%s", + lcase((unsigned char *) tmp_20k_buf), cp->textbuf ? cp->textbuf : cp->val); + break; + } + + if(reply){ + /* blat x-Reply-UID: for possible use? */ + if(reply->uid){ + char uidbuf[MAILTMPLEN], *p; + long i; + + for(i = 0L, p = tmp_20k_buf; reply->data.uid.msgs[i]; i++){ + if(i) + sstrncpy(&p, ",", SIZEOF_20KBUF-(p-tmp_20k_buf)); + + sstrncpy(&p,ulong2string(reply->data.uid.msgs[i]), SIZEOF_20KBUF-(p-tmp_20k_buf)); + } + + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + + snprintf(uidbuf, sizeof(uidbuf), "(%s%s%s)(%ld %lu %s)%s", + reply->prefix ? int2string(strlen(reply->prefix)) + : (reply->forwarded) ? "" : "0 ", + reply->prefix ? " " : "", + reply->prefix ? reply->prefix : "", + i, reply->data.uid.validity, + tmp_20k_buf, reply->mailbox); + + peAppListF(interp, objHdr, "%s%s", "x-reply-uid", uidbuf); + } + + fs_give((void **) &reply->mailbox); + fs_give((void **) &reply->prefix); + fs_give((void **) &reply->data.uid.msgs); + fs_give((void **) &reply); + } + + objBod = Tcl_NewListObj(0, NULL); + peSoStrToList(interp, objBod, so); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objHdr); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objBod); + + objAttach = peMsgAttachCollector(interp, b); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objAttach); + + if(objOpts){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),objOpts); + } + + /* clean up */ + if(fcc) + fs_give((void **) &fcc); + + if(lcc) + fs_give((void **) &lcc); + + mail_free_envelope(&env); + pine_free_body(&b); + free_action(&role); + + /* if Drafts got whacked, open INBOX */ + if(!ps_global->mail_stream) + do_broach_folder(ps_global->inbox_name, + ps_global->context_list, + NULL, DB_INBOXWOCNTXT); + + return(TCL_OK); + } + + so_give(&so); + } + else + err = "Unknown UID"; + } + else + err = "No internal storage"; + + /* redraft_work cleaned up the "stream" */ + } + else + err = "No Postponed stream"; + } + else + err = "Malformed extract request"; + } + else if(objc == 2){ + if(!strcmp(s1, "any")){ + MAILSTREAM *stream; + + if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){ + Tcl_SetResult(interp, "1", TCL_STATIC); + + if(stream != ps_global->mail_stream) + pine_mail_close(stream); + } + else + Tcl_SetResult(interp, "0", TCL_STATIC); + + return(TCL_OK); + } + else if(!strcmp(s1, "count")){ + MAILSTREAM *stream; + + if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){ + Tcl_SetResult(interp, long2string(stream->nmsgs), TCL_STATIC); + + if(stream != ps_global->mail_stream) + pine_mail_close(stream); + } + else + Tcl_SetResult(interp, "-1", TCL_STATIC); + + return(TCL_OK); + } + else if(!strcmp(s1, "list")){ + MAILSTREAM *stream; + ENVELOPE *env; + Tcl_Obj *objEnv = NULL, *objEnvList; + long n; + + if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){ + if(!stream->nmsgs){ + (void) redraft_cleanup(&stream, FALSE, REDRAFT_PPND); + Tcl_SetResult(interp, "", TCL_STATIC); + return(TCL_OK); + } + + objEnvList = Tcl_NewListObj(0, NULL); + + for(n = 1; n <= stream->nmsgs; n++){ + if((env = pine_mail_fetchstructure(stream, n, NULL)) != NULL){ + objEnv = Tcl_NewListObj(0, NULL); + + peAppListF(interp, objEnv, "%s%s", "uid", + ulong2string(mail_uid(stream, n))); + + peAppListF(interp, objEnv, "%s%a", "to", env->to); + + date_str((char *)env->date, iSDate, 1, tmp_20k_buf, SIZEOF_20KBUF, 0); + + peAppListF(interp, objEnv, "%s%s", "date", tmp_20k_buf); + + peAppListF(interp, objEnv, "%s%s", "subj", + rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, + SIZEOF_20KBUF, env->subject)); + + Tcl_ListObjAppendElement(interp, objEnvList, objEnv); + } + } + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objEnvList); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("utf-8", -1)); + + if(stream != ps_global->mail_stream) + pine_mail_close(stream); + } + + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(s1, "append")){ + int rv; + + if((rv = peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone, PMC_NONE)) == TCL_OK) + Tcl_SetResult(interp, ulong2string(get_last_append_uid()), TCL_VOLATILE); + + return(rv); + } + else if(!strcmp(s1, "draft")){ + int rv; + + if((rv = peMsgCollector(interp, objc - 2, (Tcl_Obj **) &objv[2], peDoPostpone, PMC_PRSRV_ATT)) == TCL_OK) + Tcl_SetResult(interp, ulong2string(get_last_append_uid()), TCL_VOLATILE); + + return(rv); + } + else if(!strcmp(s1, "delete")){ + if(Tcl_GetLongFromObj(interp, objv[2], &uid) == TCL_OK){ + MAILSTREAM *stream; + long rawno; + + if(postponed_stream(&stream, ps_global->VAR_POSTPONED_FOLDER, "Postponed", 0) && stream){ + if((rawno = mail_msgno(stream, uid)) > 0L){ + mail_flag(stream, long2string(rawno), "\\DELETED", ST_SET); + ps_global->expunge_in_progress = 1; + mail_expunge(stream); + ps_global->expunge_in_progress = 0; + if(stream != ps_global->mail_stream) + pine_mail_actually_close(stream); + + return(TCL_OK); + } + else + err = "PEPostpone delete: UID no longer exists"; + } + else + err = "PEPostpone delete: No Postponed stream"; + } + else + err = "PEPostpone delete: No uid provided"; + } + } + } + } + + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +/* + * peDoPostpone - handle postponing after message collection + */ +int +peDoPostpone(METAENV *metaenv, BODY *body, char *fcc, CONTEXT_S **fcc_cntxtp, char *errp) +{ + PINEFIELD *pf; + int rv; + appenduid_t *au; + + /* + * resolve fcc and store it in fcc custom header field data + */ + if(fcc && *fcc && fcc_cntxtp && *fcc_cntxtp) + for(pf = metaenv->local; pf && pf->name; pf = pf->next) + if(!strucmp("fcc", pf->name)){ + char *name, *rs, path_in_context[MAILTMPLEN]; + + if(pf->textbuf) /* free old value */ + fs_give((void **) &pf->textbuf); + + /* replace nickname with full name */ + if(!(name = folder_is_nick(fcc, FOLDERS(*fcc_cntxtp), FN_NONE))) + name = fcc; + + if(context_isambig(name) && !(((*fcc_cntxtp)->use) & CNTXT_SAVEDFLT)){ + context_apply(path_in_context, *fcc_cntxtp, name, sizeof(path_in_context)); + rs = IS_REMOTE(path_in_context) ? path_in_context : NULL; + } + else + rs = cpystr(name); + + if(rs){ + pf->textbuf = cpystr(rs); + pf->text = &pf->textbuf; + } + + break; + } + + au = mail_parameters(NIL, GET_APPENDUID, NIL); + mail_parameters(NIL, SET_APPENDUID, (void *) appenduid_cb); + + rv = write_postponed(metaenv, body); + + mail_parameters(NIL, SET_APPENDUID, (void *) au); + + return((rv < 0) ? TCL_ERROR : TCL_OK); +} + + +/* + * peMsgCollector - Collect message parts and call specified handler + */ +int +peMsgCollector(Tcl_Interp *interp, + int objc, + Tcl_Obj **objv, + int (*postfunc)(METAENV *, BODY *, char *, CONTEXT_S **, char *), + long flags) +{ + Tcl_Obj **objMsg, **objField, **objBody; + int i, j, vl, nMsg, nField, nBody; + char *field, *value, *err = NULL; + MSG_COL_S md; + PINEFIELD *pf; + STRLIST_S *tp, *lp; + static char *fakedomain = "@"; + + memset(&md, 0, sizeof(MSG_COL_S)); + md.postop_fcc_no_attach = -1; + md.postfunc = postfunc; + md.qualified_addrs = ((flags & PMC_FORCE_QUAL) == PMC_FORCE_QUAL); + + if(objc != 1){ + Tcl_SetResult(interp, "Malformed message data", TCL_STATIC); + return(TCL_ERROR); + } + else if(!ps_global){ + Tcl_SetResult(interp, "No open folder", TCL_STATIC); + return(TCL_ERROR); + } + + md.outgoing = mail_newenvelope(); + + md.metaenv = pine_new_env(md.outgoing, NULL, NULL, md.custom = peCustomHdrs()); + + Tcl_ListObjGetElements(interp, objv[0], &nMsg, &objMsg); + for(i = 0; i < nMsg; i++){ + if(Tcl_ListObjGetElements(interp, objMsg[i], &nField, &objField) != TCL_OK){ + err = ""; /* interp's result object has error message */ + return(peMsgCollected(interp, &md, err, flags)); + } + + if(nField && (field = Tcl_GetStringFromObj(objField[0], NULL))){ + if(!strcmp(field, "body")){ + if(md.msgtext){ + err = "Too many bodies"; + return(peMsgCollected(interp, &md, err, flags)); + } + else if((md.msgtext = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + /* mark storage object as user edited */ + (void) so_attr(md.msgtext, "edited", "1"); + + Tcl_ListObjGetElements(interp, objField[1], &nBody, &objBody); + for(j = 0; j < nBody; j++){ + value = Tcl_GetStringFromObj(objBody[j], &vl); + if(value){ + so_nputs(md.msgtext, value, vl); + so_puts(md.msgtext, "\n"); + } + else{ + err = "Value read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + } + else { + err = "Can't acquire body storage"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(field, "attach")){ + char *id; + COMPATT_S *a; + + if(nField == 2 + && (id = Tcl_GetStringFromObj(objField[1], NULL)) + && (a = peGetAttachID(id))){ + tp = new_strlist(id); + if((lp = md.attach) != NULL){ + do + if(!lp->next){ + lp->next = tp; + break; + } + while((lp = lp->next) != NULL); + } + else + md.attach = tp; + } + else{ + strcpy(err = tmp_20k_buf, "Unknown attachment ID"); + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(field, "fcc")){ + Tcl_Obj **objFcc; + int nFcc; + + if(Tcl_ListObjGetElements(interp, objField[1], &nFcc, &objFcc) == TCL_OK + && nFcc == 2 + && Tcl_GetIntFromObj(interp, objFcc[0], &md.fcc_colid) == TCL_OK + && (value = Tcl_GetStringFromObj(objFcc[1], NULL))){ + if(md.fcc) + fs_give((void **) &md.fcc); + + md.fcc = cpystr(value); + } + else { + strcpy(err = tmp_20k_buf, "Unrecognized Fcc specification"); + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(field, "postoption")){ + Tcl_Obj **objPO; + int nPO, ival; + + value = NULL; + if(Tcl_ListObjGetElements(interp, objField[1], &nPO, &objPO) == TCL_OK + && nPO == 2 + && (value = Tcl_GetStringFromObj(objPO[0], NULL))){ + if(!strucmp(value,"fcc-without-attachments")){ + if(Tcl_GetIntFromObj(interp, objPO[1], &ival) == TCL_OK){ + md.postop_fcc_no_attach = (ival != 0); + } + else{ + sprintf(err = tmp_20k_buf, "Malformed Post Option: fcc-without-attachments"); + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(value, "charset")){ + if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){ + char *p; + + for(p = value; ; p++){ /* sanity check */ + if(!*p){ + md.charset = cpystr(value); + break; + } + + if(isspace((unsigned char ) *p) + || !isprint((unsigned char) *p)) + break; + + if(p - value > 255) + break; + } + } + else{ + err = "Post option read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(value, "flowed")){ + if(F_OFF(F_QUELL_FLOWED_TEXT,ps_global)){ + if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){ + if(!strucmp(value, "yes")) + md.flowed = 1; + } + else{ + err = "Post option read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + } + else if(!strucmp(value, "subtype")){ + if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){ + if(!strucmp(value, "html")) + md.html = 1; + } + else{ + err = "Post option read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + else if(!strucmp(value, "priority")){ + if((value = Tcl_GetStringFromObj(objPO[1], NULL)) != NULL){ + char *priority = NULL; + + if(!strucmp(value, "highest")) + priority = "Highest"; + else if(!strucmp(value, "high")) + priority = "High"; + else if(!strucmp(value, "normal")) + priority = "Normal"; + else if(!strucmp(value, "low")) + priority = "Low"; + else if(!strucmp(value, "lowest")) + priority = "Lowest"; + + if(priority){ + if(pf = set_priority_header(md.metaenv, priority)) + pf->text = &pf->textbuf; + } + } + else{ + err = "Post option read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + else{ + sprintf(err = tmp_20k_buf, "Unknown Post Option: %s", value); + return(peMsgCollected(interp, &md, err, flags)); + } + } + else{ + sprintf(err = tmp_20k_buf, "Malformed Post Option"); + return(peMsgCollected(interp, &md, err, flags)); + } + } + else { + if(nField != 2){ + sprintf(err = tmp_20k_buf, "Malformed header (%s)", field); + return(peMsgCollected(interp, &md, err, flags)); + } + + if((value = Tcl_GetStringFromObj(objField[1], &vl)) != NULL){ + ADDRESS **addrp = NULL; + char **valp = NULL, *valcpy; + + if(!strucmp(field, "from")){ + addrp = &md.outgoing->from; + } + else if(!strucmp(field, "reply-to")){ + addrp = &md.outgoing->reply_to; + } + else if(!strucmp(field, "to")){ + addrp = &md.outgoing->to; + } + else if(!strucmp(field, "cc")){ + addrp = &md.outgoing->cc; + } + else if(!strucmp(field, "bcc")){ + addrp = &md.outgoing->bcc; + } + else if(!strucmp(field, "subject")){ + valp = &md.outgoing->subject; + } + else if(!strucmp(field, "in-reply-to")){ + valp = &md.outgoing->in_reply_to; + } + else if(!strucmp(field, "newsgroups")){ + valp = &md.outgoing->newsgroups; + } + else if(!strucmp(field, "followup-to")){ + valp = &md.outgoing->followup_to; + } + else if(!strucmp(field, "references")){ + valp = &md.outgoing->references; + } + else if(!strucmp(field, "x-reply-uid")){ + for(pf = md.metaenv->local; pf && pf->name; pf = pf->next) + if(!strucmp(pf->name, "x-reply-uid")){ + valp = pf->text = &pf->textbuf; + break; + } + } + else if(!strucmp(field, "x-auth-received")){ + for(pf = md.metaenv->local; pf && pf->name; pf = pf->next) + if(!strucmp(pf->name, "x-auth-received")){ + valp = pf->text = &pf->textbuf; + break; + } + } + else{ + for(pf = md.metaenv->custom; pf && pf->name; pf = pf->next) + if(!strucmp(field, pf->name)){ + if(pf->type == Address) + addrp = pf->addr; + else if(vl) + valp = &pf->textbuf; + else if(pf->textbuf) + fs_give((void **) &pf->textbuf); + + break; + } + + if(!pf) + dprint((2, "\nPOST: unrecognized field - %s\n", field)); + } + + if(valp){ + if(*valp) + fs_give((void **) valp); + + sprintf(*valp = fs_get((vl + 1) * sizeof(char)), "%.*s", vl, value); + } + + if(addrp){ + sprintf(valcpy = fs_get((vl + 1) * sizeof(char)), "%.*s", vl, value); + + for(; *addrp; addrp = &(*addrp)->next) + ; + + rfc822_parse_adrlist(addrp, valcpy, + (flags & PMC_FORCE_QUAL) + ? fakedomain : ps_global->maildomain); + fs_give((void **) &valcpy); + } + } + else{ + err = "Value read failure"; + return(peMsgCollected(interp, &md, err, flags)); + } + } + } + } + + return(peMsgCollected(interp, &md, err, flags)); +} + + +/* + * peMsgCollected - Dispatch collected message data and cleanup + */ +int +peMsgCollected(Tcl_Interp *interp, MSG_COL_S *md, char *err, long flags) +{ + int rv = TCL_OK, non_ascii = FALSE; + unsigned char c; + BODY *body = NULL, *tbp = NULL; + char errbuf[WP_MAX_POST_ERROR + 1], *charset; + STRLIST_S *lp; + + if(err){ + if(md->msgtext) + so_give(&md->msgtext); + + rv = TCL_ERROR; + } + else if(md->qualified_addrs && check_addresses(md->metaenv) == CA_BAD){ + sprintf(err = tmp_20k_buf, "Address must be fully qualified."); + rv = TCL_ERROR; + } + else{ + /* sniff body for possible multipart wrapping to protect encoding */ + so_seek(md->msgtext, 0L, 0); + + while(so_readc(&c, md->msgtext)) + if(!c || c & 0x80){ + non_ascii = TRUE; + break; + } + + if(!md->outgoing->from) + md->outgoing->from = generate_from(); + + rfc822_date(tmp_20k_buf); + md->outgoing->date = (unsigned char *) cpystr(tmp_20k_buf); + md->outgoing->return_path = rfc822_cpy_adr(md->outgoing->from); + md->outgoing->message_id = generate_message_id(); + + body = mail_newbody(); + + /* wire any attachments to body */ + if(md->attach || (non_ascii && F_OFF(F_COMPOSE_ALWAYS_DOWNGRADE, ps_global))){ + PART **np; + PARAMETER **pp; + COMPATT_S *a; + + /* setup slot for message text */ + body->type = TYPEMULTIPART; + body->nested.part = mail_newbody_part(); + tbp = &body->nested.part->body; + + /* link in attachments */ + for(lp = md->attach, np = &body->nested.part->next; lp; lp = lp->next, np = &(*np)->next){ + if(!(a = peGetAttachID(lp->name))){ + err = "Unknown Attachment ID"; + rv = TCL_ERROR; + break; + } + + *np = mail_newbody_part(); + + if(a->file){ + (*np)->body.id = generate_message_id(); + (*np)->body.description = cpystr(a->l.f.description); + + /* set name parameter */ + for(pp = &(*np)->body.parameter; *pp; ) + if(!struncmp((*pp)->attribute, "name", 4) + && (!*((*pp)->attribute + 4) + || *((*pp)->attribute + 4) == '*')){ + PARAMETER *free_me = *pp; + *pp = (*pp)->next; + free_me->next = NULL; + mail_free_body_parameter(&free_me); + } + else + pp = &(*pp)->next; + + *pp = NULL; + set_parameter(pp, "name", a->l.f.remote); + + /* Then set the Content-Disposition ala RFC1806 */ + if(!(*np)->body.disposition.type){ + (*np)->body.disposition.type = cpystr("attachment"); + for(pp = &(*np)->body.disposition.parameter; *pp; ) + if(!struncmp((*pp)->attribute, "filename", 4) + && (!*((*pp)->attribute + 4) + || *((*pp)->attribute + 4) == '*')){ + PARAMETER *free_me = *pp; + *pp = (*pp)->next; + free_me->next = NULL; + mail_free_body_parameter(&free_me); + } + else + pp = &(*pp)->next; + + *pp = NULL; + set_parameter(pp, "filename", a->l.f.remote); + } + + if(((*np)->body.contents.text.data = (void *) so_get(FileStar, a->l.f.local, READ_ACCESS)) != NULL){ + (*np)->body.type = mt_translate_type(a->l.f.type); + (*np)->body.subtype = cpystr(a->l.f.subtype); + (*np)->body.encoding = ENCBINARY; + (*np)->body.size.bytes = name_file_size(a->l.f.local); + + if((*np)->body.type == TYPEOTHER + && !set_mime_type_by_extension(&(*np)->body, a->l.f.local)) + set_mime_type_by_grope(&(*np)->body); + + so_release((STORE_S *)(*np)->body.contents.text.data); + } + else{ + /* unravel here */ + err = "Can't open uploaded attachment"; + rv = TCL_ERROR; + break; + } + } + else if(a->body){ + BODY *newbody = copy_body(NULL, a->l.b.body); + (*np)->body = *newbody; + fs_give((void **) &newbody); + peBodyMoveContents(a->l.b.body, &(*np)->body); + } + else{ + err = "BOTCH: Unknown attachment type"; + rv = TCL_ERROR; + break; + } + } + } + else + tbp = body; + + /* assign MIME parameters to text body part */ + tbp->type = TYPETEXT; + if(md->html) tbp->subtype = cpystr("HTML"); + + tbp->contents.text.data = (void *) md->msgtext; + tbp->encoding = ENCOTHER; + + /* set any text flowed param */ + if(md->flowed) + peMsgSetParm(&tbp->parameter, "format", "flowed"); + + if(rv == TCL_OK){ + CONTEXT_S *fcc_cntxt = ps_global->context_list; + + while(md->fcc_colid--) + if(fcc_cntxt->next) + fcc_cntxt = fcc_cntxt->next; + + if(md->postop_fcc_no_attach >= 0){ + int oldval = F_ON(F_NO_FCC_ATTACH, ps_global); + F_SET(F_NO_FCC_ATTACH, ps_global, md->postop_fcc_no_attach); + md->postop_fcc_no_attach = oldval; + } + + pine_encode_body(body); + + rv = (*md->postfunc)(md->metaenv, body, md->fcc, &fcc_cntxt, errbuf); + + if(md->postop_fcc_no_attach >= 0){ + F_SET(F_NO_FCC_ATTACH, ps_global, md->postop_fcc_no_attach); + } + + if(rv == TCL_OK){ + if((flags & PMC_PRSRV_ATT) == 0) + peFreeAttach(&peCompAttach); + } + else{ + /* maintain pointers to attachments */ + (void) peMsgAttachCollector(NULL, body); + err = errbuf; + } + } + + pine_free_body(&body); + } + + if(md->charset) + fs_give((void **) &md->charset); + + free_strlist(&md->attach); + + pine_free_env(&md->metaenv); + + if(md->custom) + free_customs(md->custom); + + mail_free_envelope(&md->outgoing); + + if(err && *err) + Tcl_SetResult(interp, err, TCL_VOLATILE); + + return(rv); +} + + +void +peMsgSetParm(PARAMETER **pp, char *pa, char *pv) +{ + for(; *pp; pp = &(*pp)->next) + if(!strucmp(pa, (*pp)->attribute)){ + if((*pp)->value) + fs_give((void **) &(*pp)->value); + + break; + } + + if(!*pp){ + *pp = mail_newbody_parameter(); + (*pp)->attribute = cpystr(pa); + } + + (*pp)->value = cpystr(pv); +} + + +Tcl_Obj * +peMsgAttachCollector(Tcl_Interp *interp, BODY *b) +{ + char *id, *name = NULL; + PART *part; + Tcl_Obj *aListObj = NULL, *aObj = NULL; + + peFreeAttach(&peCompAttach); + + if(interp) + aListObj = Tcl_NewListObj(0, NULL); + + if(b->type == TYPEMULTIPART){ + /* + * Walk first level, clipping branches and adding them + * to the attachment list... + */ + for(part = b->nested.part->next; part; part = part->next) { + id = peBodyAttachID(&part->body); + aObj = Tcl_NewListObj(0, NULL); + + if(interp){ + Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(id, -1)); + + /* name */ + if((name = get_filename_parameter(NULL, 0, &part->body, NULL)) != NULL){ + Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(name, -1)); + fs_give((void **) &name); + } + else + Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj("Unknown", -1)); + + /* size */ + Tcl_ListObjAppendElement(interp, aObj, + Tcl_NewLongObj((part->body.encoding == ENCBASE64) + ? ((part->body.size.bytes * 3)/4) + : part->body.size.bytes)); + + /* type */ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s/%s", + body_type_names(part->body.type), + part->body.subtype ? part->body.subtype : rfc822_default_subtype (part->body.type)); + Tcl_ListObjAppendElement(interp, aObj, Tcl_NewStringObj(tmp_20k_buf, -1)); + Tcl_ListObjAppendElement(interp, aListObj, aObj); + } + } + } + + return (aListObj); +} + + +int +peFccAppend(Tcl_Interp *interp, Tcl_Obj *obj, char *fcc, int colid) +{ + Tcl_Obj *objfcc = NULL; + + if(colid < 0) + colid = (ps_global->context_list && (ps_global->context_list->use & CNTXT_INCMNG)) ? 1 : 0; + + return((objfcc = Tcl_NewListObj(0, NULL)) + && Tcl_ListObjAppendElement(interp, objfcc, Tcl_NewStringObj("fcc", -1)) == TCL_OK + && peAppListF(interp, objfcc, "%i%s", colid, fcc) == TCL_OK + && Tcl_ListObjAppendElement(interp, obj, objfcc) == TCL_OK); +} + + +/* * * * * * * * * * * * * Start of Address Management Routines * * * * * * * * * * * */ + + +/* + * PEAddressCmd - export various bits of address book/directory access + */ +int +PEAddressCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *op; + + dprint((2, "PEAddressCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + return(TCL_ERROR); + } + else if(!ps_global){ + Tcl_SetResult(interp, "PEAddress: no open folder", TCL_STATIC); + return(TCL_ERROR); + } + else if((op = Tcl_GetStringFromObj(objv[1], NULL)) != NULL){ + if(objc == 2){ + if(!strcmp(op, "safecheck")){ + if(peInitAddrbooks(interp, 1) != TCL_OK) + return(TCL_ERROR); + return(TCL_OK); + } + else if(!strcmp(op, "books")){ + int i; + + /* + * return the list of configured address books + */ + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + + for(i = 0; i < as.n_addrbk; i++){ + Tcl_Obj *objmv[4]; + + objmv[0] = Tcl_NewIntObj(i); + if(as.adrbks[i].abnick){ + objmv[1] = Tcl_NewStringObj(as.adrbks[i].abnick, -1); + } + else { + char buf[256]; + + snprintf(buf, sizeof(buf), "Address book number %d", i + 1); + objmv[1] = Tcl_NewStringObj(buf, -1); + } + + objmv[2] = Tcl_NewStringObj(as.adrbks[i].filename ? as.adrbks[i].filename : "", -1); + + objmv[3] = Tcl_NewIntObj(as.adrbks[i].access == ReadWrite); + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(4, objmv)); + } + + return(TCL_OK); + } + } + else if(objc == 3){ + if(!strcmp(op, "parselist")){ + char *addrstr; + ADDRESS *addrlist = NULL, *atmp, *anextp; + static char *fakedomain = "@"; + + if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL) + addrstr = cpystr(addrstr); /* can't munge tcl copy */ + + ps_global->c_client_error[0] = '\0'; + rfc822_parse_adrlist(&addrlist, addrstr, + (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)) + ? fakedomain : ps_global->maildomain); + + fs_give((void **) &addrstr); + if(ps_global->c_client_error[0]){ + Tcl_SetResult(interp, ps_global->c_client_error, TCL_STATIC); + return(TCL_ERROR); + } + + for(atmp = addrlist; atmp; ){ + RFC822BUFFER rbuf; + + anextp = atmp->next; + atmp->next = NULL; + tmp_20k_buf[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = tmp_20k_buf; + rbuf.cur = tmp_20k_buf; + rbuf.end = tmp_20k_buf+SIZEOF_20KBUF-1; + rfc822_output_address_list(&rbuf, atmp, 0L, NULL); + *rbuf.cur = '\0'; + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(tmp_20k_buf, -1)); + atmp = anextp; + } + + mail_free_address(&addrlist); + return(TCL_OK); + } + else if(!strcmp(op, "xlookup")){ + char *addrstr; + ADDRESS *addrlist = NULL, *atmp, *anextp; + static char *fakedomain = "@"; + + if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL) + addrstr = cpystr(addrstr); /* can't munge tcl copy */ + + ps_global->c_client_error[0] = '\0'; + rfc822_parse_adrlist(&addrlist, addrstr, + (F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)) + ? fakedomain : ps_global->maildomain); + + fs_give((void **) &addrstr); + if(ps_global->c_client_error[0]){ + Tcl_SetResult(interp, ps_global->c_client_error, TCL_STATIC); + return(TCL_ERROR); + } + + for(atmp = addrlist; atmp; ){ + anextp = atmp->next; + atmp->next = NULL; + tmp_20k_buf[0] = '\0'; + if(atmp->host){ + if(atmp->host[0] == '@'){ + /* leading ampersand means "missing-hostname" */ + } + else{ + RFC822BUFFER rbuf; + + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = tmp_20k_buf; + rbuf.cur = tmp_20k_buf; + rbuf.end = tmp_20k_buf+SIZEOF_20KBUF-1; + rfc822_output_address_list(&rbuf, atmp, 0L, NULL); + *rbuf.cur = '\0'; + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(tmp_20k_buf, -1)); + } + } /* else group syntax, move on */ + + atmp = anextp; + } + + mail_free_address(&addrlist); + return(TCL_OK); + } + else if(!strcmp(op, "format")){ + int i, booknum; + char buf[256], *s; + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + + /* + * + */ + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK) + for(i = 0; i < as.n_addrbk; i++) + if(i == booknum){ + addrbook_new_disp_form(&as.adrbks[booknum], ps_global->VAR_ABOOK_FORMATS, booknum, NULL); + + for(i = 0; i < NFIELDS && as.adrbks[booknum].disp_form[i].type != Notused; i++){ + switch(as.adrbks[booknum].disp_form[i].type){ + case Nickname : + s = "nick"; + break; + case Fullname : + s = "full"; + break; + case Addr : + s = "addr"; + break; + case Filecopy : + s = "fcc"; + break; + case Comment : + s = "comment"; + break; + default : + s = NULL; + break; + } + + if(s){ + Tcl_Obj *objmv[2]; + + objmv[0] = Tcl_NewStringObj(s, -1); + objmv[1] = Tcl_NewIntObj((100 * as.adrbks[booknum].disp_form[i].width) / ps_global->ttyo->screen_cols); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(2, objmv)); + } + } + + + return(TCL_OK); + } + + snprintf(buf, sizeof(buf), "PEAddress list: unknown address book number \"%d\"", booknum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + else if(!strcmp(op, "list")){ + int i, j, k, n, booknum; + char buf[256], *s; + AdrBk_Entry *ae; + Tcl_Obj *objev[NFIELDS + 1], *objhv[2]; + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + + /* + * + */ + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK) + for(i = 0; i < as.n_addrbk; i++) + if(i == booknum){ + addrbook_new_disp_form(&as.adrbks[booknum], ps_global->VAR_ABOOK_FORMATS, booknum, NULL); + + for(i = 0; + (ae = adrbk_get_ae(as.adrbks[booknum].address_book, i)); + i++){ + + /* first member is type: Single, List or Lookup */ + switch(ae->tag){ + case Single : + s = "single"; + break; + case List : + s = "list"; + break; + default : /* not set!?! */ + continue; + } + + if(!ae->nickname) + continue; + + objhv[0] = Tcl_NewStringObj(ae->nickname, -1); + objhv[1] = Tcl_NewStringObj(s, -1); + objev[n = 0] = Tcl_NewListObj(2, objhv); + + /* + * set fields based on VAR_ABOOK_FORMATS + */ + + for(j = 0; j < NFIELDS && as.adrbks[booknum].disp_form[j].type != Notused; j++){ + switch(as.adrbks[booknum].disp_form[j].type){ + case Nickname : + objev[++n] = Tcl_NewStringObj(ae->nickname, -1); + break; + case Fullname : + objev[++n] = Tcl_NewStringObj(ae->fullname, -1); + break; + case Addr : + if(ae->tag == Single){ + objev[++n] = Tcl_NewStringObj(ae->addr.addr, -1); + } + else{ + Tcl_Obj **objav; + + for(k = 0; ae->addr.list[k]; k++) + ; + + objav = (Tcl_Obj **) fs_get(k * sizeof(Tcl_Obj *)); + for(k = 0; ae->addr.list[k]; k++) + objav[k] = Tcl_NewStringObj(ae->addr.list[k], -1); + + objev[++n] = Tcl_NewListObj(k, objav); + fs_give((void **) &objav); + } + break; + case Filecopy : + objev[++n] = Tcl_NewStringObj(ae->fcc ? ae->fcc : "", -1); + break; + case Comment : + objev[++n] = Tcl_NewStringObj(ae->extra ? ae->extra : "", -1); + break; + default : + s = NULL; + break; + } + } + + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewListObj(n + 1, objev)); + } + + return(TCL_OK); + } + + snprintf(buf, sizeof(buf), "PEAddress list: unknown address book number \"%d\"", booknum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + else if(objc == 4){ + if(!strcmp(op, "verify")){ + /* + * The object here is to check the following list of field values + * to see that they are valid address list, expanding if necessary. + * The first argument is the list of field values, with "to" being + * first. The second arg is the current fcc value. + * + * The return value is of the following form: + * + * { {{errstr {{oldstr newstr {ldap-opts ...}} ...}} ...} newfcc} + */ + Tcl_Obj **objVal; + char *addrstr, *newaddr = NULL, *error = NULL, + *tstr1, *tstr2, *fcc, *newfcc = NULL; + BuildTo toaddr; + int rv, badadrs, i , numlistvals, + numldapqueries = 0; + Tcl_Obj *resObj = NULL, *secObj, *strObj, *adrObj, *res2Obj; +#ifdef ENABLE_LDAP + WPLDAPRES_S **tsl; + + wpldap_global->query_no++; + if(wpldap_global->ldap_search_list){ + wpldap_global->ldap_search_list = + free_wpldapres(wpldap_global->ldap_search_list); + } + + tsl = &(wpldap_global->ldap_search_list); +#endif /* ENABLE_LDAP */ + + if(Tcl_ListObjGetElements(interp, objv[2], &numlistvals, + &objVal) == TCL_OK){ + if((fcc = Tcl_GetStringFromObj(objv[3], NULL)) == NULL) + return TCL_ERROR; + res2Obj = Tcl_NewListObj(0, NULL); + for(i = 0; i < numlistvals; i++){ + size_t l; + + if((addrstr = Tcl_GetStringFromObj(objVal[i], NULL)) == NULL) + return TCL_ERROR; + + addrstr = cpystr(addrstr); /* can't munge tcl copy */ + toaddr.type = Str; + toaddr.arg.str = cpystr(addrstr); + l = strlen(addrstr); + badadrs = 0; + resObj = Tcl_NewListObj(0, NULL); + secObj = Tcl_NewListObj(0, NULL); + for(tstr1 = addrstr; tstr1; tstr1 = tstr2){ + tstr2 = strqchr(tstr1, ',', 0, -1); + if(tstr2) + *tstr2 = '\0'; + + strncpy(toaddr.arg.str, tstr1, l); + toaddr.arg.str[l] = '\0'; + + removing_leading_and_trailing_white_space(toaddr.arg.str); + if(*toaddr.arg.str){ + if(i == 0 && tstr1 == addrstr) + newfcc = cpystr(fcc); + + rv = our_build_address(toaddr, &newaddr, &error, &newfcc, NULL); + + if(rv == 0){ + strObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, strObj, + Tcl_NewStringObj(toaddr.arg.str, -1)); + Tcl_ListObjAppendElement(interp, strObj, + Tcl_NewStringObj(newaddr,-1)); + /* append whether or not ldap stuff + * was returned + */ + adrObj = Tcl_NewListObj(0,NULL); +#ifdef ENABLE_LDAP + if(*tsl) { + LDAP_CHOOSE_S *tres; + LDAP_SERV_RES_S *trl; + LDAPMessage *e; + ADDRESS *newadr; + char *ret_to; + + tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S)); + for(trl = (*tsl)->reslist; trl; + trl = trl->next){ + for(e = ldap_first_entry(trl->ld, + trl->res); + e != NULL; + e = ldap_next_entry(trl->ld, e)){ + tres->ld = trl->ld; + tres->selected_entry = e; + tres->info_used = trl->info_used; + tres->serv = trl->serv; + if((newadr = address_from_ldap(tres)) != NULL){ + if(newadr->mailbox && newadr->host){ + RFC822BUFFER rbuf; + size_t len; + + len = est_size(newadr); + ret_to = (char *)fs_get(len * sizeof(char)); + ret_to[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = ret_to; + rbuf.cur = ret_to; + rbuf.end = ret_to+len-1; + rfc822_output_address_list(&rbuf, newadr, 0L, NULL); + *rbuf.cur = '\0'; + Tcl_ListObjAppendElement(interp, + adrObj, Tcl_NewStringObj(ret_to, -1)); + fs_give((void **)&ret_to); + } + mail_free_address(&newadr); + } + } + } + fs_give((void **)&tres); + numldapqueries++; + tsl = &((*tsl)->next); + } +#endif /* ENABLE_LDAP */ + Tcl_ListObjAppendElement(interp, strObj, adrObj); + Tcl_ListObjAppendElement(interp, secObj, strObj); + } + else { + badadrs = 1; + break; + } + } + if(tstr2){ + *tstr2 = ','; + tstr2++; + } + } + resObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(badadrs + ? (error ? error : "Unknown") + : "", -1)); + Tcl_ListObjAppendElement(interp, resObj, secObj); + Tcl_ListObjAppendElement(interp, res2Obj, resObj); + fs_give((void **) &addrstr); + fs_give((void **) &toaddr.arg.str); + } + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), res2Obj); + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(newfcc ? newfcc + : (fcc ? fcc : ""), -1)); + if(newfcc) fs_give((void **)&newfcc); + return(TCL_OK); + } + return(TCL_ERROR); + } + else if(!strcmp(op, "expand")){ + BuildTo toaddr; + char *addrstr, *newaddr = NULL, *error = NULL, *fcc, *newfcc = NULL; + int rv; + + /* + * Return value will be of the form: + * {"addrstr", + * ldap-query-number, + * "fcc" + * } + * + * ldap-query-number will be nonzero if + * there is something interesting to display as a result + * of an ldap query. + */ + + /* + * Given what looks like an rfc822 address line, parse the + * contents and expand any tokens that look like they ought + * to be. + */ + + if((addrstr = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + toaddr.type = Str; + toaddr.arg.str = cpystr(addrstr); /* can't munge tcl copy */ + fcc = Tcl_GetStringFromObj(objv[3], NULL); +#ifdef ENABLE_LDAP + wpldap_global->query_no++; + if(wpldap_global->ldap_search_list){ + wpldap_global->ldap_search_list = + free_wpldapres(wpldap_global->ldap_search_list); + } +#endif /* ENABLE_LDAP */ + newfcc = cpystr(fcc); + rv = our_build_address(toaddr, &newaddr, &error, &newfcc, NULL); + fs_give((void **) &toaddr.arg.str); + if(rv == 0){ +#ifdef ENABLE_LDAP + /* + * c-client quotes results with spaces in them, so we'll go + * through and unquote them. + */ + if(wpldap_global->ldap_search_list){ + WPLDAPRES_S *tres; + char *tstr1, *tstr2; + char *qstr1, *newnewaddr; + int qstr1len; + + for(tres = wpldap_global->ldap_search_list; + tres; tres = tres->next){ + if(strqchr(tres->str, ' ', 0, -1)){ + qstr1len = strlen(tres->str) + 3; + qstr1 = (char *)fs_get(qstr1len*sizeof(char)); + snprintf(qstr1, qstr1len, "\"%.*s\"", qstr1len, tres->str); + for(tstr1 = newaddr; tstr1; tstr1 = tstr2){ + tstr2 = strqchr(tstr1, ',', 0, -1); + if(strncmp(qstr1, tstr1, tstr2 ? tstr2 - tstr1 + : strlen(tstr1)) == 0){ + size_t l; + l = strlen(newaddr) + strlen(tres->str) + 2 + + (tstr2 ? strlen(tstr2) : 0); + newnewaddr = (char *) fs_get(l * sizeof(char)); + snprintf(newnewaddr, l, "%.*s%s%s", tstr1 - newaddr, + newaddr, tres->str, tstr2 ? tstr2 : ""); + fs_give((void **)&newaddr); + newaddr = newnewaddr; + break; + } + if(tstr2) + tstr2++; + if(tstr2 && *tstr2 == ' ') + tstr2++; + } + if(qstr1) + fs_give((void **) &qstr1); + } + } + } +#endif /* ENABLE_LDAP */ + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(newaddr, -1)) != TCL_OK) + return(TCL_ERROR); +#ifdef ENABLE_LDAP + if(wpldap_global->ldap_search_list){ + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(wpldap_global->query_no)) != TCL_OK) + return(TCL_ERROR); + } + else +#endif /* ENABLE_LDAP */ + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewIntObj(0)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(newfcc ? newfcc + : (fcc ? fcc : ""), -1)) != TCL_OK) + return(TCL_ERROR); + if(newfcc) fs_give((void **)&newfcc); + + return(TCL_OK); + } + else{ + Tcl_SetResult(interp, error ? error : "Indeterminate error", TCL_VOLATILE); + if(newfcc) fs_give((void **)&newfcc); + return(TCL_ERROR); + } + } + } + else if(!strcmp(op, "complete")){ + /* + * CMD: complete uid + * + * Look for possible completions for + * given query_string. + * + * ARGS: <query_string> <uid> + * + * Returns: candidate list: {nickname {personal mailbox}} + */ + char *query, *errstr; + long uid; + COMPLETE_S *completions, *cp; + + if(peInitAddrbooks(interp, 0) == TCL_OK){ + if((query = Tcl_GetStringFromObj(objv[2], NULL)) != NULL){ + if(Tcl_GetLongFromObj(interp, objv[3], &uid) == TCL_OK){ + + completions = adrbk_list_of_completions(query, + ps_global->mail_stream, + uid, +#ifdef ENABLE_LDAP + ((strlen(query) >= 5) ? ALC_INCLUDE_LDAP : 0) | +#endif /* ENABLE_LDAP */ + 0); + + if(completions){ + for(cp = completions; cp; cp = cp->next) + peAppListF(interp, Tcl_GetObjResult(interp), "%s %s %s", + cp->nickname ? cp->nickname : "", + cp->full_address ? cp->full_address : "", + cp->fcc ? cp->fcc : ""); + + free_complete_s(&completions); + } + else + Tcl_SetResult(interp, "", TCL_STATIC); + + return(TCL_OK); + } + else + errstr = "PEAddress: Cannot read UID"; + } + else + errstr = "PEAddress: Cannot get completion query"; + } + else + errstr = "PEAddress: Address Book initialization failed"; + + Tcl_SetResult(interp, errstr, TCL_STATIC); + return(TCL_ERROR); + } + } + else if(objc == 5){ + if(!strcmp(op, "entry")){ + int booknum, i, aindex; + char *nick, *astr = NULL, *errstr = NULL, *fccstr = NULL, buf[128]; + AdrBk_Entry *ae; + BuildTo bldto; + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + + /* + * Given an address book handle and nickname, return address + */ + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK) + for(i = 0; i < as.n_addrbk; i++) + if(i == booknum){ + if((nick = Tcl_GetStringFromObj(objv[3], NULL)) == NULL){ + Tcl_SetResult(interp, "PEAddress list: Can't get nickname", TCL_STATIC); + return(TCL_ERROR); + } + if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK + || (*nick == '\0' && aindex < 0)){ + Tcl_SetResult(interp, "PEAddress list: Can't get aindex", TCL_STATIC); + return(TCL_ERROR); + } + if((*nick) + ? (ae = adrbk_lookup_by_nick(as.adrbks[booknum].address_book, nick, NULL)) + : (ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex))){ + bldto.type = Abe; + bldto.arg.abe = ae; + + (void) our_build_address(bldto, &astr, &errstr, &fccstr, NULL); + + if(errstr){ + if(astr) + fs_give((void **) &astr); + + Tcl_SetResult(interp, errstr, TCL_VOLATILE); + return(TCL_ERROR); + } + + if(astr){ + char *p; + int l; + + l = (4*strlen(astr) + 1) * sizeof(char); + p = (char *) fs_get(l); + if(rfc1522_decode_to_utf8((unsigned char *) p, l, astr) == (unsigned char *) p){ + fs_give((void **) &astr); + astr = p; + } + else + fs_give((void **)&p); + } + } + + if(astr){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(astr, -1)); + fs_give((void **) &astr); + + if(fccstr){ + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(*fccstr ? fccstr : "\"\"", -1)); + fs_give((void **) &fccstr); + } + else + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj("", -1)); + } + else + Tcl_SetResult(interp, "", TCL_STATIC); + + return(TCL_OK); + } + + snprintf(buf, sizeof(buf), "PEAddress list: unknown address book ID %d", booknum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + else if(!strcmp(op, "fullentry")){ + int booknum, j, aindex; + char *nick; + AdrBk_Entry *ae; + Tcl_Obj *resObj; + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + + /* + * Given an address book handle and nickname, return + * nickname, fullname, address(es), fcc, and comments + */ + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){ + if(booknum >= 0 && booknum < as.n_addrbk){ + if((nick = Tcl_GetStringFromObj(objv[3], NULL)) == NULL) + return(TCL_ERROR); + if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK + || (*nick == '\0' && aindex < 0)) + return(TCL_ERROR); + if((*nick) + ? (ae = adrbk_lookup_by_nick(as.adrbks[booknum].address_book, nick, NULL)) + : (ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex))){ + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ae->nickname ? ae->nickname : "", -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ae->fullname ? ae->fullname : "", -1)); + resObj = Tcl_NewListObj(0,NULL); + if(ae->tag == Single) + Tcl_ListObjAppendElement(interp, + resObj, + Tcl_NewStringObj(ae->addr.addr ? ae->addr.addr : "", -1)); + else { + for(j = 0; ae->addr.list[j]; j++) + Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(ae->addr.list[j] ? ae->addr.list[j] : "", -1)); + } + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), resObj); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ae->fcc ? ae->fcc : "", -1)); + Tcl_ListObjAppendElement(interp, + Tcl_GetObjResult(interp), + Tcl_NewStringObj(ae->extra ? ae->extra : "", -1)); + return(TCL_OK); + } + } + } + return(TCL_ERROR); + } + else if(!strcmp(op, "delete")){ + char *nick, buf[256]; + int booknum, aindex; + adrbk_cntr_t old_entry; + AdrBk *ab; + if(peInitAddrbooks(interp, 0) != TCL_OK){ + snprintf(buf, sizeof(buf), "PEAddress delete: couldn't init addressbooks"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){ + nick = Tcl_GetStringFromObj(objv[3], NULL); + removing_leading_and_trailing_white_space(nick); + } + else + return(TCL_ERROR); + if(booknum >= 0 && booknum < as.n_addrbk) { + if(as.adrbks[booknum].access != ReadWrite) return TCL_ERROR; + ab = as.adrbks[booknum].address_book; + } + else{ + snprintf(buf, sizeof(buf), "PEAddress delete: Book number out of range"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + if((Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK) + || (*nick == '\0' && aindex < 0)) + return(TCL_ERROR); + adrbk_check_validity(ab, 1L); + if(ab->flags & FILE_OUTOFDATE || + (ab->rd && ab->rd->flags & REM_OUTOFDATE)){ + Tcl_SetResult(interp, + "Address book out of sync. Cannot update at this moment", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(!nick){ + snprintf(buf, sizeof(buf), "PEAddress delete: No nickname"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + if((*nick) + ? (!adrbk_lookup_by_nick(ab, nick, &old_entry)) + : ((old_entry = (adrbk_cntr_t)aindex) == -1)){ + snprintf(buf, sizeof(buf), "PEAddress delete: Nickname \"%.128s\" not found", nick); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + if(adrbk_delete(ab, old_entry, 0, 0, 1, 1)){ + snprintf(buf, sizeof(buf), "PEAddress delete: Couldn't delete addressbook entry"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + return(TCL_OK); + } + } + else if((objc == 10 || objc == 11) && !strcmp(op, "edit")){ + if(!strcmp(op, "edit")){ + int booknum, adri, add, rv, aindex; + char *nick, *fn, *fcc, *comment, *addrfield, + buf[256], **addrs, *orignick = NULL; + AdrBk_Entry *ae = NULL; + AdrBk *ab; + adrbk_cntr_t old_entry = NO_NEXT, new_entry; + Tag tag; + ADDRESS *adr = NULL; + + + if(peInitAddrbooks(interp, 0) != TCL_OK) + return(TCL_ERROR); + if(Tcl_GetIntFromObj(interp, objv[2], &booknum) == TCL_OK){ + if(as.adrbks[booknum].access != ReadWrite) return TCL_ERROR; + nick = Tcl_GetStringFromObj(objv[3], NULL); + removing_leading_and_trailing_white_space(nick); + if(Tcl_GetIntFromObj(interp, objv[4], &aindex) != TCL_OK){ + Tcl_SetResult(interp, "No Address Handle", TCL_VOLATILE); + return(TCL_ERROR); + } + fn = Tcl_GetStringFromObj(objv[5], NULL); + removing_leading_and_trailing_white_space(fn); + if(!*fn) fn = NULL; + addrfield = Tcl_GetStringFromObj(objv[6], NULL); + removing_leading_and_trailing_white_space(addrfield); + if(!*addrfield) addrfield = NULL; + /* + if(Tcl_ListObjGetElements(interp, objv[7], &numlistvals, &objVal) != TCL_OK) + return(TCL_ERROR); + */ + fcc = Tcl_GetStringFromObj(objv[7], NULL); + removing_leading_and_trailing_white_space(fcc); + if(!*fcc) fcc = NULL; + comment = Tcl_GetStringFromObj(objv[8], NULL); + removing_leading_and_trailing_white_space(comment); + if(!*comment) comment = NULL; + if(Tcl_GetIntFromObj(interp, objv[9], &add) != TCL_OK) + return(TCL_ERROR); + if(objc == 11) { + /* + * if objc == 11 then that means that they changed the + * value of nick to something else, and this one is the + * original nick + */ + orignick = Tcl_GetStringFromObj(objv[10], NULL); + removing_leading_and_trailing_white_space(orignick); + } + if((addrs = parse_addrlist(addrfield)) != NULL){ + int tbuflen = strlen(addrfield); + char *tbuf; + if(!(tbuf = (char *) fs_get(sizeof(char) * (tbuflen+128)))){ + Tcl_SetResult(interp, "malloc error", TCL_VOLATILE); + fs_give((void **) &addrs); + return(TCL_ERROR); + } + for(adri = 0; addrs[adri]; adri++){ + if(*(addrs[adri])){ + ps_global->c_client_error[0] = '\0'; + strncpy(tbuf, addrs[adri], tbuflen+128); + tbuf[tbuflen+128-1] = '\0'; + rfc822_parse_adrlist(&adr, tbuf, "@"); + if(adr) mail_free_address(&adr); + adr = NULL; + if(ps_global->c_client_error[0]){ + snprintf(buf, sizeof(buf),"Problem with address %.10s%s: %s", + addrs[adri], strlen(addrs[adri]) > 10 ? + "..." : "", ps_global->c_client_error); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + if(tbuf) + fs_give((void **) &tbuf); + fs_give((void **) &addrs); + return(TCL_ERROR); + } + } + } + if(tbuf) fs_give((void **)&tbuf); + } + else adri = 0; + + /* addrs[adri] = NULL; */ + + if(adri > 1) tag = List; + else tag = Single; + + if(booknum >= 0 && booknum < as.n_addrbk) { + ab = as.adrbks[booknum].address_book; + } + else{ + if(addrs) + fs_give((void **) &addrs); + return(TCL_ERROR); + } + adrbk_check_validity(ab, 1L); + if(ab->flags & FILE_OUTOFDATE || + (ab->rd && ab->rd->flags & REM_OUTOFDATE)){ + Tcl_SetResult(interp, + "Address book out of sync. Cannot update at this moment", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(aindex >= 0){ + ae = adrbk_get_ae(as.adrbks[booknum].address_book, aindex); + if(ae){ + old_entry = (adrbk_cntr_t) aindex; + } + else{ + Tcl_SetResult(interp, "No Address Handle!", TCL_VOLATILE); + return(TCL_ERROR); + } + } + else if(nick && *nick && adrbk_lookup_by_nick(ab, nick, NULL)){ + snprintf(buf, sizeof(buf), "Entry with nickname %.128s already exists.", + nick); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + if(addrs) + fs_give((void **) &addrs); + return(TCL_ERROR); + } + if(ae && + ((tag == List && ae->tag == Single) || + (tag == Single && ae->tag == List))){ + if(adrbk_delete(ab, old_entry, 0,0,1,0)){ + snprintf(buf, sizeof(buf), "Problem updating from %s to %s.", + ae->tag == Single ? "Single" : "List", + tag == List ? "List" : "Single"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + if(addrs) + fs_give((void **) &addrs); + return(TCL_ERROR); + } + old_entry = NO_NEXT; + } + if((rv = adrbk_add(ab, old_entry, + nick ? nick : "", + fn ? fn : "", + tag == List ? (char *)addrs : + (addrs && *addrs) ? *addrs : "", + fcc ? fcc : "", + comment ? comment : "", + tag, &new_entry, NULL, 0, 1, + tag == List ? 0 : 1)) != 0){ + snprintf(buf, sizeof(buf), "Couldn't add entry! rv=%d.", rv); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + if(addrs) + fs_give((void **) &addrs); + return(TCL_ERROR); + } + if(tag == List) { + adrbk_listdel_all(ab, new_entry); + adrbk_nlistadd(ab, new_entry, NULL, NULL, addrs, 0, 1, 1); + } + return(TCL_OK); + } + snprintf(buf, sizeof(buf), "Unknown address book ID %d", booknum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return(TCL_ERROR); + } + } + } + + Tcl_SetResult(interp, "PEAddress: unrecognized command", TCL_STATIC); + return(TCL_ERROR); +} + + +int +peInitAddrbooks(Tcl_Interp *interp, int safe) +{ + if(ps_global->remote_abook_validity > 0) + (void)adrbk_check_and_fix_all(safe, 0, 0); + + if(!init_addrbooks(NoDisplay, 1, 1, 0)){ + Tcl_SetResult(interp, "No Address Book Configured", TCL_STATIC); + return(TCL_ERROR); + } + + return(TCL_OK); +} + + + +int +peRuleStatVal(char *str, int *n) +{ + if(!str) + return(1); + + if(!strcmp(str, "either")) + *n = PAT_STAT_EITHER; + else if(!strcmp(str, "yes")) + *n = PAT_STAT_YES; + else if(!strcmp(str, "no")) + *n = PAT_STAT_NO; + else + return 1; + + return 0; +} + + +#define RS_RULE_EDIT 0x0001 +#define RS_RULE_ADD 0x0002 +#define RS_RULE_DELETE 0x0004 +#define RS_RULE_SHUFFUP 0x0008 +#define RS_RULE_SHUFFDOWN 0x0010 +#define RS_RULE_GETPAT 0x0100 +#define RS_RULE_FINDPAT 0x0200 + +int +peRuleSet(Tcl_Interp *interp, Tcl_Obj **objv) +{ + char *rule, *patvar, *patval, *actvar, *actval, *tstr, *ruleaction; + int rno, nPat, nPatEmnt, nAct, nActEmnt, i, rv = 0; + Tcl_Obj **objPat, **objPatEmnt, **objAct, **objActEmnt; + long rflags = PAT_USE_CHANGED, aflags = 0; + PAT_STATE pstate; + PAT_S *pat, *new_pat; + + if(!(rule = Tcl_GetStringFromObj(objv[0], NULL))) + return(TCL_ERROR); + + if(!(ruleaction = Tcl_GetStringFromObj(objv[1], NULL))) + return(TCL_ERROR); + + if(Tcl_GetIntFromObj(interp, objv[2], &rno) == TCL_ERROR) + return(TCL_ERROR); + + if(!(strcmp(rule, "filter"))) + rflags |= ROLE_DO_FILTER; + else if(!(strcmp(rule, "score"))) + rflags |= ROLE_DO_SCORES; + else if(!(strcmp(rule, "indexcolor"))) + rflags |= ROLE_DO_INCOLS; + else + return(TCL_ERROR); + + if(!(strcmp(ruleaction, "edit"))){ + aflags |= RS_RULE_EDIT; + aflags |= RS_RULE_GETPAT; + aflags |= RS_RULE_FINDPAT; + } + else if(!(strcmp(ruleaction, "add"))){ + aflags |= RS_RULE_ADD; + aflags |= RS_RULE_GETPAT; + } + else if(!(strcmp(ruleaction, "delete"))){ + aflags |= RS_RULE_DELETE; + aflags |= RS_RULE_FINDPAT; + } + else if(!(strcmp(ruleaction, "shuffup"))){ + aflags |= RS_RULE_SHUFFUP; + aflags |= RS_RULE_FINDPAT; + } + else if(!(strcmp(ruleaction, "shuffdown"))){ + aflags |= RS_RULE_SHUFFDOWN; + aflags |= RS_RULE_FINDPAT; + } + else return(TCL_ERROR); + + if(aflags & RS_RULE_FINDPAT){ + if(any_patterns(rflags, &pstate)){ + for(pat = first_pattern(&pstate), i = 0; + pat && i != rno; + pat = next_pattern(&pstate), i++); + if(i != rno) return(TCL_ERROR); + } + } + if(aflags & RS_RULE_GETPAT){ + int tcl_error = 0; + + Tcl_ListObjGetElements(interp, objv[3], &nPat, &objPat); + Tcl_ListObjGetElements(interp, objv[4], &nAct, &objAct); + + new_pat = (PAT_S *)fs_get(sizeof(PAT_S)); + memset(new_pat, 0, sizeof(PAT_S)); + new_pat->patgrp = (PATGRP_S *)fs_get(sizeof(PATGRP_S)); + memset(new_pat->patgrp, 0, sizeof(PATGRP_S)); + new_pat->action = (ACTION_S *)fs_get(sizeof(ACTION_S)); + memset(new_pat->action, 0, sizeof(ACTION_S)); + + /* Set up the pattern group */ + for(i = 0; i < nPat; i++){ + Tcl_ListObjGetElements(interp, objPat[i], &nPatEmnt, &objPatEmnt); + if(nPatEmnt != 2) return(TCL_ERROR); + patvar = Tcl_GetStringFromObj(objPatEmnt[0], NULL); + patval = Tcl_GetStringFromObj(objPatEmnt[1], NULL); + if(!patvar || !patval) return(TCL_ERROR); + + tstr = NULL; + if(*patval){ + tstr = cpystr(patval); + removing_leading_and_trailing_white_space(tstr); + if(!(*tstr)) + fs_give((void **) &tstr); + } + + if(!(strcmp(patvar, "nickname"))){ + new_pat->patgrp->nick = tstr; + tstr = NULL; + } + else if(!(strcmp(patvar, "comment"))){ + new_pat->patgrp->comment = tstr; + tstr = NULL; + } + else if(!(strcmp(patvar, "to"))){ + new_pat->patgrp->to = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "from"))){ + new_pat->patgrp->from = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "sender"))){ + new_pat->patgrp->sender = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "cc"))){ + new_pat->patgrp->cc = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "recip"))){ + new_pat->patgrp->recip = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "partic"))){ + new_pat->patgrp->partic = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "news"))){ + new_pat->patgrp->news = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "subj"))){ + new_pat->patgrp->subj = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "bodytext"))){ + new_pat->patgrp->bodytext = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "alltext"))){ + new_pat->patgrp->alltext = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "keyword"))){ + new_pat->patgrp->keyword = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "charset"))){ + new_pat->patgrp->charsets = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "ftype"))){ + if(!tstr) return(TCL_ERROR); + + if(!(strcmp(tstr, "any"))) + new_pat->patgrp->fldr_type = FLDR_ANY; + else if(!(strcmp(tstr, "news"))) + new_pat->patgrp->fldr_type = FLDR_NEWS; + else if(!(strcmp(tstr, "email"))) + new_pat->patgrp->fldr_type = FLDR_EMAIL; + else if(!(strcmp(tstr, "specific"))) + new_pat->patgrp->fldr_type = FLDR_SPECIFIC; + else{ + free_pat(&new_pat); + return(TCL_ERROR); + } + } + else if(!(strcmp(patvar, "folder"))){ + new_pat->patgrp->folder = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "stat_new"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_new)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_rec"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_rec)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_del"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_del)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_imp"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_imp)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_ans"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_ans)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_8bitsubj"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_8bitsubj)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_bom"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_bom)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "stat_boy"))){ + if(peRuleStatVal(tstr, &new_pat->patgrp->stat_boy)){ + free_pat(&new_pat); + tcl_error++; + } + } + else if(!(strcmp(patvar, "age"))){ + new_pat->patgrp->age = parse_intvl(tstr); + } + else if(!(strcmp(patvar, "size"))){ + new_pat->patgrp->size = parse_intvl(tstr); + } + else if(!(strcmp(patvar, "score"))){ + new_pat->patgrp->score = parse_intvl(tstr); + } + else if(!(strcmp(patvar, "addrbook"))){ + if(tstr){ + if(!strcmp(tstr, "either")) + new_pat->patgrp->inabook = IAB_EITHER; + else if(!strcmp(tstr, "yes")) + new_pat->patgrp->inabook = IAB_YES; + else if(!strcmp(tstr, "no")) + new_pat->patgrp->inabook = IAB_NO; + else if(!strcmp(tstr, "yesspecific")) + new_pat->patgrp->inabook = IAB_SPEC_YES; + else if(!strcmp(tstr, "nospecific")) + new_pat->patgrp->inabook = IAB_SPEC_NO; + else + tcl_error++; + } + else + tcl_error++; + + if(tcl_error) + free_pat(&new_pat); + } + else if(!(strcmp(patvar, "specificabook"))){ + new_pat->patgrp->abooks = string_to_pattern(tstr); + } + else if(!(strcmp(patvar, "headers"))){ + ARBHDR_S **ahp; + int nHdrList, nHdrPair, n; + Tcl_Obj **objHdrList, **objHdrPair; + + Tcl_ListObjGetElements(interp, objPatEmnt[1], &nHdrList, &objHdrList); + + for(ahp = &new_pat->patgrp->arbhdr; *ahp; ahp = &(*ahp)->next) + ; + + for (n = 0; n < nHdrList; n++){ + char *hdrfld; + char *hdrval; + + Tcl_ListObjGetElements(interp, objHdrList[n], &nHdrPair, &objHdrPair); + if(nHdrPair != 2) + continue; + + hdrfld = Tcl_GetStringFromObj(objHdrPair[0], NULL); + hdrval = Tcl_GetStringFromObj(objHdrPair[1], NULL); + + if(hdrfld){ + *ahp = (ARBHDR_S *) fs_get(sizeof(ARBHDR_S)); + memset(*ahp, 0, sizeof(ARBHDR_S)); + + (*ahp)->field = cpystr(hdrfld); + if(hdrval){ + (*ahp)->p = string_to_pattern(hdrval); + } + else + (*ahp)->isemptyval = 1; + + ahp = &(*ahp)->next; + } + } + } + else{ + free_pat(&new_pat); + tcl_error++; + } + + if(tstr) + fs_give((void **) &tstr); + + if(tcl_error) + return(TCL_ERROR); + } + + if((new_pat->patgrp->inabook & (IAB_SPEC_YES | IAB_SPEC_NO)) == 0 + && new_pat->patgrp->abooks) + free_pattern(&new_pat->patgrp->abooks); + + if(new_pat->patgrp->fldr_type != FLDR_SPECIFIC && new_pat->patgrp->folder) + free_pattern(&new_pat->patgrp->folder); + + /* set up the action */ + if(!(strcmp(rule, "filter"))) + new_pat->action->is_a_filter = 1; + else if(!(strcmp(rule, "role"))) + new_pat->action->is_a_role = 1; + else if(!(strcmp(rule, "score"))) + new_pat->action->is_a_score = 1; + else if(!(strcmp(rule, "indexcolor"))) + new_pat->action->is_a_incol = 1; + else{ + free_pat(&new_pat); + return(TCL_ERROR); + } + + for(i = 0; i < nAct; i++){ + Tcl_ListObjGetElements(interp, objAct[i], &nActEmnt, &objActEmnt); + if(nActEmnt !=2){ + free_pat(&new_pat); + return(TCL_ERROR); + } + + actvar = Tcl_GetStringFromObj(objActEmnt[0], NULL); + actval = Tcl_GetStringFromObj(objActEmnt[1], NULL); + if(!actvar || !actval){ + free_pat(&new_pat); + return(TCL_ERROR); + } + + if(new_pat->action->is_a_filter && !(strcmp(actvar, "action"))){ + if(!strcmp(actval, "delete")) + new_pat->action->kill = 1; + else if(!strcmp(actval, "move")) + new_pat->action->kill = 0; + else{ + free_pat(&new_pat); + return(TCL_ERROR); + } + } + else if(new_pat->action->is_a_filter && !(strcmp(actvar, "folder"))){ + tstr = cpystr(actval); + removing_leading_and_trailing_white_space(tstr); + if(!(*tstr)) fs_give((void **)&tstr); + new_pat->action->folder = string_to_pattern(tstr); + if(tstr) fs_give((void **)&tstr); + } + else if(new_pat->action->is_a_filter && !(strcmp(actvar, "moind"))){ + if(!strcmp(actval, "1")) + new_pat->action->move_only_if_not_deleted = 1; + else if(!strcmp(actval, "0")) + new_pat->action->move_only_if_not_deleted = 0; + else{ + free_pat(&new_pat); + return(TCL_ERROR); + } + } + else if(new_pat->action->is_a_incol && !(strcmp(actvar, "fg"))){ + char asciicolor[256]; + + if(ascii_colorstr(asciicolor, actval) == 0) { + if(!new_pat->action->incol){ + new_pat->action->incol = new_color_pair(asciicolor,NULL); + } + else + snprintf(new_pat->action->incol->fg, + sizeof(new_pat->action->incol->fg), "%s", asciicolor); + } + } + else if(new_pat->action->is_a_incol && !(strcmp(actvar, "bg"))){ + char asciicolor[256]; + + if(ascii_colorstr(asciicolor, actval) == 0) { + if(!new_pat->action->incol){ + new_pat->action->incol = new_color_pair(NULL, asciicolor); + } + else + snprintf(new_pat->action->incol->bg, + sizeof(new_pat->action->incol->bg), "%s", asciicolor); + } + } + else if(new_pat->action->is_a_score && !(strcmp(actvar, "scoreval"))){ + long scoreval = (long) atoi(actval); + + if(scoreval >= SCORE_MIN && scoreval <= SCORE_MAX) + new_pat->action->scoreval = scoreval; + } + else if(new_pat->action->is_a_score && !(strcmp(actvar, "scorehdr"))){ + HEADER_TOK_S *hdrtok; + + if((hdrtok = stringform_to_hdrtok(actval)) != NULL) + new_pat->action->scorevalhdrtok = hdrtok; + } + else{ + free_pat(&new_pat); + return(TCL_ERROR); + } + } + + if(new_pat->action->is_a_filter && new_pat->action->kill && new_pat->action->folder) + fs_give((void **)&new_pat->action->folder); + else if(new_pat->action->is_a_filter && new_pat->action->kill == 0 && new_pat->action->folder == 0){ + free_pat(&new_pat); + Tcl_SetResult(interp, "No folder set for Move", TCL_VOLATILE); + return(TCL_OK); + } + } + + if(aflags & RS_RULE_EDIT) + rv = edit_pattern(new_pat, rno, rflags); + else if(aflags & RS_RULE_ADD) + rv = add_pattern(new_pat, rflags); + else if(aflags & RS_RULE_DELETE) + rv = delete_pattern(rno, rflags); + else if(aflags & RS_RULE_SHUFFUP) + rv = shuffle_pattern(rno, 1, rflags); + else if(aflags & RS_RULE_SHUFFDOWN) + rv = shuffle_pattern(rno, -1, rflags); + else + rv = 1; + + return(rv ? TCL_ERROR : TCL_OK); +} + + +#if 0 +ADDRESS * +peAEToAddress(AdrBk_Entry *ae) +{ + char *list, *l1, *l2; + int length; + BuildTo bldto; + ADDRESS *addr = NULL; + + if(ae->tag == List){ + length = 0; + for(l2 = ae->addr.list; *l2; l2++) + length += (strlen(*l2) + 1); + + list = (char *) fs_get(length + 1); + list[0] = '\0'; + l1 = list; + for(l2 = ae->addr.list; *l2; l2++){ + if(l1 != list && l1-list < length+1) + *l1++ = ','; + + strncpy(l1, *l2, length+1-(l1-list)); + l1 += strlen(l1); + } + + list[length] = '\0'; + + bldto.type = Str; + bldto.arg.str = list; + adr2 = expand_address(bldto, userdomain, localdomain, + loop_detected, fcc, did_set, + lcc, error, 1, simple_verify, + mangled); + + fs_give((void **) &list); + } + else if(ae->tag == Single){ + if(strucmp(ae->addr.addr, a->mailbox)){ + bldto.type = Str; + bldto.arg.str = ae->addr.addr; + adr2 = expand_address(bldto, userdomain, + localdomain, loop_detected, + fcc, did_set, lcc, + error, 1, simple_verify, + mangled); + } + else{ + /* + * A loop within plain single entry is ignored. + * Set up so later code thinks we expanded. + */ + adr2 = mail_newaddr(); + adr2->mailbox = cpystr(ae->addr.addr); + adr2->host = cpystr(userdomain); + adr2->adl = cpystr(a->adl); + } + } + + /* + * Personal names: If the expanded address has a personal + * name and the address book entry is a list with a fullname, + * tack the full name from the address book on in front. + * This mainly occurs with a distribution list where the + * list has a full name, and the first person in the list also + * has a full name. + * + * This algorithm doesn't work very well if lists are + * included within lists, but it's not clear what would + * be better. + */ + if(ae->fullname && ae->fullname[0]){ + if(adr2->personal && adr2->personal[0]){ + if(ae->tag == List){ + /* combine list name and existing name */ + char *name; + + if(!simple_verify){ + size_t l; + l = strlen(adr2->personal) + strlen(ae->fullname) + 4; + name = (char *)fs_get((l+1) * sizeof(char)); + snprintf(name, l+1, "%s -- %s", ae->fullname, + adr2->personal); + fs_give((void **)&adr2->personal); + adr2->personal = name; + } + } + else{ + /* replace with nickname fullname */ + fs_give((void **)&adr2->personal); + adr2->personal = adrbk_formatname(ae->fullname, + NULL, NULL); + } + } + else{ + if(abe-p>tag != List || !simple_verify){ + if(adr2->personal) + fs_give((void **)&adr2->personal); + + adr2->personal = adrbk_formatname(abe->fullname, + NULL, NULL); + } + } + } + + return(addr); +} + + + +char * +peAEFcc(AdrBk_Entry *ae) +{ + char *fcc = NULL; + + if(ae->fcc && ae->fcc[0]){ + + if(!strcmp(ae->fcc, "\"\"")) + fcc = cpystr(""); + else + fcc = cpystr(ae->fcc); + + } + else if(ae->nickname && ae->nickname[0] && + (ps_global->fcc_rule == FCC_RULE_NICK || + ps_global->fcc_rule == FCC_RULE_NICK_RECIP)){ + /* + * else if fcc-rule=fcc-by-nickname, use that + */ + + fcc = cpystr(ae->nickname); + } + + return(fcc); +} +#endif + + +PINEFIELD * +peCustomHdrs(void) +{ + extern PINEFIELD *parse_custom_hdrs(char **, CustomType); + + return(parse_custom_hdrs(ps_global->VAR_CUSTOM_HDRS, UseAsDef)); +} + + + +/* + * PEClistCmd - Collection list editing tools + */ +int +PEClistCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *err = "Unknown PEClist request"; + + dprint((2, "PEClistCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + } + else{ + char *s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(objc == 3){ /* delete */ + if(!strcmp(s1, "delete")){ + int cl, i, n, deln; + char **newl; + CONTEXT_S *del_ctxt, *tmp_ctxt, *new_ctxt; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){ + Tcl_SetResult(interp, + "cledit malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + for(i = 0, del_ctxt = ps_global->context_list; + del_ctxt && i < cl; i++, del_ctxt = del_ctxt->next); + if(!del_ctxt) return(TCL_ERROR); + for(n = 0; del_ctxt->var.v->current_val.l[n]; n++); + n--; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + deln = del_ctxt->var.i; + for(i = 0; del_ctxt->var.v->current_val.l[i]; i++){ + if(i < deln) + newl[i] = cpystr(del_ctxt->var.v->current_val.l[i]); + else if(i > deln) + newl[i-1] = cpystr(del_ctxt->var.v->current_val.l[i]); + } + n = set_variable_list(del_ctxt->var.v - ps_global->vars, + *newl ? newl : NULL, TRUE, Main); + free_list_array(&newl); + set_current_val(del_ctxt->var.v, TRUE, FALSE); + if(n){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + for(tmp_ctxt = del_ctxt->next; tmp_ctxt && tmp_ctxt->var.v == + del_ctxt->var.v; tmp_ctxt = tmp_ctxt->next) + tmp_ctxt->var.i--; + if((tmp_ctxt = del_ctxt->next) != NULL) + tmp_ctxt->prev = del_ctxt->prev; + if((tmp_ctxt = del_ctxt->prev) != NULL) + tmp_ctxt->next= del_ctxt->next; + if(!del_ctxt->prev && !del_ctxt->next){ + new_ctxt = new_context(del_ctxt->var.v->current_val.l[0], NULL); + ps_global->context_list = new_ctxt; + if(!new_ctxt->var.v) + new_ctxt->var = del_ctxt->var; + } + else if(ps_global->context_list == del_ctxt){ + ps_global->context_list = del_ctxt->next; + if(!ps_global->context_list) + return TCL_ERROR; /* this shouldn't happen */ + } + if(ps_global->context_last == del_ctxt) + ps_global->context_last = NULL; + if(ps_global->context_current == del_ctxt){ + strncpy(ps_global->cur_folder, + ps_global->mail_stream->mailbox, + sizeof(ps_global->cur_folder)); + ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0'; + ps_global->context_current = ps_global->context_list; + } + del_ctxt->prev = NULL; + del_ctxt->next = NULL; + free_context(&del_ctxt); + init_inbox_mapping(ps_global->VAR_INBOX_PATH, + ps_global->context_list); + return TCL_OK; + } + else if(!strcmp(s1, "shuffdown")){ + int cl, i, shn, n; + CONTEXT_S *sh_ctxt, *nsh_ctxt, *tctxt; + char **newl, *tmpch; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){ + Tcl_SetResult(interp, + "cledit malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + for(sh_ctxt = ps_global->context_list, i = 0; + sh_ctxt && i < cl ; i++, sh_ctxt = sh_ctxt->next); + if(!sh_ctxt || !sh_ctxt->next){ + Tcl_SetResult(interp, + "invalid context list number", + TCL_VOLATILE); + return TCL_ERROR; + } + if(sh_ctxt->var.v == sh_ctxt->next->var.v){ + shn = sh_ctxt->var.i; + for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++); + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(i = 0; sh_ctxt->var.v->current_val.l[i]; i++){ + if(i == shn) + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i+1]); + else if(i == shn + 1) + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i-1]); + else + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]); + } + n = set_variable_list(sh_ctxt->var.v - ps_global->vars, + newl, TRUE, Main); + free_list_array(&newl); + set_current_val(sh_ctxt->var.v, TRUE, FALSE); + if(n){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + nsh_ctxt = sh_ctxt->next; + nsh_ctxt->var.i--; + sh_ctxt->var.i++; + } + else{ + nsh_ctxt = sh_ctxt->next; + shn = sh_ctxt->var.i; + tmpch = cpystr(sh_ctxt->var.v->current_val.l[shn]); + for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++); + n--; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(i = 0; sh_ctxt->var.v->current_val.l[i+1]; i++) + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]); + n = set_variable_list(sh_ctxt->var.v - ps_global->vars, + newl, FALSE, Main); + free_list_array(&newl); + set_current_val(sh_ctxt->var.v, TRUE, FALSE); + for(n = 0; nsh_ctxt->var.v->current_val.l[n]; n++); + n++; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + newl[0] = cpystr(nsh_ctxt->var.v->current_val.l[0]); + newl[1] = tmpch; + for(i = 2; nsh_ctxt->var.v->current_val.l[i-1]; i++) + newl[i] = cpystr(nsh_ctxt->var.v->current_val.l[i-1]); + n = set_variable_list(nsh_ctxt->var.v - ps_global->vars, + newl, TRUE, Main); + free_list_array(&newl); + set_current_val(nsh_ctxt->var.v, TRUE, FALSE); + sh_ctxt->var.v = nsh_ctxt->var.v; + sh_ctxt->var.i = 1; + /* this for loop assumes that there are only two variable lists, + * folder-collections and news-collections, a little more will + * have to be done if we want to accomodate for the INHERIT + * option introduced in 4.30. + */ + for(tctxt = nsh_ctxt->next; tctxt; tctxt = tctxt->next) + tctxt->var.i++; + } + if(sh_ctxt->prev) sh_ctxt->prev->next = nsh_ctxt; + nsh_ctxt->prev = sh_ctxt->prev; + sh_ctxt->next = nsh_ctxt->next; + nsh_ctxt->next = sh_ctxt; + sh_ctxt->prev = nsh_ctxt; + if(sh_ctxt->next) sh_ctxt->next->prev = sh_ctxt; + if(ps_global->context_list == sh_ctxt) + ps_global->context_list = nsh_ctxt; + init_inbox_mapping(ps_global->VAR_INBOX_PATH, + ps_global->context_list); + return TCL_OK; + } + else if(!strcmp(s1, "shuffup")){ + int cl, i, shn, n; + CONTEXT_S *sh_ctxt, *psh_ctxt, *tctxt; + char **newl, *tmpch; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){ + Tcl_SetResult(interp, + "cledit malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + for(sh_ctxt = ps_global->context_list, i = 0; + sh_ctxt && i < cl ; i++, sh_ctxt = sh_ctxt->next); + if(!sh_ctxt || !sh_ctxt->prev){ + Tcl_SetResult(interp, + "invalid context list number", + TCL_VOLATILE); + return TCL_ERROR; + } + if(sh_ctxt->var.v == sh_ctxt->prev->var.v){ + shn = sh_ctxt->var.i; + for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++); + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(i = 0; sh_ctxt->var.v->current_val.l[i]; i++){ + if(i == shn) + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i-1]); + else if(i == shn - 1) + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i+1]); + else + newl[i] = cpystr(sh_ctxt->var.v->current_val.l[i]); + } + i = set_variable_list(sh_ctxt->var.v - ps_global->vars, + newl, TRUE, Main); + free_list_array(&newl); + set_current_val(sh_ctxt->var.v, TRUE, FALSE); + if(i){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + psh_ctxt = sh_ctxt->prev; + psh_ctxt->var.i++; + sh_ctxt->var.i--; + } + else{ + psh_ctxt = sh_ctxt->prev; + shn = sh_ctxt->var.i; + tmpch = cpystr(sh_ctxt->var.v->current_val.l[shn]); + for(n = 0; sh_ctxt->var.v->current_val.l[n]; n++); + n--; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(i = 1; sh_ctxt->var.v->current_val.l[i]; i++) + newl[i-1] = cpystr(sh_ctxt->var.v->current_val.l[i]); + i = set_variable_list(sh_ctxt->var.v - ps_global->vars, + newl, FALSE, Main); + free_list_array(&newl); + if(i){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + set_current_val(sh_ctxt->var.v, TRUE, FALSE); + for(n = 0; psh_ctxt->var.v->current_val.l[n]; n++); + n++; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(i = 0; psh_ctxt->var.v->current_val.l[i+1]; i++) + newl[i] = cpystr(psh_ctxt->var.v->current_val.l[i]); + newl[i++] = tmpch; + newl[i] = cpystr(psh_ctxt->var.v->current_val.l[i-1]); + i = set_variable_list(psh_ctxt->var.v - ps_global->vars, + newl, TRUE, Main); + free_list_array(&newl); + if(i){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + set_current_val(psh_ctxt->var.v, TRUE, FALSE); + for(tctxt = sh_ctxt->next ; tctxt; tctxt = tctxt->next) + tctxt->var.i--; + sh_ctxt->var.v = psh_ctxt->var.v; + sh_ctxt->var.i = n - 2; + /* There MUST be at least 2 collections in the list */ + psh_ctxt->var.i++; + } + if(sh_ctxt->next) sh_ctxt->next->prev = psh_ctxt; + psh_ctxt->next = sh_ctxt->next; + sh_ctxt->prev = psh_ctxt->prev; + psh_ctxt->prev = sh_ctxt; + sh_ctxt->next = psh_ctxt; + if(sh_ctxt->prev) sh_ctxt->prev->next = sh_ctxt; + if(ps_global->context_list == psh_ctxt) + ps_global->context_list = sh_ctxt; + init_inbox_mapping(ps_global->VAR_INBOX_PATH, + ps_global->context_list); + return TCL_OK; + } + } + else if(objc == 7){ + if(!strcmp(s1, "edit") || !strcmp(s1, "add")){ + int cl, quotes_needed = 0, i, add = 0, n = 0; + char *nick, *server, *path, *view, + context_buf[MAILTMPLEN*4], **newl; + CONTEXT_S *new_ctxt, *tmp_ctxt; + + if(!strcmp(s1, "add")) add = 1; + + if(Tcl_GetIntFromObj(interp, objv[2], &cl) == TCL_ERROR){ + Tcl_SetResult(interp, + "cledit malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(!(nick = Tcl_GetStringFromObj(objv[3], NULL))){ + Tcl_SetResult(interp, + "Error1", + TCL_VOLATILE); + return TCL_ERROR; + } + if(!(server = Tcl_GetStringFromObj(objv[4], NULL))){ + Tcl_SetResult(interp, + "Error2", + TCL_VOLATILE); + return TCL_ERROR; + } + if(!(path = Tcl_GetStringFromObj(objv[5], NULL))){ + Tcl_SetResult(interp, + "Error3", + TCL_VOLATILE); + return TCL_ERROR; + } + if(!(view = Tcl_GetStringFromObj(objv[6], NULL))){ + Tcl_SetResult(interp, + "Error4", + TCL_VOLATILE); + return TCL_ERROR; + } + removing_leading_and_trailing_white_space(nick); + removing_leading_and_trailing_white_space(server); + removing_leading_and_trailing_white_space(path); + removing_leading_and_trailing_white_space(view); + if(strchr(nick, ' ')) + quotes_needed = 1; + if(strlen(nick)+strlen(server)+strlen(path)+strlen(view) > + MAILTMPLEN * 4 - 20) { /* for good measure */ + Tcl_SetResult(interp, + "info too long", + TCL_VOLATILE); + + return TCL_ERROR; + } + if(3 + strlen(nick) + strlen(server) + strlen(path) + + strlen(view) > MAILTMPLEN + 4){ + Tcl_SetResult(interp, + "collection fields too long", + TCL_VOLATILE); + return(TCL_OK); + } + snprintf(context_buf, sizeof(context_buf), "%s%s%s%s%s%s[%s]", quotes_needed ? + "\"" : "", nick, quotes_needed ? "\"" : "", + strlen(nick) ? " " : "", + server, path, view); + new_ctxt = new_context(context_buf, NULL); + if(!add){ + for(tmp_ctxt = ps_global->context_list, i = 0; + tmp_ctxt && i < cl; i++, tmp_ctxt = tmp_ctxt->next); + if(!tmp_ctxt){ + Tcl_SetResult(interp, + "invalid context list number", + TCL_VOLATILE); + return TCL_ERROR; + } + new_ctxt->next = tmp_ctxt->next; + new_ctxt->prev = tmp_ctxt->prev; + if(tmp_ctxt->prev && tmp_ctxt->prev->next == tmp_ctxt) + tmp_ctxt->prev->next = new_ctxt; + if(tmp_ctxt->next && tmp_ctxt->next->prev == tmp_ctxt) + tmp_ctxt->next->prev = new_ctxt; + if(ps_global->context_list == tmp_ctxt) + ps_global->context_list = new_ctxt; + if(ps_global->context_current == tmp_ctxt){ + strncpy(ps_global->cur_folder, + ps_global->mail_stream->mailbox, + sizeof(ps_global->cur_folder)); + ps_global->cur_folder[sizeof(ps_global->cur_folder)-1] = '\0'; + ps_global->context_current = new_ctxt; + } + if(ps_global->context_last == tmp_ctxt) + ps_global->context_last = new_ctxt; + new_ctxt->var = tmp_ctxt->var; + tmp_ctxt->next = tmp_ctxt->prev = NULL; + free_context(&tmp_ctxt); + } + else { + for(tmp_ctxt = ps_global->context_list; + tmp_ctxt->next; tmp_ctxt = tmp_ctxt->next); + new_ctxt->prev = tmp_ctxt; + tmp_ctxt->next = new_ctxt; + new_ctxt->var.v = tmp_ctxt->var.v; + new_ctxt->var.i = tmp_ctxt->var.i + 1; + } + if(!new_ctxt->var.v){ + Tcl_SetResult(interp, + "Error5", + TCL_VOLATILE); + return TCL_ERROR; + } + for(n = 0; new_ctxt->var.v->current_val.l[n]; n++); + if(add) n++; + newl = (char **) fs_get((n + 1) * sizeof(char *)); + newl[n] = NULL; + for(n = 0; new_ctxt->var.v->current_val.l[n]; n++) + newl[n] = (n == new_ctxt->var.i) + ? cpystr(context_buf) + : cpystr(new_ctxt->var.v->current_val.l[n]); + if(add) newl[n++] = cpystr(context_buf); + n = set_variable_list(new_ctxt->var.v - ps_global->vars, + newl, TRUE, Main); + free_list_array(&newl); + set_current_val(new_ctxt->var.v, TRUE, FALSE); + init_inbox_mapping(ps_global->VAR_INBOX_PATH, + ps_global->context_list); + if(n){ + Tcl_SetResult(interp, + "Error saving changes", + TCL_VOLATILE); + return TCL_OK; + } + return TCL_OK; + + } + } + } + } + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +/* + * peTakeaddr - Take Address + */ +int +peTakeaddr(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + TA_S *talist = NULL, *current, *head; + Tcl_Obj *itemObj, *secObj = NULL, *resObj = NULL; + int anum = 0; + + mn_set_cur(sp_msgmap(ps_global->mail_stream), peMessageNumber(uid)); + + if(set_up_takeaddr('a', ps_global, sp_msgmap(ps_global->mail_stream), + &talist, &anum, TA_NOPROMPT, NULL) < 0 + || (talist == NULL)){ + Tcl_SetResult(interp, + "Take address failed to set up", + TCL_VOLATILE); + return(TCL_ERROR); + } + + for(head = talist ; head->prev; head = head->prev); + /* + * Return value will be of the form: + * { + * { "line to print", + * {"personal", "mailbox", "host"} # addr + * {"nick", "fullname", "fcc", "comment"} # suggested + * } + * ... + * } + * + * The two list items will be empty if that line is + * just informational. + */ + itemObj = Tcl_NewListObj(0, NULL); + for(current = head; current ; current = current->next){ + if(current->skip_it && !current->print) continue; + secObj = Tcl_NewListObj(0, NULL); + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(current->strvalue,-1)) != TCL_OK) + return(TCL_ERROR); + resObj = Tcl_NewListObj(0, NULL); + /* append the address information */ + if(current->addr && !current->print){ + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->addr->personal + ? current->addr->personal + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->addr->mailbox + ? current->addr->mailbox + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->addr->host + ? current->addr->host + : "", -1)) != TCL_OK) + return(TCL_ERROR); + } + if(Tcl_ListObjAppendElement(interp, secObj, + resObj) != TCL_OK) + return(TCL_ERROR); + resObj = Tcl_NewListObj(0, NULL); + /* append the suggested possible entries */ + if(!current->print + && (current->nickname || current->fullname + || current->fcc || current->comment)){ + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->nickname + ? current->nickname + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->fullname + ? current->fullname + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->fcc + ? current->fcc + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(current->comment + ? current->comment + : "", -1)) != TCL_OK) + return(TCL_ERROR); + } + if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + secObj) != TCL_OK) + return(TCL_ERROR); + } + + free_talines(&talist); + return(TCL_OK); +} + + +/* + * peTakeFrom - Take only From Address + */ +int +peTakeFrom(Tcl_Interp *interp, imapuid_t uid, int objc, Tcl_Obj **objv) +{ + char *err = NULL; + Tcl_Obj *objItem; + ADDRESS *ap; + ENVELOPE *env; + long rawno; + + /* + * Return value will be of the form: + * { + * { "line to print", + * {"personal", "mailbox", "host"} # addr + * {"nick", "fullname", "fcc", "comment"} # suggested + * } + * ... + * } + * + * The two list items will be empty if that line is + * just informational. + */ + + if(uid){ + if((env = pine_mail_fetchstructure(ps_global->mail_stream, + rawno = peSequenceNumber(uid), + NULL))){ + /* append the address information */ + for(ap = env->from; ap; ap = ap->next){ + objItem = Tcl_NewListObj(0, NULL); + /* append EMPTY "line to print" */ + if(Tcl_ListObjAppendElement(interp, objItem, Tcl_NewStringObj("",-1)) != TCL_OK) + return(TCL_ERROR); + + /* append address info */ + peAppListF(interp, objItem, "%s%s%s", + ap->personal ? (char *) rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, ap->personal) : "", + ap->mailbox ? ap->mailbox : "", + ap->host ? ap->host : ""); + + /* append suggested info */ + peAddSuggestedContactInfo(interp, objItem, ap); + + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), objItem) != TCL_OK) + return(TCL_ERROR); + } + + return(TCL_OK); + } + else + err = ps_global->last_error; + } + else + err = "Invalid UID"; + + return(TCL_ERROR); +} + + +int +peAddSuggestedContactInfo(Tcl_Interp *interp, Tcl_Obj *lobjp, ADDRESS *addr) +{ + char *nick = NULL, *full = NULL, *fcc = NULL, *comment = NULL; + + get_contactinfo_from_addr(addr, &nick, &full, &fcc, &comment); + + peAppListF(interp, lobjp, "%s%s%s%s", + nick ? nick : "", + full ? full : "", + fcc ? fcc : "", + comment ? comment : ""); + + if(nick) + fs_give((void **) &nick); + + if(full) + fs_give((void **) &full); + + if(fcc) + fs_give((void **) &fcc); + + if(comment) + fs_give((void **) &comment); +} + + +/* * * * * * * * * Status message ring management * * * * * * * * * * * * */ + +STATMSG_S * +sml_newmsg(int priority, char *text) +{ + static long id = 1; + STATMSG_S *smp; + + smp = (STATMSG_S *) fs_get(sizeof(STATMSG_S)); + memset(smp, 0, sizeof(STATMSG_S)); + smp->id = id++; + smp->posted = time(0); + smp->type = priority; + smp->text = cpystr(text); + return(smp); +} + + +void +sml_addmsg(int priority, char *text) +{ + STATMSG_S *smp = sml_newmsg(priority, text); + + if(peStatList){ + smp->next = peStatList; + peStatList = smp; + } + else + peStatList = smp; +} + + +char ** +sml_getmsgs(void) +{ + int n; + STATMSG_S *smp; + char **retstrs = NULL, **tmpstrs; + + for(n = 0, smp = peStatList; smp && !smp->seen; n++, smp = smp->next) + ; + + if(n == 0) return NULL; + retstrs = (char **)fs_get((n+1)*sizeof(char *)); + for(tmpstrs = retstrs, smp = peStatList; smp && !smp->seen; smp = smp->next){ + *tmpstrs = smp->text; + tmpstrs++; + } + + *tmpstrs = NULL; + return(retstrs); +} + + +char * +sml_getmsg(void) +{ + return(peStatList ? peStatList->text : ""); +} + +void +sml_seen(void) +{ + STATMSG_S *smp; + + for(smp = peStatList; smp; smp = smp->next) + smp->seen = 1; +} + + + +/* * * * * * * * * LDAP Support Routines * * * * * * * * * * * */ + + +/* + * PELdapCmd - LDAP TCL interface + */ +int +PELdapCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ +#ifndef ENABLE_LDAP + char *err = "Call to PELdap when LDAP not enabled"; +#else + char *err = "Unknown PELdap request"; + char *s1; + + dprint((2, "PELdapCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); + } + s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + int qn; + if(!strcmp(s1, "directories")){ + int i; + LDAP_SERV_S *info; + Tcl_Obj *secObj; + + if(objc != 2){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); + } + if(ps_global->VAR_LDAP_SERVERS){ + for(i = 0; ps_global->VAR_LDAP_SERVERS[i] && + ps_global->VAR_LDAP_SERVERS[i][0]; i++){ + info = break_up_ldap_server(ps_global->VAR_LDAP_SERVERS[i]); + secObj = Tcl_NewListObj(0, NULL); + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(info->nick ? info->nick + : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(info->serv ? info->serv + : "", -1)) != TCL_OK) + return(TCL_ERROR); + + if(info) + free_ldap_server_info(&info); + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + secObj) != TCL_OK) + return(TCL_ERROR); + } + } + else + Tcl_SetResult(interp, "", TCL_STATIC); + + return(TCL_OK); + } + else if(!strcmp(s1, "query")){ + int dir; + char *srchstr, *filtstr; + LDAP_CHOOSE_S *winning_e = NULL; + LDAP_SERV_RES_S *results = NULL; + WP_ERR_S wp_err; + CUSTOM_FILT_S *filter = NULL; + + if(objc != 5){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); + } + if(Tcl_GetIntFromObj(interp, objv[2], &dir) == TCL_ERROR){ + Tcl_SetResult(interp, + "PELdap results malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + wpldap_global->query_no++; + if(wpldap_global->ldap_search_list){ + wpldap_global->ldap_search_list = + free_wpldapres(wpldap_global->ldap_search_list); + } + srchstr = Tcl_GetStringFromObj(objv[3], NULL); + filtstr = Tcl_GetStringFromObj(objv[4], NULL); + if(!srchstr) return(TCL_ERROR); + if(!filtstr) return(TCL_ERROR); + if(*filtstr){ + filter = (CUSTOM_FILT_S *)fs_get(sizeof(CUSTOM_FILT_S)); + filter->filt = cpystr(filtstr); + filter->combine = 0; + } + memset(&wp_err, 0, sizeof(wp_err)); + ldap_lookup_all(srchstr, dir, 0, AlwaysDisplay, filter, &winning_e, + &wp_err, &results); + if(filter){ + fs_give((void **)&filter->filt); + fs_give((void **)&filter); + } + Tcl_SetResult(interp, int2string(wpldap_global->ldap_search_list + ? wpldap_global->query_no : 0), + TCL_VOLATILE); + return(TCL_OK); + } + /* + * First argument has always got to be the query number for now. + * Might need to rething that when setting up queries. + */ + if(objc == 2){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); + } + if(Tcl_GetIntFromObj(interp, objv[2], &qn) == TCL_ERROR){ + Tcl_SetResult(interp, + "PELdap results malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(qn != wpldap_global->query_no){ + Tcl_SetResult(interp, + "Query is no longer valid", TCL_VOLATILE); + return(TCL_ERROR); + } + if(objc == 3){ + if(!strcmp(s1, "results")){ + return(peLdapQueryResults(interp)); + } + } + else if(objc == 4){ + if(!strcmp(s1, "ldapext")){ + /* + * Returns a list of the form: + * {"dn" {{attrib {val, ...}}, ...}} + */ + char *whichrec = Tcl_GetStringFromObj(objv[3], NULL); + char *tmpstr, *tmp, *tmp2, **vals, *a; + WPLDAPRES_S *curres; + LDAP_CHOOSE_S *winning_e = NULL; + LDAP_SERV_RES_S *trl; + Tcl_Obj *secObj = NULL, *resObj = NULL, *itemObj; + BerElement *ber; + LDAPMessage *e; + int i, j, whichi, whichj; + + if(whichrec == NULL){ + Tcl_SetResult(interp, "Ldap ldapext error 1", TCL_VOLATILE); + return TCL_ERROR; + } + tmpstr = cpystr(whichrec); + tmp = tmpstr; + for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != '.'){ + Tcl_SetResult(interp, "Ldap ldapext error 2", TCL_VOLATILE); + return TCL_ERROR; + } + *tmp2 = '\0'; + whichi = atoi(tmp); + *tmp2 = '.'; + tmp2++; + for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != '\0'){ + Tcl_SetResult(interp, "Ldap ldapext error 3", TCL_VOLATILE); + return TCL_ERROR; + } + whichj = atoi(tmp); + fs_give((void **)&tmpstr); + for(curres = wpldap_global->ldap_search_list, i = 0; + i < whichi && curres; i++, curres = curres->next); + if(!curres){ + Tcl_SetResult(interp, "Ldap ldapext error 4", TCL_VOLATILE); + return TCL_ERROR; + } + for(trl = curres->reslist, j = 0; trl; trl = trl->next){ + for(e = ldap_first_entry(trl->ld, trl->res); + e != NULL && j < whichj; + e = ldap_next_entry(trl->ld, e), j++); + if(e != NULL && j == whichj) + break; + } + if(e == NULL || trl == NULL){ + Tcl_SetResult(interp, "Ldap ldapext error 5", TCL_VOLATILE); + return TCL_ERROR; + } + winning_e = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S)); + winning_e->ld = trl->ld; + winning_e->selected_entry = e; + winning_e->info_used = trl->info_used; + winning_e->serv = trl->serv; + a = ldap_get_dn(winning_e->ld, winning_e->selected_entry); + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(a ? a : "", -1)) != TCL_OK) + return(TCL_ERROR); + if(a) + our_ldap_dn_memfree(a); + + itemObj = Tcl_NewListObj(0, NULL); + for(a = ldap_first_attribute(winning_e->ld, winning_e->selected_entry, &ber); + a != NULL; + a = ldap_next_attribute(winning_e->ld, winning_e->selected_entry, ber)){ + if(a && *a){ + secObj = Tcl_NewListObj(0, NULL); + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(ldap_translate(a, + winning_e->info_used), -1)) != TCL_OK) + return(TCL_ERROR); + resObj = Tcl_NewListObj(0, NULL); + vals = ldap_get_values(winning_e->ld, winning_e->selected_entry, a); + if(vals){ + for(i = 0; vals[i]; i++){ + if(Tcl_ListObjAppendElement(interp, resObj, + Tcl_NewStringObj(vals[i], -1)) != TCL_OK) + return(TCL_ERROR); + } + ldap_value_free(vals); + if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK) + return(TCL_ERROR); + } + if(!strcmp(a,"objectclass")){ + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj("objectclass", -1)) != TCL_OK) + return(TCL_ERROR); + } + if(Tcl_ListObjAppendElement(interp, itemObj, secObj) != TCL_OK) + return(TCL_ERROR); + } + our_ldap_memfree(a); + } + + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + itemObj) != TCL_OK) + return(TCL_ERROR); + + fs_give((void **)&winning_e); + return(TCL_OK); + } + } + else if(objc == 6){ + if(!strcmp(s1, "setaddrs")){ + char *listset = Tcl_GetStringFromObj(objv[3], NULL); + char *addrstr = Tcl_GetStringFromObj(objv[4], NULL); + char *tmp, *tmp2, *tmplistset, was_char, *ret_to, + *tmpaddrstr; + int **lset, noreplace = 0; + ADDRESS *adr = NULL, *curadr, *prevadr, *newadr, + *curnewadr, *newadrs; + int curi, i, j, numsrchs, numset, setit; + LDAP_CHOOSE_S *tres; + LDAP_SERV_RES_S *trl; + WPLDAPRES_S *curres; + LDAPMessage *e; + RFC822BUFFER rbuf; + size_t len; + + if(Tcl_GetIntFromObj(interp, objv[5], &noreplace) == TCL_ERROR){ + Tcl_SetResult(interp, + "PELdap results malformed: first arg must be int", + TCL_VOLATILE); + return(TCL_ERROR); + } + if(listset == NULL || addrstr == NULL) return TCL_ERROR; + tmpaddrstr = cpystr(addrstr); + + if(!noreplace){ + mail_parameters(NIL, SET_PARSEPHRASE, (void *)massage_phrase_addr); + rfc822_parse_adrlist(&adr, tmpaddrstr, "@"); + mail_parameters(NIL, SET_PARSEPHRASE, NULL); + } + + tmplistset = cpystr(listset); + for(curres = wpldap_global->ldap_search_list, numsrchs = 0; + curres; curres = curres->next, numsrchs++); + lset = (int **)fs_get((numsrchs+1)*sizeof(int *)); + for(i = 0; i < numsrchs; i++){ + for(tmp = tmplistset, numset = 0; *tmp;){ + for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != '.'){ + Tcl_SetResult(interp, "Ldap error 1", TCL_VOLATILE); + return TCL_ERROR; + } + if(atoi(tmp) == i) numset++; + tmp2++; + for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != ',' && *tmp2 != '\0'){ + Tcl_SetResult(interp, "Ldap error 2", TCL_VOLATILE); + return TCL_ERROR; + } + if(*tmp2) tmp2++; + tmp = tmp2; + } + lset[i] = (int *)fs_get((numset+1)*sizeof(int)); + for(tmp = tmplistset, j = 0; *tmp && j < numset;){ + setit = 0; + for(tmp2 = tmp; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != '.'){ + Tcl_SetResult(interp, "Ldap error 3", TCL_VOLATILE); + return TCL_ERROR; + } + *tmp2 = '\0'; + if(atoi(tmp) == i) setit++; + *tmp2 = '.'; + tmp2++; + for(tmp = tmp2; *tmp2 >= '0' && *tmp2 <= '9'; tmp2++); + if(*tmp2 != ',' && *tmp2 != '\0'){ + Tcl_SetResult(interp, "Ldap error 4", TCL_VOLATILE); + return TCL_ERROR; + } + if(setit){ + was_char = *tmp2; + *tmp2 = '\0'; + lset[i][j++] = atoi(tmp); + *tmp2 = was_char; + } + if(*tmp2) tmp2++; + tmp = tmp2; + } + lset[i][j] = -1; + } + lset[i] = NULL; + for(i = 0, curres = wpldap_global->ldap_search_list; + i < numsrchs && curres; i++, curres = curres->next){ + prevadr = NULL; + for(curadr = adr; curadr; curadr = curadr->next){ + if(strcmp(curadr->mailbox, curres->str) == 0 + && curadr->host && *curadr->host == '@') + break; + prevadr = curadr; + } + if(!curadr && !noreplace){ + Tcl_SetResult(interp, "Ldap error 5", TCL_VOLATILE); + return TCL_ERROR; + } + newadrs = newadr = curnewadr = NULL; + for(trl = curres->reslist, j = 0, curi = 0; trl; trl = trl->next){ + for(e = ldap_first_entry(trl->ld, trl->res); + e != NULL && lset[i][curi] != -1; + e = ldap_next_entry(trl->ld, e), j++){ + if(j == lset[i][curi]){ + tres = (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S)); + tres->ld = trl->ld; + tres->selected_entry = e; + tres->info_used = trl->info_used; + tres->serv = trl->serv; + newadr = address_from_ldap(tres); + fs_give((void **)&tres); + + if(newadrs == NULL){ + newadrs = curnewadr = newadr; + } + else { + curnewadr->next = newadr; + curnewadr = newadr; + } + curi++; + } + } + } + if(newadrs == NULL || curnewadr == NULL){ + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "No Result Selected for \"%s\"", curadr->mailbox ? curadr->mailbox : "noname"); + q_status_message(SM_ORDER, 0, 3, tmp_20k_buf); + newadr = copyaddr(curadr); + if(newadrs == NULL){ + newadrs = curnewadr = newadr; + } + else { + curnewadr->next = newadr; + curnewadr = newadr; + } + } + curnewadr->next = curadr ? curadr->next : NULL; + if(curadr) curadr->next = NULL; + if(curadr == adr) + adr = newadrs; + else{ + prevadr->next = newadrs; + if(curadr) + mail_free_address(&curadr); + } + } + + len = est_size(adr); + ret_to = (char *)fs_get(len * sizeof(char)); + ret_to[0] = '\0'; + strip_personal_quotes(adr); + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = ret_to; + rbuf.cur = ret_to; + rbuf.end = ret_to+len-1; + rfc822_output_address_list(&rbuf, adr, 0L, NULL); + *rbuf.cur = '\0'; + Tcl_SetResult(interp, ret_to, TCL_VOLATILE); + fs_give((void **)&ret_to); + fs_give((void **)&tmpaddrstr); + fs_give((void **)&tmplistset); + for(i = 0; lset[i]; i++) + fs_give((void **)&lset[i]); + fs_give((void **)&lset); + if(adr) + mail_free_address(&adr); + + return(TCL_OK); + } + } + } +#endif /* ENABLE_LDAP */ + Tcl_SetResult(interp, err, TCL_STATIC); + return(TCL_ERROR); +} + + +#ifdef ENABLE_LDAP +int +peLdapQueryResults(Tcl_Interp *interp) +{ + WPLDAPRES_S *tsl; + Tcl_Obj *secObj = NULL, *resObj = NULL, *itemObj; + LDAPMessage *e; + LDAP_SERV_RES_S *trl; + /* returned list will be of the form: + * + * { + * {search-string + * {name, {title, ...}, {unit, ...}, + * {org, ...}, {email, ...}}, + * ... + * }, + * ... + * } + */ + + for(tsl = wpldap_global->ldap_search_list; + tsl; tsl = tsl->next){ + secObj = Tcl_NewListObj(0, NULL); + if(Tcl_ListObjAppendElement(interp, secObj, + Tcl_NewStringObj(tsl->str ? tsl->str + : "", -1)) != TCL_OK) + return(TCL_ERROR); + resObj = Tcl_NewListObj(0, NULL); + for(trl = tsl->reslist; trl; trl = trl->next){ + for(e = ldap_first_entry(trl->ld, trl->res); + e != NULL; + e = ldap_next_entry(trl->ld, e)){ + char *dn; + char **cn, **org, **unit, **title, **mail, **sn; + + dn = NULL; + cn = org = title = unit = mail = sn = NULL; + + itemObj = Tcl_NewListObj(0, NULL); + peLdapEntryParse(trl, e, &cn, &org, &unit, &title, + &mail, &sn); + if(cn){ + if(Tcl_ListObjAppendElement(interp, itemObj, + Tcl_NewStringObj(cn[0], -1)) != TCL_OK) + return(TCL_ERROR); + ldap_value_free(cn); + } + else if(sn){ + if(Tcl_ListObjAppendElement(interp, itemObj, + Tcl_NewStringObj(sn[0], -1)) != TCL_OK) + return(TCL_ERROR); + ldap_value_free(sn); + } + else{ + dn = ldap_get_dn(trl->ld, e); + + if(dn && !dn[0]){ + our_ldap_dn_memfree(dn); + dn = NULL; + } + + if(Tcl_ListObjAppendElement(interp, itemObj, + Tcl_NewStringObj(dn ? dn : "", -1)) != TCL_OK) + return(TCL_ERROR); + + if(dn) + our_ldap_dn_memfree(dn); + } + if(peLdapStrlist(interp, itemObj, title) == TCL_ERROR) + return(TCL_ERROR); + if(peLdapStrlist(interp, itemObj, unit) == TCL_ERROR) + return(TCL_ERROR); + if(peLdapStrlist(interp, itemObj, org) == TCL_ERROR) + return(TCL_ERROR); + if(peLdapStrlist(interp, itemObj, mail) == TCL_ERROR) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, resObj, itemObj) != TCL_OK) + return(TCL_ERROR); + if(title) + ldap_value_free(title); + if(unit) + ldap_value_free(unit); + if(org) + ldap_value_free(org); + if(mail) + ldap_value_free(mail); + } + } + if(Tcl_ListObjAppendElement(interp, secObj, resObj) != TCL_OK) + return(TCL_ERROR); + if(Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + secObj) != TCL_OK) + return(TCL_ERROR); + } + return(TCL_OK); +} + +int +peLdapStrlist(Tcl_Interp *interp, Tcl_Obj *itemObj, char **strl) +{ + Tcl_Obj *strlObj; + int i; + + strlObj = Tcl_NewListObj(0, NULL); + if(strl){ + for(i = 0; strl[i] && strl[i][0]; i++){ + if(Tcl_ListObjAppendElement(interp, strlObj, + Tcl_NewStringObj(strl[i], -1)) != TCL_OK) + return(TCL_ERROR); + } + } + if(Tcl_ListObjAppendElement(interp, itemObj, strlObj) != TCL_OK) + return(TCL_ERROR); + return(TCL_OK); +} + + +int +init_ldap_pname(struct pine *ps) +{ + if(!ps_global->VAR_PERSONAL_NAME + || ps_global->VAR_PERSONAL_NAME[0] == '\0'){ + char *pname; + struct variable *vtmp; + + if(ps->maildomain && *ps->maildomain + && ps->VAR_USER_ID && *ps->VAR_USER_ID){ + pname = peLdapPname(ps->VAR_USER_ID, ps->maildomain); + if(pname){ + vtmp = &ps->vars[V_PERSONAL_NAME]; + if((vtmp->fixed_val.p && vtmp->fixed_val.p[0] == '\0') + || (vtmp->is_fixed && !vtmp->fixed_val.p)){ + if(vtmp->fixed_val.p) + fs_give((void **)&vtmp->fixed_val.p); + vtmp->fixed_val.p = cpystr(pname); + } + else { + if(vtmp->global_val.p) + fs_give((void **)&vtmp->global_val.p); + vtmp->global_val.p = cpystr(pname); + } + fs_give((void **)&pname); + set_current_val(vtmp, FALSE, FALSE); + } + } + } + return 0; +} +#endif /* ENABLE_LDAP */ + +/* + * Note: this is taken straight out of pico/composer.c + * + * strqchr - returns pointer to first non-quote-enclosed occurance of ch in + * the given string. otherwise NULL. + * s -- the string + * ch -- the character we're looking for + * q -- q tells us if we start out inside quotes on entry and is set + * correctly on exit. + * m -- max characters we'll check for ch (set to -1 for no check) + */ +char * +strqchr(char *s, int ch, int *q, int m) +{ + int quoted = (q) ? *q : 0; + + for(; s && *s && m != 0; s++, m--){ + if(*s == '"'){ + quoted = !quoted; + if(q) + *q = quoted; + } + + if(!quoted && *s == ch) + return(s); + } + + return(NULL); +} + + +Tcl_Obj * +wp_prune_folders(CONTEXT_S *ctxt, + char *fcc, + int cur_month, + char *type, + unsigned pr, + int *ok, + int moved_fldrs, + Tcl_Interp *interp) +{ + Tcl_Obj *resObj = NULL, *secObj = NULL; + char path2[MAXPATH+1], tmp[21]; + int exists, month_to_use; + struct sm_folder *mail_list, *sm; + + mail_list = get_mail_list(ctxt, fcc); + + for(sm = mail_list; sm != NULL && sm->name != NULL; sm++) + if(sm->month_num == cur_month - 1) + break; /* matched a month */ + + month_to_use = (sm == NULL || sm->name == NULL) ? cur_month - 1 : 0; + + if(!(month_to_use == 0 || pr == PRUNE_NO_AND_ASK || pr == PRUNE_NO_AND_NO)){ + strncpy(path2, fcc, sizeof(path2)-1); + path2[sizeof(path2)-1] = '\0'; + strncpy(tmp, month_abbrev((month_to_use % 12)+1), sizeof(tmp)-1); + tmp[sizeof(tmp)-1] = '\0'; + lcase((unsigned char *) tmp); + snprintf(path2 + strlen(path2), sizeof(path2)-strlen(path2), "-%.20s-%d", tmp, month_to_use/12); + + if((exists = folder_exists(ctxt, fcc)) == FEX_ERROR){ + (*ok) = 0; + return(NULL); + } + else if(exists & FEX_ISFILE){ + if(pr == PRUNE_YES_AND_ASK || (pr == PRUNE_YES_AND_NO && !moved_fldrs)){ + prune_move_folder(fcc, path2, ctxt); + } else { + resObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, resObj, Tcl_NewStringObj(type, -1)); + secObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(fcc, -1)); + Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(path2, -1)); + Tcl_ListObjAppendElement(interp, resObj, secObj); + } + } + } + if(pr == PRUNE_ASK_AND_ASK || pr == PRUNE_YES_AND_ASK + || pr == PRUNE_NO_AND_ASK){ + sm = mail_list; + if(!resObj && sm && sm->name && sm->name[0] != '\0'){ + resObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, resObj, Tcl_NewStringObj(type, -1)); + Tcl_ListObjAppendElement(interp, resObj, Tcl_NewListObj(0, NULL)); + } + if(resObj) + secObj = Tcl_NewListObj(0, NULL); + for(sm = mail_list; sm != NULL && sm->name != NULL; sm++){ + if(sm->name[0] == '\0') /* can't happen */ + continue; + Tcl_ListObjAppendElement(interp, secObj, Tcl_NewStringObj(sm->name, -1)); + } + if(resObj) + Tcl_ListObjAppendElement(interp, resObj, secObj); + } else if(resObj) + Tcl_ListObjAppendElement(interp, resObj, Tcl_NewListObj(0, NULL)); + + free_folder_list(ctxt); + + if((sm = mail_list) != NULL){ + while(sm->name){ + fs_give((void **)&(sm->name)); + sm++; + } + + fs_give((void **)&mail_list); + } + + return(resObj); +} + + +int +hex_colorstr(char *hexcolor, char *str) +{ + char *tstr, *p, *p2, tbuf[256]; + int i; + + strcpy(hexcolor, "000000"); + tstr = color_to_asciirgb(str); + p = tstr; + p2 = strindex(p, ','); + if(p2 == NULL) return 0; + strncpy(tbuf, p, min(50, p2-p)); + i = atoi(tbuf); + sprintf(hexcolor, "%2.2x", i); + p = p2+1; + p2 = strindex(p, ','); + if(p2 == NULL) return 0; + strncpy(tbuf, p, min(50, p2-p)); + i = atoi(tbuf); + sprintf(hexcolor+2, "%2.2x", i); + p = p2+1; + strncpy(tbuf, p, 50); + i = atoi(tbuf); + sprintf(hexcolor+4, "%2.2x", i); + + return 0; +} + +int +hexval(char ch) +{ + if(ch >= '0' && ch <= '9') + return (ch - '0'); + else if (ch >= 'A' && ch <= 'F') + return (10 + (ch - 'A')); + else if (ch >= 'a' && ch <= 'f') + return (10 + (ch - 'a')); + return -1; +} + +int +ascii_colorstr(char *acolor, char *hexcolor) +{ + int i, hv; + + if(strlen(hexcolor) > 6) return 1; + /* red value */ + if((hv = hexval(hexcolor[0])) == -1) return 1; + i = 16 * hv; + if((hv = hexval(hexcolor[1])) == -1) return 1; + i += hv; + sprintf(acolor, "%3.3d,", i); + /* green value */ + if((hv = hexval(hexcolor[2])) == -1) return 1; + i = 16 * hv; + if((hv = hexval(hexcolor[3])) == -1) return 1; + i += hv; + sprintf(acolor+4, "%3.3d,", i); + /* blue value */ + if((hv = hexval(hexcolor[4])) == -1) return 1; + i = 16 * hv; + if((hv = hexval(hexcolor[5])) == -1) return 1; + i += hv; + sprintf(acolor+8, "%3.3d", i); + + return 0; +} + + +char * +peRandomString(char *b, int l, int f) +{ + static char *kb = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + char *s = b; + int j; + long n; + + while(1){ + n = random(); + for(j = 0; j < ((sizeof(long) * 8) / 5); j++){ + if(l-- <= 0){ + *s = '\0'; + return(b); + } + + switch(f){ + case PRS_LOWER_CASE : + *s++ = (char) tolower((unsigned char) kb[(n & 0x1F)]); + break; + + case PRS_MIXED_CASE : + if(random() % 2){ + *s++ = (char) tolower((unsigned char) kb[(n & 0x1F)]); + break; + } + + default : + *s++ = kb[(n & 0x1F)]; + break; + } + + n = n >> 5; + } + } +} + + +long +peAppendMsg(MAILSTREAM *stream, void *data, char **flags, char **date, STRING **message) +{ + char *t,*t1,tmp[MAILTMPLEN]; + unsigned long u; + MESSAGECACHE *elt; + APPEND_PKG *ap = (APPEND_PKG *) data; + *flags = *date = NIL; /* assume no flags or date */ + if (ap->flags) fs_give ((void **) &ap->flags); + if (ap->date) fs_give ((void **) &ap->date); + mail_gc (ap->stream,GC_TEXTS); + if (++ap->msgno <= ap->msgmax) { + /* initialize flag string */ + memset (t = tmp,0,MAILTMPLEN); + /* output system flags */ + if ((elt = mail_elt (ap->stream,ap->msgno))->seen) {strncat (t," \\Seen", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';} + if (elt->deleted) {strncat (t," \\Deleted", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';} + if (elt->flagged) {strncat (t," \\Flagged", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';} + if (elt->answered) {strncat (t," \\Answered", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';} + if (elt->draft) {strncat (t," \\Draft", sizeof(tmp)-(t-tmp)-1); tmp[sizeof(tmp)-1] = '\0';} + if ((u = elt->user_flags) != 0L) do /* any user flags? */ + if ((MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long) + (2 + strlen + (t1 = ap->stream->user_flags[find_rightmost_bit (&u)]))) { + if(t-tmp < sizeof(tmp)) + *t++ = ' '; /* space delimiter */ + strncpy (t,t1,sizeof(tmp)-(t-tmp)); /* copy the user flag */ + } + while (u); /* until no more user flags */ + tmp[sizeof(tmp)-1] = '\0'; + *flags = ap->flags = cpystr (tmp + 1); + *date = ap->date = cpystr (mail_date (tmp,elt)); + *message = ap->message; /* message stringstruct */ + INIT (ap->message,mstring,(void *) ap,elt->rfc822_size); + } + else *message = NIL; /* all done */ + return LONGT; +} + + +/* Initialize file string structure for file stringstruct +* Accepts: string structure + * pointer to message data structure + * size of string + */ + +void +ms_init(STRING *s, void *data, unsigned long size) +{ + APPEND_PKG *md = (APPEND_PKG *) data; + s->data = data; /* note stream/msgno and header length */ + mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,FT_PREFETCHTEXT); + mail_fetchtext_full (md->stream,md->msgno,&s->size,NIL); + s->size += s->data1; /* header + body size */ + SETPOS (s,0); +} + + +/* Get next character from file stringstruct + * Accepts: string structure + * Returns: character, string structure chunk refreshed + */ +char +ms_next(STRING *s) +{ + char c = *s->curpos++; /* get next byte */ + SETPOS (s,GETPOS (s)); /* move to next chunk */ + return c; /* return the byte */ +} + + +/* Set string pointer position for file stringstruct + * Accepts: string structure + * new position + */ +void +ms_setpos(STRING *s, unsigned long i) +{ + APPEND_PKG *md = (APPEND_PKG *) s->data; + if (i < s->data1) { /* want header? */ + s->chunk = mail_fetchheader (md->stream,md->msgno); + s->chunksize = s->data1; /* header length */ + s->offset = 0; /* offset is start of message */ + } + else if (i < s->size) { /* want body */ + s->chunk = mail_fetchtext (md->stream,md->msgno); + s->chunksize = s->size - s->data1; + s->offset = s->data1; /* offset is end of header */ + } + else { /* off end of message */ + s->chunk = NIL; /* make sure that we crack on this then */ + s->chunksize = 1; /* make sure SNX cracks the right way... */ + s->offset = i; + } + /* initial position and size */ + s->curpos = s->chunk + (i -= s->offset); + s->cursize = s->chunksize - i; +} + + +int +remote_pinerc_failure(void) +{ + snprintf(ps_global->last_error, sizeof(ps_global->last_error), "%s", + ps_global->c_client_error[0] + ? ps_global->c_client_error + : _("Unable to read remote configuration")); + + return(TRUE); +} + +char * +peWebAlpinePrefix(void) +{ + return("Web "); +} + + +void peNewMailAnnounce(MAILSTREAM *stream, long n, long t_nm_count){ + char subject[MAILTMPLEN+1], subjtext[MAILTMPLEN+1], from[MAILTMPLEN+1], + *folder = NULL, intro[MAILTMPLEN+1]; + long number; + ENVELOPE *e = NULL; + Tcl_Obj *resObj; + + if(n && (resObj = Tcl_NewListObj(0, NULL)) != NULL){ + + Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewLongObj(number = sp_mail_since_cmd(stream))); + Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewLongObj(mail_uid(stream, n))); + + if(stream){ + e = pine_mail_fetchstructure(stream, n, NULL); + + if(sp_flagged(stream, SP_INBOX)) + folder = NULL; + else{ + folder = STREAMNAME(stream); + if(folder[0] == '?' && folder[1] == '\0') + folder = NULL; + } + } + + format_new_mail_msg(folder, number, e, intro, from, subject, subjtext, sizeof(intro)); + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, + "%s%s%s%.80s%.80s", intro, + from ? ((number > 1L) ? " Most recent f" : " F") : "", + from ? "rom " : "", + from ? from : "", + subjtext); + + Tcl_ListObjAppendElement(peED.interp, resObj, Tcl_NewStringObj(tmp_20k_buf,-1)); + + Tcl_ListObjAppendElement(peED.interp, Tcl_GetObjResult(peED.interp), resObj); + } +} + + +/* * * * * * * * * RSS 2.0 Support Routines * * * * * * * * * * * */ + +/* + * PERssCmd - RSS TCL interface + */ +int +PERssCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *s1; + + dprint((2, "PERssCmd")); + + if(objc == 1){ + Tcl_WrongNumArgs(interp, 1, objv, "cmd ?args?"); + return(TCL_ERROR); + } + s1 = Tcl_GetStringFromObj(objv[1], NULL); + + if(s1){ + if(!strcmp(s1, "news")){ + return(peRssReturnFeed(interp, "news", ps_global->VAR_RSS_NEWS)); + } + else if(!strcmp(s1, "weather")){ + return(peRssReturnFeed(interp, "weather", ps_global->VAR_RSS_WEATHER)); + } + } + + Tcl_SetResult(interp, "Unknown PERss command", TCL_STATIC); + return(TCL_ERROR); +} + +/* + * peRssReturnFeed - fetch feed contents and package Tcl response + */ +int +peRssReturnFeed(Tcl_Interp *interp, char *type, char *link) +{ + RSS_FEED_S *feed; + char *errstr = "UNKNOWN"; + + if(link){ + ps_global->c_client_error[0] = '\0'; + + if((feed = peRssFeed(interp, type, link)) != NULL) + return(peRssPackageFeed(interp, feed)); + + if(ps_global->mm_log_error) + errstr = ps_global->c_client_error; + } + else + errstr = "missing setting"; + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s feed fail: %s", type, errstr); + Tcl_SetResult(interp, tmp_20k_buf, TCL_VOLATILE); + return(TCL_ERROR); +} + +/* + * peRssPackageFeed - build a list of feed item elements + * + * LIST ORDER: {title} {link} {description} {image} + */ +int +peRssPackageFeed(Tcl_Interp *interp, RSS_FEED_S *feed) +{ + RSS_ITEM_S *item; + + for(item = feed->items; item; item = item->next) + if(peAppListF(interp, Tcl_GetObjResult(interp), "%s %s %s %s", + (item->title && *item->title)? item->title : "Feed Provided No Title", + item->link ? item->link : "", + item->description ? item->description : "", + feed->image ? feed->image : "") != TCL_OK) + return(TCL_ERROR); + + return(TCL_OK); +} + + +/* + * peRssFeed - return cached feed struct or fetch a new one + */ +RSS_FEED_S * +peRssFeed(Tcl_Interp *interp, char *type, char *link) +{ + int i, cache_l, cp_ref; + time_t now = time(0); + RSS_FEED_S *feed = NULL; + RSS_CACHE_S *cache, *cp; + static RSS_CACHE_S news_cache[RSS_NEWS_CACHE_SIZE], weather_cache[RSS_WEATHER_CACHE_SIZE]; + + if(!strucmp(type,"news")){ + cache = &news_cache[0]; + cache_l = RSS_NEWS_CACHE_SIZE; + } + else{ + cache = &weather_cache[0]; + cache_l = RSS_WEATHER_CACHE_SIZE; + } + + /* search/purge cache */ + for(i = 0; i < cache_l; i++) + if(cache[i].link){ + if(now > cache[i].stale){ + peRssClearCacheEntry(&cache[i]); + } + else if(!strcmp(link, cache[i].link)){ + cache[i].referenced++; + return(cache[i].feed); /* HIT! */ + } + } + + if((feed = peRssFetch(interp, link)) != NULL){ + /* find cache slot, and insert feed into cache */ + for(i = 0, cp_ref = 0; i < cache_l; i++) + if(!cache[i].feed){ + cp = &cache[i]; + break; + } + else if(cache[i].referenced >= cp_ref) + cp = &cache[i]; + + if(!cp) + cp = &cache[0]; /* failsafe */ + + peRssClearCacheEntry(cp); /* make sure */ + + cp->link = cpystr(link); + cp->feed = feed; + cp->referenced = 0; + cp->stale = now + (((feed->ttl > 0) ? feed->ttl : 60) * 60); + } + + return(feed); +} + +/* + * peRssFetch - follow the provided link an return the resulting struct + */ +RSS_FEED_S * +peRssFetch(Tcl_Interp *interp, char *link) +{ + char *scheme = NULL, *loc = NULL, *path = NULL, *parms = NULL, *query = NULL, *frag = NULL; + char *buffer = NULL, *bp, *p, *q; + int ttl = 60; + unsigned long port = 0L, buffer_len = 0L; + time_t theirdate = 0; + STORE_S *feed_so = NULL; + TCPSTREAM *tcp_stream; + + if(link){ + /* grok url */ + rfc1808_tokens(link, &scheme, &loc, &path, &parms, &query, &frag); + if(scheme && loc && path){ + if((p = strchr(loc,':')) != NULL){ + *p++ = '\0'; + while(*p && isdigit((unsigned char) *p)) + port = ((port * 10) + (*p++ - '0')); + + if(*p){ + Tcl_SetResult(interp, "Bad RSS port number", TCL_STATIC); + peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag); + return(NULL); + } + } + + if(scheme && !strucmp(scheme, "feed")){ + fs_give((void **) &scheme); + scheme = cpystr("http"); + } + + mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 5); + tcp_stream = tcp_open (loc, scheme, port | NET_NOOPENTIMEOUT); + mail_parameters(NULL, SET_OPENTIMEOUT, (void *)(long) 30); + + if(tcp_stream != NULL){ + char rev[128]; + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "GET /%s%s%s%s%s HTTP/1.1\r\nHost: %s\r\nAccept: application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nUser-Agent: Web-Alpine/%s (%s %s)\r\n\r\n", + path, parms ? ":" : "", parms ? parms : "", + query ? "?" : "", query ? query : "", loc, + ALPINE_VERSION, SYSTYPE, get_alpine_revision_string(rev, sizeof(rev))); + + mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long) 5); + mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 5); + + if(tcp_sout(tcp_stream, tmp_20k_buf, strlen(tmp_20k_buf))){ + int ok = 0, chunked = FALSE; + + while((p = tcp_getline(tcp_stream)) != NULL){ + if(!ok){ + ok++; + if(strucmp(p,"HTTP/1.1 200 OK")){ + fs_give((void **) &p); + break; /* bail */ + } + } + else if(*p == '\0'){ /* first blank line, start of body */ + if(buffer || feed_so){ + fs_give((void **) &p); + break; /* bail */ + } + + if(buffer_len){ + buffer = fs_get(buffer_len + 16); + if(!tcp_getbuffer(tcp_stream, buffer_len, buffer)) + fs_give((void **) &buffer); + + fs_give((void **) &p); + break; /* bail */ + } + else if((feed_so = so_get(CharStar, NULL, EDIT_ACCESS)) == NULL){ + fs_give((void **) &p); + break; /* bail */ + } + } + else if(feed_so){ /* collect body */ + if(chunked){ + int chunk_len = 0, gotbuf; + + /* first line is chunk size in hex */ + for(q = p; *q && isxdigit((unsigned char) *q); q++) + chunk_len = (chunk_len * 16) + XDIGIT2C(*q); + + if(chunk_len > 0){ /* collect chunk */ + char *tbuf = fs_get(chunk_len + 16); + gotbuf = tcp_getbuffer(tcp_stream, chunk_len, tbuf); + if(gotbuf) + so_nputs(feed_so, tbuf, chunk_len); + + fs_give((void **) &tbuf); + + if(!gotbuf){ + fs_give((void **) &p); + break; /* bail */ + } + } + + /* collect trailing CRLF */ + gotbuf = ((q = tcp_getline(tcp_stream)) != NULL && *q == '\0'); + if(q) + fs_give((void **) &q); + + if(chunk_len == 0 || !gotbuf){ + fs_give((void **) &p); + break; /* bail */ + } + } + else + so_puts(feed_so, p); + } + else{ /* in header, grok fields */ + if(q = strchr(p,':')){ + int l = q - p; + + *q++ = '\0'; + while(isspace((unsigned char ) *q)) + q++; + + /* content-length */ + if(l == 4 && !strucmp(p, "date")){ + theirdate = date_to_local_time_t(q); + } + else if(l == 7 && !strucmp(p, "expires")){ + time_t expires = date_to_local_time_t(q) - ((theirdate > 0) ? theirdate : time(0)); + + if(expires > 0 && expires < (8 * 60 * 60)) + ttl = expires; + } + else if(l == 12 && !strucmp(p, "content-type") + && struncmp(q,"text/xml", 8) + && struncmp(q,"application/xhtml+xml", 21) + && struncmp(q,"application/rss+xml", 19) + && struncmp(q,"application/xml", 15)){ + fs_give((void **) &p); + break; /* bail */ + } + else if(l == 13 && !strucmp(p, "cache-control")){ + if(!struncmp(q,"max-age=",8)){ + int secs = 0; + + for(q += 8; *q && isdigit((unsigned char) *q); q++) + secs = ((secs * 10) + (*q - '0')); + + if(secs > 0) + ttl = secs; + } + } + else if(l == 14 && !strucmp(p,"content-length")){ + while(*q && isdigit((unsigned char) *q)) + buffer_len = ((buffer_len * 10) + (*q++ - '0')); + + if(*q){ + fs_give((void **) &p); + break; /* bail */ + } + } + else if(l == 17 && !strucmp(p, "transfer-encoding")){ + if(!struncmp(q,"chunked", 7)){ + chunked = TRUE; + } + else{ /* unknown encoding */ + fs_give((void **) &p); + break; /* bail */ + } + } + } + } + + fs_give((void **) &p); + } + } + else{ + Tcl_SetResult(interp, "RSS send failure", TCL_STATIC); + peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag); + } + + tcp_close(tcp_stream); + mail_parameters(NULL, SET_READTIMEOUT, (void *)(long) 60); + mail_parameters(NULL, SET_WRITETIMEOUT, (void *)(long) 60); + peRssComponentFree(&scheme,&loc,&path,&parms,&query,&frag); + + if(feed_so){ + buffer = (char *) so_text(feed_so); + buffer_len = (int) so_tell(feed_so); + } + + if(buffer && buffer_len){ + RSS_FEED_S *feed; + char *err; + STORE_S *bucket; + gf_io_t gc, pc; + + /* grok response */ + bucket = so_get(CharStar, NULL, EDIT_ACCESS); + gf_set_readc(&gc, buffer, buffer_len, CharStar, 0); + gf_set_so_writec(&pc, bucket); + gf_filter_init(); + gf_link_filter(gf_html2plain, gf_html2plain_rss_opt(&feed,0)); + if((err = gf_pipe(gc, pc)) != NULL){ + gf_html2plain_rss_free(&feed); + Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC); + } + + so_give(&bucket); + + if(feed_so) + so_give(&feed_so); + else + fs_give((void **) &buffer); + + return(feed); + } + else + Tcl_SetResult(interp, "RSS response error", TCL_STATIC); + } + else + Tcl_SetResult(interp, "RSS connection failure", TCL_STATIC); + } + else + Tcl_SetResult(interp, "RSS feed missing scheme", TCL_STATIC); + } + else + Tcl_SetResult(interp, "No RSS Feed Defined", TCL_STATIC); + + return(NULL); +} + + +void +peRssComponentFree(char **scheme,char **loc,char **path,char **parms,char **query,char **frag) +{ + if(scheme) fs_give((void **) scheme); + if(loc) fs_give((void **) loc); + if(path) fs_give((void **) path); + if(parms) fs_give((void **) parms); + if(query) fs_give((void **) query); + if(frag) fs_give((void **) frag); +} + +void +peRssClearCacheEntry(RSS_CACHE_S *entry) +{ + if(entry){ + if(entry->link) + fs_give((void **) &entry->link); + + gf_html2plain_rss_free(&entry->feed); + memset(entry, 0, sizeof(RSS_CACHE_S)); + } +} diff --git a/web/src/alpined.d/alpined.h b/web/src/alpined.d/alpined.h new file mode 100644 index 00000000..b16fd5bc --- /dev/null +++ b/web/src/alpined.d/alpined.h @@ -0,0 +1,49 @@ +/*----------------------------------------------------------------------- + $Id: alpined.h 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $ + -----------------------------------------------------------------------*/ + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/* + * Various constants + */ +#define WP_MAXSTATUS 1024 + +/* + * Seconds afterwhich we bail on imap connections + */ +#define WP_TCP_TIMEOUT (10 * 60) + +/* + * buf to hold hostname for auth/cert + */ +#define CRED_REQ_SIZE 256 + +/* + * Various external definitions + */ +extern int peNoPassword; +extern int peCredentialError; +extern char peCredentialRequestor[]; +extern int peCertQuery; +extern int peCertFailure; +extern char *peSocketName; +extern STRLIST_S *peCertHosts; + +/* + * Protoypes for various functions + */ + +/* alpined.c */ +void sml_addmsg(int, char *); + diff --git a/web/src/alpined.d/alpineldap.c b/web/src/alpined.d/alpineldap.c new file mode 100644 index 00000000..c29ef7f4 --- /dev/null +++ b/web/src/alpined.d/alpineldap.c @@ -0,0 +1,181 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: alpineldap.c 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" +#include "../../../c-client/imap4r1.h" + +#include "../../../pith/osdep/color.h" /* color support library */ +#include "../../../pith/osdep/canaccess.h" +#include "../../../pith/osdep/temp_nam.h" + +#include "../../../pith/stream.h" +#include "../../../pith/context.h" +#include "../../../pith/state.h" +#include "../../../pith/msgno.h" +#include "../../../pith/debug.h" +#include "../../../pith/init.h" +#include "../../../pith/conf.h" +#include "../../../pith/conftype.h" +#include "../../../pith/detoken.h" +#include "../../../pith/flag.h" +#include "../../../pith/help.h" +#include "../../../pith/remote.h" +#include "../../../pith/status.h" +#include "../../../pith/mailcmd.h" +#include "../../../pith/savetype.h" +#include "../../../pith/save.h" +#include "../../../pith/reply.h" +#include "../../../pith/sort.h" +#include "../../../pith/ldap.h" +#include "../../../pith/addrbook.h" +#include "../../../pith/takeaddr.h" +#include "../../../pith/bldaddr.h" +#include "../../../pith/copyaddr.h" +#include "../../../pith/thread.h" +#include "../../../pith/folder.h" +#include "../../../pith/mailview.h" +#include "../../../pith/indxtype.h" +#include "../../../pith/mailindx.h" +#include "../../../pith/mailpart.h" +#include "../../../pith/mimedesc.h" +#include "../../../pith/detach.h" +#include "../../../pith/newmail.h" +#include "../../../pith/charset.h" +#include "../../../pith/util.h" +#include "../../../pith/rfc2231.h" +#include "../../../pith/string.h" +#include "../../../pith/send.h" + +#include "alpined.h" +#include "ldap.h" + +struct pine *ps_global; /* THE global variable! */ +char tmp_20k_buf[20480]; + +char *peSocketName; + +#ifdef ENABLE_LDAP +WPLDAP_S *wpldap_global; +#endif + +int peNoPassword, peCredentialError; +int peCertQuery, peCertFailure; +char peCredentialRequestor[CRED_REQ_SIZE]; +STRLIST_S *peCertHosts; + +void +sml_addmsg(priority, text) + int priority; + char *text; +{ +} + +void +peDestroyUserContext(pps) + struct pine **pps; +{ +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef ENABLE_LDAP + struct pine *pine_state; + char *p = NULL, *userid = NULL, *domain = NULL, *pname; + struct variable *vars; + int i, usage = 0, rv = 0; + + pine_state = new_pine_struct(); + ps_global = pine_state; + vars = ps_global->vars; + debug = 0; + + for(i = 1 ; i < argc; i++){ + if(*argv[i] == '-'){ + switch (argv[i++][1]) { + case 'p': + p = argv[i]; + break; + case 'u': + userid = argv[i]; + break; + case 'd': + domain = argv[i]; + break; + default: + usage = rv = 1; + break; + } + } + else + usage = rv = 1; + if(usage == 1) break; + } + if(argc == 1) usage = rv = 1; + if (usage == 1 || !p || !userid){ + usage = rv = 1; + goto done; + } + wpldap_global = (WPLDAP_S *)fs_get(sizeof(WPLDAP_S)); + wpldap_global->query_no = 0; + wpldap_global->ldap_search_list = NULL; + + ps_global->pconf = new_pinerc_s(p); + if(ps_global->pconf) + read_pinerc(ps_global->pconf, vars, ParseGlobal); + else { + fprintf(stderr, "Failed to read pineconf\n"); + rv = 1; + goto done; + } + set_current_val(&ps_global->vars[V_LDAP_SERVERS], FALSE, FALSE); + set_current_val(&ps_global->vars[V_USER_DOMAIN], FALSE, FALSE); + if(!ps_global->VAR_USER_DOMAIN && !domain){ + fprintf(stderr, "No domain set in pineconf\n"); + usage = 1; + goto done; + } + if((pname = peLdapPname(userid, domain ? domain : ps_global->VAR_USER_DOMAIN)) != NULL){ + fprintf(stdout, "%s\n", pname); + fs_give((void **)&pname); + } + else + fprintf(stdout, "\n"); + +done: + if(usage) + fprintf(stderr, "usage: pineldap -u userid -p pineconf [-d domain]\n"); + if(wpldap_global){ + if(wpldap_global->ldap_search_list) + free_wpldapres(wpldap_global->ldap_search_list); + fs_give((void **)&wpldap_global); + } + if(ps_global->pconf) + free_pinerc_s(&ps_global->pconf); + free_pine_struct(&pine_state); + + exit(rv); +#else + fprintf(stderr, "%s: Not built with LDAP support\n", argv[0]); + exit(-1); +#endif +} + diff --git a/web/src/alpined.d/busy.c b/web/src/alpined.d/busy.c new file mode 100644 index 00000000..6f10fa7f --- /dev/null +++ b/web/src/alpined.d/busy.c @@ -0,0 +1,49 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: signal.c 91 2006-07-28 19:02:07Z mikes@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../pith/status.h" +#include "../../../pith/busy.h" + + +/* + * Turn on a busy alarm. + */ +int +busy_cue(char *msg, percent_done_t pc_func, int init_msg) +{ + if(msg && !strncmp("Moving", msg, 6)){ + strncpy(msg+1, "Moved", 5); + q_status_message(SM_ORDER, 3, 3, msg+1); + } + + return(0); +} + + +/* + * If final_message was set when busy_cue was called: + * and message_pri = -1 -- no final message queued + * else final message queued with min equal to message_pri + */ +void +cancel_busy_cue(int message_pri) +{ +} + + diff --git a/web/src/alpined.d/color.c b/web/src/alpined.d/color.c new file mode 100644 index 00000000..e8d0af86 --- /dev/null +++ b/web/src/alpined.d/color.c @@ -0,0 +1,678 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: color.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../pith/osdep/color.h" +#include "../../../pith/osdep/collate.h" + + +static COLOR_PAIR *the_rev_color; +static char *_nfcolor, *_nbcolor, *_rfcolor, *_rbcolor; +static char *_last_fg_color, *_last_bg_color; +static int _force_fg_color_change, _force_bg_color_change; + + +/* * * * * * * PITH-REQUIRED COLOR ROUTINES * * * * * * */ + +/* internal prototypes */ +char *alpine_color_name(char *); +int alpine_valid_rgb(char *s); + +int +pico_usingcolor(void) +{ + return(TRUE); +} + + +int +pico_hascolor(void) +{ + return(TRUE); +} + + +/* + * Web Alpine Color Table + */ +static struct color_table { + int number; + char *rgb; + struct { + char *s, + l; + } name; +} webcoltab[] = { + {COL_BLACK, " 0, 0, 0", {"black", 5}}, + {COL_RED, "255, 0, 0", {"red", 3}}, + {COL_GREEN, " 0,255, 0", {"green", 5}}, + {COL_YELLOW, "255,255, 0", {"yellow", 6}}, + {COL_BLUE, " 0, 0,255", {"blue", 4}}, + {COL_MAGENTA, "255, 0,255", {"magenta", 7}}, + {COL_CYAN, " 0,255,255", {"cyan", 4}}, + {COL_WHITE, "255,255,255", {"white", 5}}, + {8, "192,192,192", {"color008", 8}}, /* light gray */ + {9, "128,128,128", {"color009", 8}}, /* gray */ + {10, " 64, 64, 64", {"color010", 8}}, /* dark gray */ + {COL_YELLOW, "255,255, 0", {"color011", 8}}, + {COL_BLUE, " 0, 0,255", {"color012", 8}}, + {COL_MAGENTA, "255, 0,255", {"color013", 8}}, + {COL_CYAN, " 0,255,255", {"color014", 8}}, + {COL_WHITE, "255,255,255", {"color015", 8}}, + {8, "192,192,192", {"colorlgr", 8}}, /* light gray */ + {9, "128,128,128", {"colormgr", 8}}, /* gray */ + {10, " 64, 64, 64", {"colordgr", 8}}, /* dark gray */ + {16, "000,000,000", {"color016", 8}}, + {17, "000,000,095", {"color017", 8}}, + {18, "000,000,135", {"color018", 8}}, + {19, "000,000,175", {"color019", 8}}, + {20, "000,000,215", {"color020", 8}}, + {21, "000,000,255", {"color021", 8}}, + {22, "000,095,000", {"color022", 8}}, + {23, "000,095,095", {"color023", 8}}, + {24, "000,095,135", {"color024", 8}}, + {25, "000,095,175", {"color025", 8}}, + {26, "000,095,215", {"color026", 8}}, + {27, "000,095,255", {"color027", 8}}, + {28, "000,135,000", {"color028", 8}}, + {29, "000,135,095", {"color029", 8}}, + {30, "000,135,135", {"color030", 8}}, + {31, "000,135,175", {"color031", 8}}, + {32, "000,135,215", {"color032", 8}}, + {33, "000,135,255", {"color033", 8}}, + {34, "000,175,000", {"color034", 8}}, + {35, "000,175,095", {"color035", 8}}, + {36, "000,175,135", {"color036", 8}}, + {37, "000,175,175", {"color037", 8}}, + {38, "000,175,215", {"color038", 8}}, + {39, "000,175,255", {"color039", 8}}, + {40, "000,215,000", {"color040", 8}}, + {41, "000,215,095", {"color041", 8}}, + {42, "000,215,135", {"color042", 8}}, + {43, "000,215,175", {"color043", 8}}, + {44, "000,215,215", {"color044", 8}}, + {45, "000,215,255", {"color045", 8}}, + {46, "000,255,000", {"color046", 8}}, + {47, "000,255,095", {"color047", 8}}, + {48, "000,255,135", {"color048", 8}}, + {49, "000,255,175", {"color049", 8}}, + {50, "000,255,215", {"color050", 8}}, + {51, "000,255,255", {"color051", 8}}, + {52, "095,000,000", {"color052", 8}}, + {53, "095,000,095", {"color053", 8}}, + {54, "095,000,135", {"color054", 8}}, + {55, "095,000,175", {"color055", 8}}, + {56, "095,000,215", {"color056", 8}}, + {57, "095,000,255", {"color057", 8}}, + {58, "095,095,000", {"color058", 8}}, + {59, "095,095,095", {"color059", 8}}, + {60, "095,095,135", {"color060", 8}}, + {61, "095,095,175", {"color061", 8}}, + {62, "095,095,215", {"color062", 8}}, + {63, "095,095,255", {"color063", 8}}, + {64, "095,135,000", {"color064", 8}}, + {65, "095,135,095", {"color065", 8}}, + {66, "095,135,135", {"color066", 8}}, + {67, "095,135,175", {"color067", 8}}, + {68, "095,135,215", {"color068", 8}}, + {69, "095,135,255", {"color069", 8}}, + {70, "095,175,000", {"color070", 8}}, + {71, "095,175,095", {"color071", 8}}, + {72, "095,175,135", {"color072", 8}}, + {73, "095,175,175", {"color073", 8}}, + {74, "095,175,215", {"color074", 8}}, + {75, "095,175,255", {"color075", 8}}, + {76, "095,215,000", {"color076", 8}}, + {77, "095,215,095", {"color077", 8}}, + {78, "095,215,135", {"color078", 8}}, + {79, "095,215,175", {"color079", 8}}, + {80, "095,215,215", {"color080", 8}}, + {81, "095,215,255", {"color081", 8}}, + {82, "095,255,000", {"color082", 8}}, + {83, "095,255,095", {"color083", 8}}, + {84, "095,255,135", {"color084", 8}}, + {85, "095,255,175", {"color085", 8}}, + {86, "095,255,215", {"color086", 8}}, + {87, "095,255,255", {"color087", 8}}, + {88, "135,000,000", {"color088", 8}}, + {89, "135,000,095", {"color089", 8}}, + {90, "135,000,135", {"color090", 8}}, + {91, "135,000,175", {"color091", 8}}, + {92, "135,000,215", {"color092", 8}}, + {93, "135,000,255", {"color093", 8}}, + {94, "135,095,000", {"color094", 8}}, + {95, "135,095,095", {"color095", 8}}, + {96, "135,095,135", {"color096", 8}}, + {97, "135,095,175", {"color097", 8}}, + {98, "135,095,215", {"color098", 8}}, + {99, "135,095,255", {"color099", 8}}, + {100, "135,135,000", {"color100", 8}}, + {101, "135,135,095", {"color101", 8}}, + {102, "135,135,135", {"color102", 8}}, + {103, "135,135,175", {"color103", 8}}, + {104, "135,135,215", {"color104", 8}}, + {105, "135,135,255", {"color105", 8}}, + {106, "135,175,000", {"color106", 8}}, + {107, "135,175,095", {"color107", 8}}, + {108, "135,175,135", {"color108", 8}}, + {109, "135,175,175", {"color109", 8}}, + {110, "135,175,215", {"color110", 8}}, + {111, "135,175,255", {"color111", 8}}, + {112, "135,215,000", {"color112", 8}}, + {113, "135,215,095", {"color113", 8}}, + {114, "135,215,135", {"color114", 8}}, + {115, "135,215,175", {"color115", 8}}, + {116, "135,215,215", {"color116", 8}}, + {117, "135,215,255", {"color117", 8}}, + {118, "135,255,000", {"color118", 8}}, + {119, "135,255,095", {"color119", 8}}, + {120, "135,255,135", {"color120", 8}}, + {121, "135,255,175", {"color121", 8}}, + {122, "135,255,215", {"color122", 8}}, + {123, "135,255,255", {"color123", 8}}, + {124, "175,000,000", {"color124", 8}}, + {125, "175,000,095", {"color125", 8}}, + {126, "175,000,135", {"color126", 8}}, + {127, "175,000,175", {"color127", 8}}, + {128, "175,000,215", {"color128", 8}}, + {129, "175,000,255", {"color129", 8}}, + {130, "175,095,000", {"color130", 8}}, + {131, "175,095,095", {"color131", 8}}, + {132, "175,095,135", {"color132", 8}}, + {133, "175,095,175", {"color133", 8}}, + {134, "175,095,215", {"color134", 8}}, + {135, "175,095,255", {"color135", 8}}, + {136, "175,135,000", {"color136", 8}}, + {137, "175,135,095", {"color137", 8}}, + {138, "175,135,135", {"color138", 8}}, + {139, "175,135,175", {"color139", 8}}, + {140, "175,135,215", {"color140", 8}}, + {141, "175,135,255", {"color141", 8}}, + {142, "175,175,000", {"color142", 8}}, + {143, "175,175,095", {"color143", 8}}, + {144, "175,175,135", {"color144", 8}}, + {145, "175,175,175", {"color145", 8}}, + {146, "175,175,215", {"color146", 8}}, + {147, "175,175,255", {"color147", 8}}, + {148, "175,215,000", {"color148", 8}}, + {149, "175,215,095", {"color149", 8}}, + {150, "175,215,135", {"color150", 8}}, + {151, "175,215,175", {"color151", 8}}, + {152, "175,215,215", {"color152", 8}}, + {153, "175,215,255", {"color153", 8}}, + {154, "175,255,000", {"color154", 8}}, + {155, "175,255,095", {"color155", 8}}, + {156, "175,255,135", {"color156", 8}}, + {157, "175,255,175", {"color157", 8}}, + {158, "175,255,215", {"color158", 8}}, + {159, "175,255,255", {"color159", 8}}, + {160, "215,000,000", {"color160", 8}}, + {161, "215,000,095", {"color161", 8}}, + {162, "215,000,135", {"color162", 8}}, + {163, "215,000,175", {"color163", 8}}, + {164, "215,000,215", {"color164", 8}}, + {165, "215,000,255", {"color165", 8}}, + {166, "215,095,000", {"color166", 8}}, + {167, "215,095,095", {"color167", 8}}, + {168, "215,095,135", {"color168", 8}}, + {169, "215,095,175", {"color169", 8}}, + {170, "215,095,215", {"color170", 8}}, + {171, "215,095,255", {"color171", 8}}, + {172, "215,135,000", {"color172", 8}}, + {173, "215,135,095", {"color173", 8}}, + {174, "215,135,135", {"color174", 8}}, + {175, "215,135,175", {"color175", 8}}, + {176, "215,135,215", {"color176", 8}}, + {177, "215,135,255", {"color177", 8}}, + {178, "215,175,000", {"color178", 8}}, + {179, "215,175,095", {"color179", 8}}, + {180, "215,175,135", {"color180", 8}}, + {181, "215,175,175", {"color181", 8}}, + {182, "215,175,215", {"color182", 8}}, + {183, "215,175,255", {"color183", 8}}, + {184, "215,215,000", {"color184", 8}}, + {185, "215,215,095", {"color185", 8}}, + {186, "215,215,135", {"color186", 8}}, + {187, "215,215,175", {"color187", 8}}, + {188, "215,215,215", {"color188", 8}}, + {189, "215,215,255", {"color189", 8}}, + {190, "215,255,000", {"color190", 8}}, + {191, "215,255,095", {"color191", 8}}, + {192, "215,255,135", {"color192", 8}}, + {193, "215,255,175", {"color193", 8}}, + {194, "215,255,215", {"color194", 8}}, + {195, "215,255,255", {"color195", 8}}, + {196, "255,000,000", {"color196", 8}}, + {197, "255,000,095", {"color197", 8}}, + {198, "255,000,135", {"color198", 8}}, + {199, "255,000,175", {"color199", 8}}, + {200, "255,000,215", {"color200", 8}}, + {201, "255,000,255", {"color201", 8}}, + {202, "255,095,000", {"color202", 8}}, + {203, "255,095,095", {"color203", 8}}, + {204, "255,095,135", {"color204", 8}}, + {205, "255,095,175", {"color205", 8}}, + {206, "255,095,215", {"color206", 8}}, + {207, "255,095,255", {"color207", 8}}, + {208, "255,135,000", {"color208", 8}}, + {209, "255,135,095", {"color209", 8}}, + {210, "255,135,135", {"color210", 8}}, + {211, "255,135,175", {"color211", 8}}, + {212, "255,135,215", {"color212", 8}}, + {213, "255,135,255", {"color213", 8}}, + {214, "255,175,000", {"color214", 8}}, + {215, "255,175,095", {"color215", 8}}, + {216, "255,175,135", {"color216", 8}}, + {217, "255,175,175", {"color217", 8}}, + {218, "255,175,215", {"color218", 8}}, + {219, "255,175,255", {"color219", 8}}, + {220, "255,215,000", {"color220", 8}}, + {221, "255,215,095", {"color221", 8}}, + {222, "255,215,135", {"color222", 8}}, + {223, "255,215,175", {"color223", 8}}, + {224, "255,215,215", {"color224", 8}}, + {225, "255,215,255", {"color225", 8}}, + {226, "255,255,000", {"color226", 8}}, + {227, "255,255,095", {"color227", 8}}, + {228, "255,255,135", {"color228", 8}}, + {229, "255,255,175", {"color229", 8}}, + {230, "255,255,215", {"color230", 8}}, + {231, "255,255,255", {"color231", 8}} +}; + + +char * +colorx(int color) +{ + int i; + static char cbuf[12]; + + for(i = 0; i < sizeof(webcoltab) / sizeof(struct color_table); i++) + if(color == webcoltab[i].number) + return(webcoltab[i].rgb); + + sprintf(cbuf, "color%3.3d", color); + return(cbuf); +} + + +/* + * Return a pointer to an rgb string for the input color. The output is 11 + * characters long and looks like rrr,ggg,bbb. + * + * Args colorName -- The color to convert to ascii rgb. + * + * Returns Pointer to a static buffer containing the rgb string. + */ +char * +color_to_asciirgb(char *colorName) +{ + int i; + static char c_to_a_buf[3][RGBLEN+1]; + static int whichbuf = 0; + + whichbuf = (whichbuf + 1) % 3; + + for(i = 0; i < sizeof(webcoltab) / sizeof(struct color_table); i++) + if(!strucmp(webcoltab[i].name.s, colorName)) + return(webcoltab[i].rgb); + + /* + * If we didn't find the color it could be that it is the + * normal color (MATCH_NORM_COLOR) or the none color + * (MATCH_NONE_COLOR). If that is the case, this strncpy thing + * will work out correctly because those two strings are + * RGBLEN long. Otherwise we're in a bit of trouble. This + * most likely means that the user is using the same pinerc on + * two terminals, one with more colors than the other. We didn't + * find a match because this color isn't present on this terminal. + * Since the return value of this function is assumed to be + * RGBLEN long, we'd better make it that long. + * It still won't work correctly because colors will be screwed up, + * but at least the embedded colors in filter.c will get properly + * sucked up when they're encountered. + */ + strncpy(c_to_a_buf[whichbuf], "xxxxxxxxxxx", RGBLEN); /* RGBLEN is 11 */ + i = strlen(colorName); + strncpy(c_to_a_buf[whichbuf], colorName, (i < RGBLEN) ? i : RGBLEN); + c_to_a_buf[whichbuf][RGBLEN] = '\0'; + return(c_to_a_buf[whichbuf]); +} + + + +int +pico_is_good_color(char *s) +{ + return(alpine_color_name(s) != NULL || alpine_valid_rgb(s)); +} + + +int +alpine_valid_rgb(char *s) +{ + int i, j; + + /* has to be three spaces or decimal digits followed by a dot.*/ + + for(i = 0; i < 3; i++){ + int n = 0; + + for(j = 0; j < 3; j++, s++) { + if(*s == ' '){ + if(n) + return(FALSE); + } + else if(isdigit((unsigned char) *s)){ + n = (n * 10) + (*s - '0'); + } + else + return(FALSE); + } + + if (i < 2 && *s++ != ',') + return(FALSE); + } + + return (TRUE); +} + + + +char * +alpine_color_name(char *s) +{ + if(s){ + int i; + + if(!struncmp(s, MATCH_NORM_COLOR, RGBLEN) || !struncmp(s, MATCH_NONE_COLOR, RGBLEN)) + return(s); + else if(*s == ' ' || isdigit(*s)){ + /* check for rgb string instead of name */ + for(i = 0; i < sizeof(webcoltab) / sizeof(struct color_table); i++) + if(!strncmp(webcoltab[i].rgb, s, RGBLEN)) + return(webcoltab[i].name.s); + } + else{ + for(i = 0; i < sizeof(webcoltab) / sizeof(struct color_table); i++) + if(!struncmp(webcoltab[i].name.s, s, webcoltab[i].name.l)) + return(webcoltab[i].name.s); + } + } + + return(NULL); +} + + +/* + * Sets color to (fg,bg). + * Flags == PSC_NONE No alternate default if fg,bg fails. + * == PSC_NORM Set it to Normal color on failure. + * == PSC_REV Set it to Reverse color on failure. + * + * If flag PSC_RET is set, returns an allocated copy of the previous + * color pair, otherwise returns NULL. + */ +COLOR_PAIR * +pico_set_colors(char *fg, char *bg, int flags) +{ + int uc; + COLOR_PAIR *cp = NULL, *rev = NULL; + + if(flags & PSC_RET) + cp = pico_get_cur_color(); + + if(!((uc = pico_usingcolor()) + && fg && bg + && pico_set_fg_color(fg) && pico_set_bg_color(bg))){ + + if(uc && flags & PSC_NORM){ + pico_set_normal_color(); + } + else if(flags & PSC_REV){ + if((rev = pico_get_rev_color()) != NULL){ + pico_set_fg_color(rev->fg); /* these will succeed */ + pico_set_bg_color(rev->bg); + } + } + } + + return(cp); +} + + + +void +pico_nfcolor(char *s) +{ + if(_nfcolor){ + free(_nfcolor); + _nfcolor = NULL; + } + + if(s){ + _nfcolor = (char *)malloc(strlen(s)+1); + if(_nfcolor) + strcpy(_nfcolor, s); + } +} + + +void +pico_nbcolor(char *s) +{ + if(_nbcolor){ + free(_nbcolor); + _nbcolor = NULL; + } + + if(s){ + _nbcolor = (char *)malloc(strlen(s)+1); + if(_nbcolor) + strcpy(_nbcolor, s); + } +} + +void +pico_rfcolor(char *s) +{ + if(_rfcolor){ + free(_rfcolor); + _rfcolor = NULL; + } + + if(s){ + _rfcolor = (char *)malloc(strlen(s)+1); + if(_rfcolor) + strcpy(_rfcolor, s); + + if(the_rev_color) + strcpy(the_rev_color->fg, _rfcolor); + } + else if(the_rev_color) + free_color_pair(&the_rev_color); +} + +void +pico_rbcolor(char *s) +{ + if(_rbcolor){ + free(_rbcolor); + _rbcolor = NULL; + } + + if(s){ + _rbcolor = (char *)malloc(strlen(s)+1); + if(_rbcolor) + strcpy(_rbcolor, s); + + if(the_rev_color) + strcpy(the_rev_color->bg, _rbcolor); + } + else if(the_rev_color) + free_color_pair(&the_rev_color); +} + + +void +pico_endcolor(void) +{ + if(_nfcolor){ + free(_nfcolor); + _nfcolor = NULL; + } + + if(_nbcolor){ + free(_nbcolor); + _nbcolor = NULL; + } + + if(_rfcolor){ + free(_rfcolor); + _rfcolor = NULL; + } + + if(_rbcolor){ + free(_rbcolor); + _rbcolor = NULL; + } + + if(the_rev_color) + free_color_pair(&the_rev_color); +} + + +COLOR_PAIR * +pico_get_cur_color(void) +{ + return(new_color_pair(_last_fg_color, _last_bg_color)); +} + +/* + * If inverse is a color, returns a pointer to that color. + * If not, returns NULL. + * + * NOTE: Don't free this! + */ +COLOR_PAIR * +pico_get_rev_color(void) +{ + if(pico_usingcolor() && _rfcolor && _rbcolor && + pico_is_good_color(_rfcolor) && pico_is_good_color(_rbcolor)){ + if(!the_rev_color) + the_rev_color = new_color_pair(_rfcolor, _rbcolor); + + return(the_rev_color); + } + else + return(NULL); +} + + +int +pico_set_fg_color(char *s) +{ + if(pico_is_good_color(s)){ + if(!struncmp(s, MATCH_NORM_COLOR, RGBLEN)) + s = _nfcolor; + else if(!struncmp(s, MATCH_NONE_COLOR, RGBLEN)) + return(TRUE); + + /* already set correctly */ + if(!_force_fg_color_change + && _last_fg_color + && !strcmp(_last_fg_color, s)) + return(TRUE); + + _force_fg_color_change = 0; + if(_last_fg_color) + free(_last_fg_color); + + if((_last_fg_color = (char *) malloc(strlen(s) + 1)) != NULL) + strcpy(_last_fg_color, s); + + return(TRUE); + } + + return(FALSE); +} + + +int +pico_set_bg_color(char *s) +{ + if(pico_is_good_color(s)){ + if(!struncmp(s, MATCH_NORM_COLOR, RGBLEN)) + s = _nbcolor; + else if(!struncmp(s, MATCH_NONE_COLOR, RGBLEN)) + return(TRUE); + + /* already set correctly */ + if(!_force_bg_color_change + && _last_bg_color + && !strcmp(_last_bg_color, s)) + return(TRUE); + + _force_bg_color_change = 0; + if(_last_bg_color) + free(_last_bg_color); + + if((_last_bg_color = (char *) malloc(strlen(s) + 1)) != NULL) + strcpy(_last_bg_color, s); + + return(TRUE); + } + + return(FALSE); +} + + +void +pico_set_normal_color(void) +{ + if(!_nfcolor || !_nbcolor || + !pico_set_fg_color(_nfcolor) || !pico_set_bg_color(_nbcolor)){ + (void)pico_set_fg_color(DEFAULT_NORM_FORE_RGB); + (void)pico_set_bg_color(DEFAULT_NORM_BACK_RGB); + } +} + + +char * +pico_get_last_fg_color(void) +{ + char *ret = NULL; + + if(_last_fg_color) + if((ret = (char *)malloc(strlen(_last_fg_color)+1)) != NULL) + strcpy(ret, _last_fg_color); + + return(ret); +} + +char * +pico_get_last_bg_color(void) +{ + char *ret = NULL; + + if(_last_bg_color) + if((ret = (char *)malloc(strlen(_last_bg_color)+1)) != NULL) + strcpy(ret, _last_bg_color); + + return(ret); +} diff --git a/web/src/alpined.d/color.h b/web/src/alpined.d/color.h new file mode 100644 index 00000000..3040ffbc --- /dev/null +++ b/web/src/alpined.d/color.h @@ -0,0 +1,25 @@ +/*----------------------------------------------------------------------- + $Id: color.h 764 2007-10-23 23:44:49Z hubert@u.washington.edu $ + -----------------------------------------------------------------------*/ + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WEB_ALPINE_COLOR_INCLUDED +#define _WEB_ALPINE_COLOR_INCLUDED + +void pico_endcolor(void); + +#endif /* _WEB_ALPINE_COLOR_INCLUDED */ + + + diff --git a/web/src/alpined.d/debug.c b/web/src/alpined.d/debug.c new file mode 100644 index 00000000..d3c4d2b7 --- /dev/null +++ b/web/src/alpined.d/debug.c @@ -0,0 +1,151 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: wimap.c 73 2006-06-13 16:46:59Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/*====================================================================== + debug.c + Provide debug support routines + ====*/ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/state.h" +#include "../../../pith/debug.h" + +#include "debug.h" + + +#define MAX_DEBUG_FMT 1024 + + +#ifndef DEBUG +/* + * Preserve debug for syslog trace + */ +int debug; +#endif + + +void +debug_init(void) +{ +#if HAVE_SYSLOG + openlog("alpined", LOG_PID, LOG_MAIL); +#endif +} + + +void +output_debug_msg(int dlevel, char *fmt, ...) +{ + /* always write SYSDBG */ + if((dlevel & SYSDBG) || dlevel <= debug){ +#if HAVE_SYSLOG + va_list args; + char fmt2[MAX_DEBUG_FMT], *p, *q, *trailing = NULL; + int priority = LOG_DEBUG, leading = 1; + + /* whack nl's */ + for(p = fmt, q = fmt2; *p && p - fmt < MAX_DEBUG_FMT - 2; p++){ + if(*p == '\n'){ + if(!leading && !trailing) + trailing = q; + } + else{ + leading = 0; + if(trailing){ + *q++ = '_'; + trailing = NULL; + } + + *q++ = *p; + } + } + + *q = '\0'; + if(trailing) + *trailing = '\0'; + + if(dlevel & SYSDBG) + switch(dlevel){ + case SYSDBG_ALERT : priority = LOG_ALERT; break; + case SYSDBG_ERR : priority = LOG_ERR; break; + case SYSDBG_INFO : priority = LOG_INFO; break; + default : priority = LOG_DEBUG; break; + } + + + va_start(args, fmt); + vsyslog(priority, fmt2, args); + va_end(args); +#else +# error Write something to record error/debugging output +#endif + } +} + +#ifdef DEBUG + +void +dump_configuration(int brief) +{ + dprint((8, "asked to dump_configuration")); +} + + +void +dump_contexts(void) +{ + dprint((8, "asked to dump_contexts")); +} + + +void +setup_imap_debug(void) +{ + int olddebug; + + olddebug = debug; + + if(debug > 7) + ps_global->debug_imap = 4; + else if(debug > 6) + ps_global->debug_imap = 3; + else if(debug > 4) + ps_global->debug_imap = 2; + else if(debug > 2) + ps_global->debug_imap = 1; + else + ps_global->debug_imap = 0; + + if(ps_global->mail_stream){ + if(ps_global->debug_imap > 0){ + mail_debug(ps_global->mail_stream); + } + else{ + mail_nodebug(ps_global->mail_stream); + } + } + + if(debug > 7 && olddebug <= 7) + mail_parameters(NULL, SET_TCPDEBUG, (void *) TRUE); + else if(debug <= 7 && olddebug > 7 && !ps_global->debugmem) + mail_parameters(NULL, SET_TCPDEBUG, (void *) FALSE); + +} +#endif /* DEBUG */ diff --git a/web/src/alpined.d/debug.h b/web/src/alpined.d/debug.h new file mode 100644 index 00000000..9a44ba81 --- /dev/null +++ b/web/src/alpined.d/debug.h @@ -0,0 +1,52 @@ +/*----------------------------------------------------------------------- + $Id: debug.h 130 2006-09-22 04:39:36Z mikes@u.washington.edu $ + -----------------------------------------------------------------------*/ + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WEB_ALPINE_DEBUG_INCLUDED +#define _WEB_ALPINE_DEBUG_INCLUDED + + +#ifndef DEBUG +/* + * support dprint regardless so we leave at least a few + * footsteps in syslog + */ +#undef dprint +#define dprint(x) { output_debug_msg x ; } + +/* alpined-scoped debugging level */ +extern int debug; + +void output_debug_msg(int, char *fmt, ...); +#endif + + +/* + * Use these to for dprint() debug level arg to force + * debug output (typically to syslog()) + */ +#define SYSDBG 0x8000 +#define SYSDBG_ALERT SYSDBG+1 +#define SYSDBG_ERR SYSDBG+2 +#define SYSDBG_INFO SYSDBG+3 +#define SYSDBG_DEBUG SYSDBG+4 + + +/* exported prototypes */ +void debug_init(void); +void setup_imap_debug(void); + + +#endif /* _WEB_ALPINE_DEBUG_INCLUDED */ diff --git a/web/src/alpined.d/imap.c b/web/src/alpined.d/imap.c new file mode 100644 index 00000000..6872d085 --- /dev/null +++ b/web/src/alpined.d/imap.c @@ -0,0 +1,516 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: imap.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/*====================================================================== + imap.c + The call back routines for the c-client/imap + - handles error messages and other notification + - handles prelimirary notification of new mail and expunged mail + - prompting for imap server login and password + + ====*/ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/state.h" +#include "../../../pith/debug.h" +#include "../../../pith/string.h" +#include "../../../pith/flag.h" +#include "../../../pith/imap.h" +#include "../../../pith/status.h" +#include "../../../pith/osdep/collate.h" + +#include "debug.h" +#include "alpined.h" + + + +/* + * Internal prototypes + */ +long imap_seq_exec(MAILSTREAM *, char *,long (*)(MAILSTREAM *, long, void *), void *); +long imap_seq_exec_append(MAILSTREAM *, long, void *); + + +/* + * Exported globals setup by searching functions to tell mm_searched + * where to put message numbers that matched the search criteria, + * and to allow mm_searched to return number of matches. + */ +MAILSTREAM *mm_search_stream; + +MM_LIST_S *mm_list_info; + + + +/*---------------------------------------------------------------------- + Queue imap log message for display in the message line + + Args: string -- The message + errflg -- flag set to 1 if pertains to an error + + Result: Message queued for display + + The c-client/imap reports most of it's status and errors here + ---*/ +void +mm_log(char *string, long errflg) +{ + char message[300]; + char *occurance; + int was_capitalized; + time_t now; + struct tm *tm_now; + + if(errflg == ERROR){ + dprint((SYSDBG_ERR, "%.*s (%ld)", 128, string, errflg)); + } + + now = time((time_t *)0); + tm_now = localtime(&now); + + dprint((ps_global->debug_imap ? 0 : (errflg == ERROR ? 1 : 2), + "IMAP %2.2d:%2.2d:%2.2d %d/%d mm_log %s: %s\n", + tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, tm_now->tm_mon+1, + tm_now->tm_mday, + (errflg == ERROR) + ? "ERROR" + : (errflg == WARN) + ? "warn" + : (errflg == PARSE) + ? "parse" + : "babble", + string)); + + if(errflg == ERROR && !strncmp(string, "[TRYCREATE]", 11)){ + ps_global->try_to_create = 1; + return; + } + else if(ps_global->try_to_create + || (sp_dead_stream(ps_global->mail_stream) + && (!strncmp(string, "[CLOSED]", 8) || strstr(string, "No-op")))) + /* + * Don't display if creating new folder OR + * warning about a dead stream ... + */ + return; + + /*---- replace all "mailbox" with "folder" ------*/ + strncpy(message, string, sizeof(message)); + message[sizeof(message) - 1] = '\0'; + occurance = srchstr(message, "mailbox"); + while(occurance) { + if(!*(occurance+7) || isspace((unsigned char)*(occurance+7))){ + was_capitalized = isupper((unsigned char)*occurance); + rplstr(occurance, 7, 7, (errflg == PARSE ? "address" : "folder")); + if(was_capitalized) + *occurance = (errflg == PARSE ? 'A' : 'F'); + } + else + occurance += 7; + + occurance = srchstr(occurance, "mailbox"); + } + + if(errflg == ERROR) + ps_global->mm_log_error = 1; + + if(errflg == PARSE || (errflg == ERROR && ps_global->noshow_error)){ + strncpy(ps_global->c_client_error, message, sizeof(ps_global->c_client_error)); + ps_global->c_client_error[sizeof(ps_global->c_client_error)-1] = '\0'; + } + + if(ps_global->noshow_error + || (ps_global->noshow_warn && errflg == WARN) + || !(errflg == ERROR || errflg == WARN)) + return; /* Only care about errors; don't print when asked not to */ + + /*---- Display the message ------*/ + q_status_message((errflg == ERROR) ? (SM_ORDER | SM_DING) : SM_ORDER, + 3, 5, message); + if(errflg == ERROR){ + strncpy(ps_global->last_error, message, sizeof(ps_global->last_error)); + ps_global->last_error[sizeof(ps_global->last_error)-1] = '\0'; + } +} + + + +/*---------------------------------------------------------------------- + recieve notification from IMAP + + Args: stream -- Mail stream message is relavant to + string -- The message text + errflag -- Set if it is a serious error + + Result: message displayed in status line + + The facility is for general notices, such as connection to server; + server shutting down etc... It is used infrequently. + ----------------------------------------------------------------------*/ +void +mm_notify(MAILSTREAM *stream, char *string, long errflag) +{ + if(errflag == ERROR){ + dprint((SYSDBG_ERR, "mm_notify: %s (%ld)", string, errflag)); + } + + /* be sure to log the message... */ +#ifdef DEBUG + if(ps_global->debug_imap) + dprint((0, "IMAP mm_notify %s : %s (%s) : %s\n", + (!errflag) ? "NIL" : + (errflag == ERROR) ? "error" : + (errflag == WARN) ? "warning" : + (errflag == BYE) ? "bye" : "unknown", + (stream && stream->mailbox) ? stream->mailbox : "-no folder-", + (stream && stream == sp_inbox_stream()) ? "inboxstream" : + (stream && stream == ps_global->mail_stream) ? "mailstream" : + (stream) ? "abookstream?" : "nostream", + string)); +#endif + + strncpy(ps_global->last_error, string, 500); + ps_global->last_error[499] = '\0'; + + /* + * Then either set special bits in the pine struct or + * display the message if it's tagged as an "ALERT" or + * its errflag > NIL (i.e., WARN, or ERROR) + */ + if(errflag == BYE){ + if(stream == ps_global->mail_stream){ + if(sp_dead_stream(ps_global->mail_stream)) + return; + else + sp_set_dead_stream(ps_global->mail_stream, 1); + } + else if(stream && stream == sp_inbox_stream()){ + if(sp_dead_stream(stream)) + return; + else + sp_set_dead_stream(stream, 1); + } + } + else if(!strncmp(string, "[TRYCREATE]", 11)) + ps_global->try_to_create = 1; + else if(!strncmp(string, "[ALERT]", 7)) + q_status_message2(SM_MODAL, 3, 3, "Alert received while accessing \"%s\": %s", + (stream && stream->mailbox) + ? stream->mailbox : "-no folder-", + rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, string)); + else if(!strncmp(string, "[UNSEEN ", 8)){ + char *p; + long n = 0; + + for(p = string + 8; isdigit(*p); p++) + n = (n * 10) + (*p - '0'); + + sp_set_first_unseen(ps_global->mail_stream, n); + } + else if(!strncmp(string, "[READ-ONLY]", 11) + && !(stream && stream->mailbox && IS_NEWS(stream))) + q_status_message2(SM_ORDER | SM_DING, 3, 3, "%s : %s", + (stream && stream->mailbox) + ? stream->mailbox : "-no folder-", + string + 11); + else if(errflag && (errflag == WARN || errflag == ERROR)) + q_status_message(SM_ORDER | ((errflag == ERROR) ? SM_DING : 0), + 3, 6, ps_global->last_error); +} + + + +/*---------------------------------------------------------------------- + Do work of getting login and password from user for IMAP login + + Args: mb -- The mail box property struct + user -- Buffer to return the user name in + passwd -- Buffer to return the passwd in + trial -- The trial number or number of attempts to login + + Result: username and password passed back to imap + ----*/ +void +mm_login_work(NETMBX *mb, char *user, char *pwd, long trial, char *usethisprompt, char *altuserforcache) +{ + STRLIST_S hostlist[2]; + NETMBX cmb; + int l; + + pwd[0] = '\0'; + + if((l = strlen(mb->orighost)) > 0 && l < CRED_REQ_SIZE) + strcpy(peCredentialRequestor, mb->orighost); + + if(trial){ /* one shot only! */ + user[0] = '\0'; + peCredentialError = 1; + return; + } + +#if 0 + if(ps_global && ps_global->anonymous) { + /*------ Anonymous login mode --------*/ + if(trial < 1) { + strcpy(user, "anonymous"); + sprintf(pwd, "%s@%s", ps_global->VAR_USER_ID, + ps_global->hostname); + } + else + user[0] = pwd[0] = '\0'; + + return; + } +#endif + +#if WEB_REQUIRE_SECURE_IMAP + /* we *require* secure authentication */ + if(!(mb->sslflag || mb->tlsflag) && strcmp("localhost",mb->host)){ + user[0] = pwd[0] = '\0'; + return; + } +#endif + + /* + * heavily paranoid about offering password to server + * that the users hasn't also indicated the remote user + * name + */ + if(*mb->user){ + strcpy(user, mb->user); + } + else if(ps_global->prc + && ps_global->prc->name + && mail_valid_net_parse(ps_global->prc->name,&cmb) + && cmb.user){ + strcpy(user, cmb.user); + } + else{ + /* + * don't blindly offer user/pass + */ + user[0] = pwd[0] = '\0'; + return; + } + + /* + * set up host list for sybil servers... + */ + hostlist[0].name = mb->host; + if(mb->orighost[0] && strucmp(mb->host, mb->orighost)){ + hostlist[0].next = &hostlist[1]; + hostlist[1].name = mb->orighost; + hostlist[1].next = NULL; + } + else + hostlist[0].next = NULL; + + /* try last working password associated with this host. */ + if(!imap_get_passwd(mm_login_list, pwd, user, hostlist, (mb->sslflag || mb->tlsflag))){ + peNoPassword = 1; + user[0] = pwd[0] = '\0'; + } +} + + + +/*---------------------------------------------------------------------- + Receive notification of an error writing to disk + + Args: stream -- The stream the error occured on + errcode -- The system error code (errno) + serious -- Flag indicating error is serious (mail may be lost) + +Result: If error is non serious, the stream is marked as having an error + and deletes are disallowed until error clears + If error is serious this returns with syslogging if possible + ----*/ +long +mm_diskerror (MAILSTREAM *stream, long errcode, long serious) +{ + if(!serious && stream == ps_global->mail_stream) { + sp_set_io_error_on_stream(ps_global->mail_stream, 1); + } + + dprint((SYSDBG_ERR, "mm_diskerror: mailbox: %s, errcode: %ld, serious: %ld\n", + (stream && stream->mailbox) ? stream->mailbox : "", errcode, serious)); + + return(1); +} + + +/* + * alpine_tcptimeout - C-client callback to handle tcp-related timeouts. + */ +long +alpine_tcptimeout(long elapsed, long sincelast) +{ + long rv = 1L; /* keep trying by default */ + + dprint((SYSDBG_INFO, "tcptimeout: waited %s seconds\n", long2string(elapsed))); + + if(elapsed > WP_TCP_TIMEOUT){ + dprint((SYSDBG_ERR, "tcptimeout: BAIL after %s seconds\n", long2string(elapsed))); + rv = 0L; + } + + return(rv); +} + + +/* + * C-client callback to handle SSL/TLS certificate validation failures + * + * Returning 0 means error becomes fatal + * Non-zero means certificate problem is ignored and SSL session is + * established + * + * We remember the answer and won't re-ask for subsequent open attempts to + * the same hostname. + */ +long +alpine_sslcertquery(char *reason, char *host, char *cert) +{ + static char buf[256]; + STRLIST_S *p; + + for(p = peCertHosts; p; p = p->next) + if(!strucmp(p->name, host)) + return(1); + + peCertQuery = 1; + snprintf(peCredentialRequestor, CRED_REQ_SIZE, "%s++%s", host ? host : "?", reason ? reason : "UNKNOWN"); + q_status_message(SM_ORDER, 0, 3, "SSL Certificate Problem"); + dprint((SYSDBG_INFO, "sslcertificatequery: host=%s reason=%s cert=%s\n", + host ? host : "?", reason ? reason : "?", + cert ? cert : "?")); + return(0); +} + + +/* + * C-client callback to handle SSL/TLS certificate validation failures + */ +void +alpine_sslfailure(char *host, char *reason, unsigned long flags) +{ + peCertFailure = 1; + snprintf(peCredentialRequestor, CRED_REQ_SIZE, "%s++%s", host ? host : "?", reason ? reason : "UNKNOWN"); + q_status_message1(SM_ORDER, 0, 3, "SSL Certificate Failure: %s", reason ? reason : "?"); + dprint((SYSDBG_INFO, "SSL Invalid Cert (%s) : %s", host, reason)); +} + + + +/*---------------------------------------------------------------------- + This can be used to prevent the flickering of the check_cue char + caused by numerous (5000+) fetches by c-client. Right now, the only + practical use found is newsgroup subsciption. + + check_cue_display will check if this global is set, and won't clear + the check_cue_char if set. + ----*/ +void +set_read_predicted(int i) +{ +} + +/*---------------------------------------------------------------------- + Exported method to display status of mail check + + Args: putstr -- should be NO LONGER THAN 2 bytes + + Result: putstr displayed at upper-left-hand corner of screen + ----*/ +void +check_cue_display(char *putstr) +{ +} + + + +void +alpine_set_passwd(char *user, char *passwd, char *host, int altflag) +{ + STRLIST_S hostlist[1]; + + hostlist[0].name = host; + hostlist[0].next = NULL; + + imap_set_passwd(&mm_login_list, passwd, user, hostlist, altflag, 1, 0); +} + + +void +alpine_clear_passwd(char *user, char *host) +{ + MMLOGIN_S **lp, *l; + STRLIST_S hostlist[1]; + + hostlist[0].name = host; + hostlist[0].next = NULL; + + for(lp = &mm_login_list; *lp; lp = &(*lp)->next) + if(imap_same_host((*lp)->hosts, hostlist) + && (!*user || !strcmp(user, (*lp)->user))){ + l = *lp; + *lp = (*lp)->next; + + if(l->user) + fs_give((void **) &l->user); + + free_strlist(&l->hosts); + + if(l->passwd){ + char *p = l->passwd; + + while(*p) + *p++ = '\0'; + } + + fs_give((void **) &l); + + break; + } +} + + +int +alpine_have_passwd(char *user, char *host, int altflag) +{ + STRLIST_S hostlist[1]; + + hostlist[0].name = host; + hostlist[0].next = NULL; + + return(imap_get_passwd(mm_login_list, NULL, user, hostlist, altflag)); +} + + +char * +alpine_get_user(char *host) +{ + STRLIST_S hostlist[1]; + + hostlist[0].name = host; + hostlist[0].next = NULL; + + return(imap_get_user(mm_login_list, hostlist)); +} diff --git a/web/src/alpined.d/imap.h b/web/src/alpined.d/imap.h new file mode 100644 index 00000000..024e1781 --- /dev/null +++ b/web/src/alpined.d/imap.h @@ -0,0 +1,23 @@ +/*----------------------------------------------------------------------- + $Id: imap.h 82 2006-07-12 23:36:59Z mikes@u.washington.edu $ + -----------------------------------------------------------------------*/ + +#ifndef _WEB_ALPINE_IMAP_INCLUDED +#define _WEB_ALPINE_IMAP_INCLUDED + + +#include "../../../pith/imap.h" + + +/* exported protoypes */ +long alpine_tcptimeout(long, long); +long alpine_sslcertquery(char *, char *, char *); +void alpine_sslfailure(char *, char *, unsigned long); +void alpine_set_passwd(char *, char *, char *, int); +void alpine_clear_passwd(char *, char *); +int alpine_have_passwd(char *, char *, int); +char *alpine_get_user(char *, int); + + + +#endif /* _WEB_ALPINE_IMAP_INCLUDED */ diff --git a/web/src/alpined.d/ldap.c b/web/src/alpined.d/ldap.c new file mode 100644 index 00000000..3e6bf99f --- /dev/null +++ b/web/src/alpined.d/ldap.c @@ -0,0 +1,241 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: ldap.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/state.h" +#include "../../../pith/debug.h" +#include "../../../pith/adrbklib.h" +#include "../../../pith/ldap.h" + +#include "ldap.h" + + +#ifdef ENABLE_LDAP + +int +ldap_addr_select(ps, ac, result, style, wp_err, srchstr) + struct pine *ps; + ADDR_CHOOSE_S *ac; + LDAP_CHOOSE_S **result; + LDAPLookupStyle style; + WP_ERR_S *wp_err; + char *srchstr; +{ + LDAP_SERV_RES_S *res_list, *tmp_rl; + LDAPMessage *e, *tmp_e; + char **mail = NULL, *a; + int got_n_entries = 0, retval = -5; + BerElement *ber; + + dprint((7, "ldap_addr_select, srchstr: %s", srchstr)); + for(res_list = ac->res_head; res_list; res_list = res_list->next){ + tmp_rl = res_list; + for(e = ldap_first_entry(res_list->ld, res_list->res); + e != NULL; + e = ldap_next_entry(res_list->ld, e)){ + tmp_e = e; + got_n_entries++; + } + } + if(got_n_entries == 1){ + for(a = ldap_first_attribute(tmp_rl->ld, tmp_e, &ber); + a != NULL; + a = ldap_next_attribute(tmp_rl->ld, tmp_e, ber)){ + if(strcmp(a, tmp_rl->info_used->mailattr) == 0){ + mail = ldap_get_values(tmp_rl->ld, tmp_e, a); + break; + } + } + if(mail && mail[0] && mail[0][0]){ + retval = 0; + if(result){ + (*result) = + (LDAP_CHOOSE_S *)fs_get(sizeof(LDAP_CHOOSE_S)); + (*result)->ld = tmp_rl->ld; + (*result)->selected_entry = tmp_e; + (*result)->info_used = tmp_rl->info_used; + (*result)->serv = tmp_rl->serv; + } + } + else{ + retval = -2; + } + } + else + retval = -3; + + return(retval); +} + + +char * +peLdapPname(mailbox, host) + char *mailbox; + char *host; +{ + char *retstr = NULL; + char adrstr[1024], **cn; + int ecnt; + CUSTOM_FILT_S *filter; + WP_ERR_S wp_err; + LDAP_CHOOSE_S *winning_e = NULL; + LDAP_SERV_RES_S *results = NULL; + LDAP_SERV_RES_S *trl; + LDAPMessage *e; + + sprintf(adrstr, "(mail=%.500s@%.500s)", mailbox, host); + filter = (CUSTOM_FILT_S *)fs_get(sizeof(CUSTOM_FILT_S)); + filter->filt = cpystr(adrstr); + filter->combine = 0; + memset(&wp_err, 0, sizeof(wp_err)); + wpldap_global->query_no++; + if(wpldap_global->ldap_search_list){ + wpldap_global->ldap_search_list = + free_wpldapres(wpldap_global->ldap_search_list); + } + ldap_lookup_all("", 0, 0, AlwaysDisplay, filter, &winning_e, + &wp_err, &results); + if(filter){ + fs_give((void **)&filter->filt); + fs_give((void **)&filter); + } + if(wpldap_global->ldap_search_list){ + trl = wpldap_global->ldap_search_list->reslist; + for(ecnt = 0, e = ldap_first_entry(trl->ld, trl->res); + e != NULL; e = ldap_next_entry(trl->ld, e), ecnt++); + if(ecnt == 1) { /* found the one true name */ + e = ldap_first_entry(trl->ld, trl->res); + peLdapEntryParse(trl, e, &cn, NULL, NULL, NULL, + NULL, NULL); + if(cn){ + retstr = cpystr(cn[0]); + ldap_value_free(cn); + } + } + } + return(retstr); +} + +int +peLdapEntryParse(trl, e, ret_cn, ret_org, ret_unit, + ret_title, ret_mail, ret_sn) + LDAP_SERV_RES_S *trl; + LDAPMessage *e; + char ***ret_cn; + char ***ret_org; + char ***ret_unit; + char ***ret_title; + char ***ret_mail; + char ***ret_sn; +{ + char *a, **cn, **org, **unit, **title, **mail, **sn; + BerElement *ber; + + cn = org = title = unit = mail = sn = NULL; + + for(a = ldap_first_attribute(trl->ld, e, &ber); + a != NULL; + a = ldap_next_attribute(trl->ld, e, ber)){ + dprint((9, " %s", a)); + if(strcmp(a, trl->info_used->cnattr) == 0){ + if(!cn) + cn = ldap_get_values(trl->ld, e, a); + + if(cn && !(cn[0] && cn[0][0])){ + ldap_value_free(cn); + cn = NULL; + } + } + else if(strcmp(a, trl->info_used->mailattr) == 0){ + if(!mail) + mail = ldap_get_values(trl->ld, e, a); + } + else if(strcmp(a, "o") == 0){ + if(!org) + org = ldap_get_values(trl->ld, e, a); + } + else if(strcmp(a, "ou") == 0){ + if(!unit) + unit = ldap_get_values(trl->ld, e, a); + } + else if(strcmp(a, "title") == 0){ + if(!title) + title = ldap_get_values(trl->ld, e, a); + } + + our_ldap_memfree(a); + } + + if(!cn){ + for(a = ldap_first_attribute(trl->ld, e, &ber); + a != NULL; + a = ldap_next_attribute(trl->ld, e, ber)){ + + if(strcmp(a, trl->info_used->snattr) == 0){ + if(!sn) + sn = ldap_get_values(trl->ld, e, a); + + if(sn && !(sn[0] && sn[0][0])){ + ldap_value_free(sn); + sn = NULL; + } + } + our_ldap_memfree(a); + } + } + if(ret_cn) + (*ret_cn) = cn; + else if(cn) ldap_value_free(cn); + if(ret_org) + (*ret_org) = org; + else if(org) ldap_value_free(org); + if(ret_unit) + (*ret_unit) = unit; + else if(unit) ldap_value_free(unit); + if(ret_title) + (*ret_title) = title; + else if(title) ldap_value_free(title); + if(ret_mail) + (*ret_mail) = mail; + else if(mail) ldap_value_free(mail); + if(ret_sn) + (*ret_sn) = sn; + else if(sn) ldap_value_free(sn); + + return 0; +} + +WPLDAPRES_S * +free_wpldapres(wpldapr) + WPLDAPRES_S *wpldapr; +{ + WPLDAPRES_S *tmp1, *tmp2; + + for(tmp1 = wpldapr; tmp1; tmp1 = tmp2){ + tmp2 = tmp1->next; + if(tmp1->str) + fs_give((void **)&tmp1->str); + if(tmp1->reslist) + free_ldap_result_list(&tmp1->reslist); + } + fs_give((void **)&wpldapr); + return(NULL); +} +#endif /* ENABLE_LDAP */ diff --git a/web/src/alpined.d/ldap.h b/web/src/alpined.d/ldap.h new file mode 100644 index 00000000..2ada2908 --- /dev/null +++ b/web/src/alpined.d/ldap.h @@ -0,0 +1,48 @@ +/*----------------------------------------------------------------------- + $Id: ldap.h 5 2006-01-04 17:53:54Z hubert $ + -----------------------------------------------------------------------*/ + +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WEB_ALPINE_LDAP_INCLUDED +#define _WEB_ALPINE_LDAP_INCLUDED + + +#ifdef ENABLE_LDAP + +#include "../../../pith/ldap.h" + +typedef struct wpldapres { + char *str; + LDAP_SERV_RES_S *reslist; + struct wpldapres *next; +} WPLDAPRES_S; + +typedef struct wpldap { + int query_no; + WPLDAPRES_S *ldap_search_list; +} WPLDAP_S; + + +extern WPLDAP_S *wpldap_global; + + +char *peLdapPname(char *, char *); +int peLdapEntryParse(LDAP_SERV_RES_S *, LDAPMessage *, + char ***, char ***, char ***, char ***, + char ***, char ***); +WPLDAPRES_S *free_wpldapres(WPLDAPRES_S *); + +#endif /* ENABLE_LDAP */ + +#endif /* _WEB_ALPINE_LDAP_INCLUDED */ diff --git a/web/src/alpined.d/remote.c b/web/src/alpined.d/remote.c new file mode 100644 index 00000000..3269a978 --- /dev/null +++ b/web/src/alpined.d/remote.c @@ -0,0 +1,78 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: remote.c 101 2006-08-10 22:53:04Z mikes@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/remote.h" +#include "../../../pith/msgno.h" +#include "../../../pith/filter.h" +#include "../../../pith/util.h" +#include "../../../pith/debug.h" +#include "../../../pith/osdep/collate.h" + + +/* + * Internal prototypes + */ + +int +rd_prompt_about_forged_remote_data(reason, rd, extra) + int reason; + REMDATA_S *rd; + char *extra; +{ + char tmp[2000]; + char *unknown = "<unknown>"; + char *foldertype, *foldername, *special; + + /* + * Since we're web based the user doesn't have much recourse in the event of one of these + * weird errors, so we just report what happened and forge ahead + */ + + foldertype = (rd && rd->t.i.special_hdr && !strucmp(rd->t.i.special_hdr, REMOTE_ABOOK_SUBTYPE)) + ? "address book" + : (rd && rd->t.i.special_hdr && !strucmp(rd->t.i.special_hdr, REMOTE_PINERC_SUBTYPE)) + ? "configuration" + : "data"; + foldername = (rd && rd->rn) ? rd->rn : unknown; + special = (rd && rd->t.i.special_hdr) ? rd->t.i.special_hdr : unknown; + + dprint((1, "rd_check_out_forged_remote_data: reason: %d, type: $s, name: %s", + reason, foldertype ? foldertype : "?", foldername ? foldername : "?")); + + if(rd && rd->flags & USER_SAID_NO) + return(-1); + + if(reason == -2){ + snprintf(tmp, sizeof(tmp), _("Missing \"%s\" header in remote pinerc"), special); + tmp[sizeof(tmp)-1] = '\0'; + } + else if(reason == -1){ + snprintf(tmp, sizeof(tmp), _("Unexpected \"Received\" header in remote pinerc")); + tmp[sizeof(tmp)-1] = '\0'; + } + else if(reason >= 0){ + snprintf(tmp, sizeof(tmp), _("Unexpected value \"%s: %s\" in remote pinerc"), special, (extra && *extra) ? extra : "?"); + tmp[sizeof(tmp)-1] = '\0'; + } + + rd->flags |= USER_SAID_YES; + return(1); +} diff --git a/web/src/alpined.d/signal.c b/web/src/alpined.d/signal.c new file mode 100644 index 00000000..3bdb7b41 --- /dev/null +++ b/web/src/alpined.d/signal.c @@ -0,0 +1,280 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: signal.c 91 2006-07-28 19:02:07Z mikes@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/conf.h" +#include "../../../pith/status.h" +#include "../../../pith/signal.h" +#include "../../../pith/debug.h" +#include "../../../pith/adrbklib.h" +#include "../../../pith/remote.h" +#include "../../../pith/imap.h" + +#include "alpined.h" +#include "debug.h" + + +static int cleanup_called_from_sig_handler; + +static RETSIGTYPE hup_signal(int); +static RETSIGTYPE term_signal(int); +static RETSIGTYPE auger_in_signal(int); +int fast_clean_up(); +void end_signals(int); +#if defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2) +static RETSIGTYPE usr1_signal(int); +static RETSIGTYPE usr2_signal(int); +#endif + + +/*---------------------------------------------------------------------- + Install handlers for all the signals we care to catch + ----------------------------------------------------------------------*/ +void +init_signals(void) +{ + /* prepare for unexpected exit */ + signal(SIGHUP, hup_signal); + signal(SIGTERM, term_signal); + + /* prepare for unforseen problems */ + signal(SIGILL, auger_in_signal); + signal(SIGTRAP, auger_in_signal); +#ifdef SIGEMT + signal(SIGEMT, auger_in_signal); +#endif + signal(SIGBUS, auger_in_signal); + signal(SIGSEGV, auger_in_signal); + signal(SIGSYS, auger_in_signal); + +#if defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2) + /* Set up SIGUSR2 to {in,de}crement debug level */ + signal(SIGUSR1, usr1_signal); + signal(SIGUSR2, usr2_signal); +#endif +} + + +/*---------------------------------------------------------------------- + handle hang up signal -- SIGHUP + +Not much to do. Rely on periodic mail file check pointing. + ----------------------------------------------------------------------*/ +static RETSIGTYPE +hup_signal(int sig) +{ + end_signals(1); + cleanup_called_from_sig_handler = 1; + + while(!fast_clean_up()) + sleep(1); + + if(peSocketName) /* clean up unix domain socket */ + (void) unlink(peSocketName); + + exceptional_exit("SIGHUP received", 0); +} + + +/*---------------------------------------------------------------------- + handle terminate signal -- SIGTERM + +Not much to do. Rely on periodic mail file check pointing. + ----------------------------------------------------------------------*/ +static RETSIGTYPE +term_signal(int sig) +{ + end_signals(1); + cleanup_called_from_sig_handler = 1; + + while(!fast_clean_up()) + sleep(1); + + if(peSocketName) /* clean up unix domain socket */ + (void) unlink(peSocketName); + + exceptional_exit("SIGTERM received", 0); +} + + +/*---------------------------------------------------------------------- + Handle signals caused by aborts -- SIGSEGV, SIGILL, etc + +Call panic which cleans up tty modes and then core dumps + ----------------------------------------------------------------------*/ +static RETSIGTYPE +auger_in_signal(int sig) +{ + end_signals(1); + + if(peSocketName) /* clean up unix domain socket */ + (void) unlink(peSocketName); + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Abort: signal %d", sig); + panic(tmp_20k_buf); /* clean up and get out */ + exit(-1); /* in case panic doesn't kill us */ +} + + +/*---------------------------------------------------------------------- + Handle cleaning up mail streams and tty modes... +Not much to do. Rely on periodic mail file check pointing. Don't try +cleaning up screen or flushing output since stdout is likely already +gone. To be safe, though, we'll at least restore the original tty mode. +Also delete any remnant _DATAFILE_ from sending-filters. + ----------------------------------------------------------------------*/ +int +fast_clean_up(void) +{ + int i; + MAILSTREAM *m; + + if(ps_global->expunge_in_progress) + return(0); + + /* + * This gets rid of temporary cache files for remote addrbooks. + */ + completely_done_with_adrbks(); + + /* + * This flushes out deferred changes and gets rid of temporary cache + * files for remote config files. + */ + if(ps_global->prc){ + if(ps_global->prc->outstanding_pinerc_changes) + write_pinerc(ps_global, Main, + cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE); + + if(ps_global->prc->rd) + rd_close_remdata(&ps_global->prc->rd); + + free_pinerc_s(&ps_global->prc); + } + + /* as does this */ + if(ps_global->post_prc){ + if(ps_global->post_prc->outstanding_pinerc_changes) + write_pinerc(ps_global, Post, + cleanup_called_from_sig_handler ? WRP_NOUSER : WRP_NONE); + + if(ps_global->post_prc->rd) + rd_close_remdata(&ps_global->post_prc->rd); + + free_pinerc_s(&ps_global->post_prc); + } + + /* + * Can't figure out why this section is inside the ifdef, but no + * harm leaving it that way, I guess. + */ +#if !defined(DOS) && !defined(OS2) + for(i = 0; i < ps_global->s_pool.nstream; i++){ + m = ps_global->s_pool.streams[i]; + if(m && !m->lock) + pine_mail_actually_close(m); + } +#endif /* !DOS */ + + imap_flush_passwd_cache(TRUE); + + if(peSocketName) /* clean up unix domain socket */ + (void) unlink(peSocketName); + + dprint((1, "done with fast_clean_up\n")); + return(1); +} + + + +/*---------------------------------------------------------------------- + Return all signal handling back to normal + ----------------------------------------------------------------------*/ +void +end_signals(int blockem) +{ +#ifndef SIG_ERR +#define SIG_ERR (RETSIGTYPE (*)())-1 +#endif + if(signal(SIGILL, blockem ? SIG_IGN : SIG_DFL) != SIG_ERR){ + signal(SIGTRAP, blockem ? SIG_IGN : SIG_DFL); +#ifdef SIGEMT + signal(SIGEMT, blockem ? SIG_IGN : SIG_DFL); +#endif + signal(SIGBUS, blockem ? SIG_IGN : SIG_DFL); + signal(SIGSEGV, blockem ? SIG_IGN : SIG_DFL); + signal(SIGSYS, blockem ? SIG_IGN : SIG_DFL); + signal(SIGHUP, blockem ? SIG_IGN : SIG_DFL); + signal(SIGTERM, blockem ? SIG_IGN : SIG_DFL); + signal(SIGINT, blockem ? SIG_IGN : SIG_DFL); + } +} + + +#if defined(DEBUG) && defined(SIGUSR1) && defined(SIGUSR2) +/*---------------------------------------------------------------------- + handle -- SIGUSR1 + + Increment debug level + ----------------------------------------------------------------------*/ +static RETSIGTYPE +usr1_signal(int sig) +{ + if(debug < 11) + debug++; + + setup_imap_debug(); + + dprint((SYSDBG_INFO, "Debug level now %d", debug)); +} + +/*---------------------------------------------------------------------- + handle -- SIGUSR2 + + Decrement debug level + ----------------------------------------------------------------------*/ +static RETSIGTYPE +usr2_signal(int sig) +{ + if(debug > 0) + debug--; + + setup_imap_debug(); + + dprint((SYSDBG_INFO, "Debug level now %d", debug)); + +} +#endif + + +/* + * Command interrupt support. + */ +int +intr_handling_on(void) +{ + return 0; +} + + +void +intr_handling_off(void) +{ +} diff --git a/web/src/alpined.d/signal.h b/web/src/alpined.d/signal.h new file mode 100644 index 00000000..3ae6bd50 --- /dev/null +++ b/web/src/alpined.d/signal.h @@ -0,0 +1,15 @@ +/*----------------------------------------------------------------------- + $Id: signal.h 82 2006-07-12 23:36:59Z mikes@u.washington.edu $ + -----------------------------------------------------------------------*/ + +#ifndef _WEB_ALPINE_SIGNAL_INCLUDED +#define _WEB_ALPINE_SIGNAL_INCLUDED + + +/* exported protoypes */ +void init_signals(void); + + + + +#endif /* _WEB_ALPINE_SIGNAL_INCLUDED */ diff --git a/web/src/alpined.d/status.c b/web/src/alpined.d/status.c new file mode 100644 index 00000000..3c546d6f --- /dev/null +++ b/web/src/alpined.d/status.c @@ -0,0 +1,78 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: status.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +/*====================================================================== + status.c + Functions that manage the status line (third from the bottom) + - put messages on the queue to be displayed + - display messages on the queue with timers + - check queue to figure out next timeout + - prompt for yes/no type of questions + ====*/ + +#include <system.h> +#include <general.h> + +#include "../../../pith/status.h" +#include "../../../pith/helptext.h" +#include "../../../pith/debug.h" +#include "../../../pith/string.h" + +#include "alpined.h" + + + + +/*---------------------------------------------------------------------- + Put a message for the status line on the queue + ----------*/ +void +q_status_message(int flags, int min_time, int max_time, char *message) +{ + if(!(flags & SM_INFO)) + sml_addmsg(0, message); +} + + +/*---------------------------------------------------------------------- + Time remaining for current message's minimum display + ----*/ +int +status_message_remaining(void) +{ + return(0); +} + + + +/*---------------------------------------------------------------------- + Update status line, clearing or displaying a message +----------------------------------------------------------------------*/ +int +display_message(UCS command) +{ + return(0); +} + + + +/*---------------------------------------------------------------------- + Display all the messages on the queue as quickly as possible + ----*/ +void +flush_status_messages(int skip_last_pause) +{ +} diff --git a/web/src/alpined.d/stubs.c b/web/src/alpined.d/stubs.c new file mode 100644 index 00000000..299c7c81 --- /dev/null +++ b/web/src/alpined.d/stubs.c @@ -0,0 +1,169 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: stubs.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../../../c-client/c-client.h" + +#include "../../../pith/takeaddr.h" +#include "../../../pith/ldap.h" +#include "../../../pith/debug.h" +#include "../../../pith/osdep/coredump.h" + +#include "alpined.h" + + +/* let cleanup calls know we're screwed */ +static int in_panic = 0; + +/* input timeout */ +static int input_timeout = 0; + +/* time of last user-initiated newmail check */ +static time_t time_of_input; + + +void +peMarkInputTime(void) +{ + time_of_input = time((time_t *)0); +} + + +/********* ../../../pith/newmail.c stub **********/ +time_t +time_of_last_input() +{ + return(time_of_input); +} + + +/********* ../../../pith/conf.c stub **********/ +int +set_input_timeout(t) + int t; +{ + int old_t = input_timeout; + + input_timeout = t; + return(old_t); +} + + +int +get_input_timeout() +{ + return(input_timeout); +} + + +int +unexpected_pinerc_change() +{ + dprint((1, "Unexpected pinerc change")); + return(0); /* always overwrite */ +} + +/********* ../../../pith/mailcap.c stub **********/ +int +exec_mailcap_test_cmd(cmd) + char *cmd; +{ + return(-1); /* never succeeds on web server */ +} + + +/****** various other stuff ******/ +/*---------------------------------------------------------------------- + panic - call on detected programmatic errors to exit pine + + Args: message -- message to record in debug file and to be printed for user + + Result: The various tty modes are restored + If debugging is active a core dump will be generated + Exits Pine + + This is also called from imap routines and fs_get and fs_resize. + ----*/ +void +panic(message) + char *message; +{ + in_panic = 1; + + syslog(LOG_ERR, message); /* may not work, but try */ + +#if 0 + if(ps_global) + peDestroyUserContext(&ps_global); +#endif + +#ifdef DEBUG + if(debug > 1) + coredump(); /*--- If we're debugging get a core dump --*/ +#endif + + exit(-1); + fatal("ffo"); /* BUG -- hack to get fatal out of library in right order*/ +} + + +/*---------------------------------------------------------------------- + panicking - called to test whether we're sunk + + Args: none + + ----*/ +int +panicking() +{ + return(in_panic); +} + + +/*---------------------------------------------------------------------- + exceptional_exit - called to exit under unusual conditions (with no core) + + Args: message -- message to record in debug file and to be printed for user + ev -- exit value + + ----*/ +void +exceptional_exit(message, ev) + char *message; + int ev; +{ + syslog(LOG_ALERT, message); + exit(ev); +} + + +/*---------------------------------------------------------------------- + write argument error to the display... + + Args: none + + Result: prints help messages + ----------------------------------------------------------------------*/ +void +display_args_err(s, a, err) + char *s; + char **a; + int err; +{ + syslog(LOG_INFO, "Arg Error: %s", s); +} diff --git a/web/src/alpined.d/stubs.h b/web/src/alpined.d/stubs.h new file mode 100644 index 00000000..8128a4aa --- /dev/null +++ b/web/src/alpined.d/stubs.h @@ -0,0 +1,25 @@ +/*----------------------------------------------------------------------- + $Id: stubs.h 130 2006-09-22 04:39:36Z mikes@u.washington.edu $ + -----------------------------------------------------------------------*/ + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WEB_ALPINE_STUBS_INCLUDED +#define _WEB_ALPINE_STUBS_INCLUDED + + +/* exported prototypes */ +void peMarkInputTime(void); + + +#endif /* _WEB_ALPINE_STUBS_INCLUDED */ diff --git a/web/src/alpined.d/wpcomm.c b/web/src/alpined.d/wpcomm.c new file mode 100644 index 00000000..b9f17073 --- /dev/null +++ b/web/src/alpined.d/wpcomm.c @@ -0,0 +1,197 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: wpcomm.c 1266 2009-07-14 18:39:12Z hubert@u.washington.edu $"; +#endif + +/* ======================================================================== + * Copyright 2006-2007 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +#include <string.h> +#include <tcl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + + +#define VERSION "0.1" + +#define READBUF 4096 +#define RESULT_MAX 16 + +int append_rbuf(char *, char *, int); +int WPSendCmd(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []); + + +/* + * WPComm_Init - entry point for Web Alpine servlet communications. + * + * returns: TCL defined values for success or failure + * + */ + +int +Wpcomm_Init(Tcl_Interp *interp) +{ + if(Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL + && TCL_VERSION[0] == '7' + && Tcl_PkgRequire(interp, "Tcl", "8.0", 0) == NULL) + return TCL_ERROR; + + if(Tcl_PkgProvide(interp, "WPComm", VERSION) != TCL_OK) + return TCL_ERROR; + + Tcl_CreateObjCommand(interp, "WPSend", WPSendCmd, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + return TCL_OK; +} + + + +/* + * WPSendCmd - establish communication with the specified device, + * send the given command and return results to caller. + * + */ +int +WPSendCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char buf[READBUF], lbuf[32], *errbuf = NULL, rbuf[RESULT_MAX], *fname, *cmd; + int s, i, n, b, rs, rv = TCL_ERROR, wlen; + struct sockaddr_un name; + Tcl_Obj *lObj; + + errno = 0; + + if(objc == 3 + && (fname = Tcl_GetStringFromObj(objv[1], NULL)) + && (cmd = Tcl_GetByteArrayFromObj(objv[2], &wlen))){ + if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1){ + snprintf(errbuf = buf, sizeof(buf), "WPC: socket: %s", strerror(errno)); + } + else{ + name.sun_family = AF_UNIX; + strcpy(name.sun_path, fname); + + if(connect(s, (struct sockaddr *) &name, sizeof(name)) == -1){ + if(errno == ECONNREFUSED || errno == ENOENT) + snprintf(errbuf = buf, sizeof(buf), "WPC: Inactive session"); + else + snprintf(errbuf = buf, sizeof(buf), "WPC: connect: %s", strerror(errno)); + } + else if((n = wlen) != 0){ + if(n < 0x7fffffff){ + snprintf(lbuf, sizeof(lbuf), "%d\n", n); + i = strlen(lbuf); + if(write(s, lbuf, i) == i){ + for(i = 0; n; n = n - i) + if((i = write(s, cmd + i, n)) == -1){ + snprintf(errbuf = buf, sizeof(buf), "WPC: write: %s", strerror(errno)); + break; + } + } + else + snprintf(errbuf = buf, sizeof(buf), "Can't write command length."); + } + else + snprintf(errbuf = buf, sizeof(buf), "Command too long."); + + rbuf[0] = '\0'; + rs = 0; + lObj = NULL; + while((n = read(s, buf, READBUF)) > 0) + if(!errbuf){ + for(i = b = 0; i < n; i++) + if(buf[i] == '\n'){ + if(rs){ + Tcl_AppendToObj(Tcl_GetObjResult(interp), &buf[b], i - b); + Tcl_AppendToObj(Tcl_GetObjResult(interp), " ", 1); + } + else{ + rs = 1; + if(append_rbuf(rbuf, &buf[b], i - b) < 0) + snprintf(errbuf = buf, sizeof(buf), "WPC: Response Code Overrun"); + else if(!strcasecmp(rbuf,"OK")) + rv = TCL_OK; + else if(!strcasecmp(rbuf,"ERROR")) + rv = TCL_ERROR; + else if(!strcasecmp(rbuf,"BREAK")) + rv = TCL_BREAK; + else if(!strcasecmp(rbuf,"RETURN")) + rv = TCL_RETURN; + else + snprintf(errbuf = buf, sizeof(buf), "WPC: Unexpected response: %s", rbuf); + } + + b = i + 1; + } + + if(i - b > 0){ + if(rs) + Tcl_AppendToObj(Tcl_GetObjResult(interp), &buf[b], i - b); + else if(append_rbuf(rbuf, &buf[b], i - b) < 0) + snprintf(errbuf = buf, sizeof(buf), "WPC: Response Code Overrun"); + } + } + + if(!errbuf){ + if(n < 0){ + snprintf(errbuf = buf, sizeof(buf), "WPC: read: %s", strerror(errno)); + rv = TCL_ERROR; + } + else if(!rs){ + if(n == 0) + snprintf(errbuf = buf, sizeof(buf), "WPC: Server connection closed (%d)", errno); + else + snprintf(errbuf = buf, sizeof(buf), "WPC: Invalid Response to \"%.*s\" (len %d) (%d): %.*s", 12, cmd, wlen, errno, RESULT_MAX, rbuf); + + rv = TCL_ERROR; + } + else if(rv == TCL_ERROR){ + char *s = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL); + if(!(s && *s)) + snprintf(errbuf = buf, sizeof(buf), "WPC: Empty ERROR Response"); + } + } + } + + close(s); + } + } + else + snprintf(errbuf = buf, sizeof(buf), "Usage: %s path cmd", Tcl_GetStringFromObj(objv[0], NULL)); + + if(errbuf) + Tcl_SetResult(interp, errbuf, TCL_VOLATILE); + + return(rv); +} + + +int +append_rbuf(char *rbuf, char *b, int l) +{ + int i; + + if(l + (i = strlen(rbuf)) > RESULT_MAX) + return(-1); + + rbuf += i; + + while(l--) + *rbuf++ = *b++; + + *rbuf = '\0'; + return(0); +} diff --git a/web/src/cgi.tcl-1.10/HISTORY b/web/src/cgi.tcl-1.10/HISTORY new file mode 100644 index 00000000..3fc80020 --- /dev/null +++ b/web/src/cgi.tcl-1.10/HISTORY @@ -0,0 +1,644 @@ +This is the HISTORY file for cgi.tcl. + +Date Version Description +------- ------- ------------------------------------------------------ +5/1/05 1.10.0 Odd Arne Jensen <odd@bibsyst.xno> observed that <input>-related + tags were producing </input> which is forbidden by the HTML + spec. We agreed to go with .../> for max compatibility with + both HTML and XHTML. + + Noticed hackers submitting filenames with leading hyphens to + display to do interesting things. It did fail gracefully + fortunately but it shouldn't fail at all. Added -- to switch. + + Evan Mezeske <emezeske@enflex.xnet> recommended settable limits + on file uploads to avoid denial-of-service attacks. Added + cgi_file_limit. + +12/14/05 1.9.0 Tore Morkemo noted backward test in cgi_noscript used puts + instead of cgi_puts. + + Aravindo Wingeier <wingeier@glue.ch> provided patches to choose + an encoding or use UTF-8 encoding by default. + + Rolf Ade <pointsmen@gmx.xnet> noted an initialization proc + would be useful for things like tclhttpd. + + Modified display.cgi to deal more gracefully with people + experimenting with tildes. + + De Clarke noted cgi_input failed if whitespace appeared in a + client filename. Due to assumption that Content-Disposition + line would be a proper list. + + De also noted that lynx simply wasn't providing quotes in + multipart input variable names. Relaxed code to accept that. + + De also noted that the binary file upload wasn't working in + pre-Tcl 8.1 but neither of us were interested in spending the + time to find out why. Unless someone bothers to figure it, for + now, I'm just dropping support for such old versions. + + Due to DoC policy, changed cookie example from persistent to + non-persistent. + + Added utf.cgi example to demonstrate UTF works for + mel@redolive.com. + +10/16/02 1.8.0 To accomodate open-ended forms in echo, modified cgi_input so + that it accepts multiple values even in variables that don't + end with "List". This opens a possible ambiguity (see + documentation) but only one that would've existed before had + the diagnostic not prevented it. + + Added example: echo.cgi + + Added cgierror anchor to cgi_eval. + + Tian-Hsiang Huang <xiang@phys.ncku.edu.tw> noted bug in testing + for error of passwd.cgi example. + +4/27/02 1.7.0 David Kuehling <dvdkhlng@gmx.de> noted that cgi_content_type + needed to protect args in call to cgi_http_head. + +4/15/02 1.6.1 Darren New fixed my attempt at 1.6.0! + +4/15/02 1.6.0 Darren New <dnew@san.rr.com> noted that quote_url needed to + translate +. + +3/16/02 1.6.0 Added test for checked=bool to radio/checkbox to avoid having + user have to do "eval ... [expr ...?"checked":""]" nonsense. + + Added version.cgi script to make it easier for people to figure + out whether examples on NIST server are using the same version + of cgi.tcl that they're using. + + Tore Morkemo noted backward test in cgi_refresh. + +9/19/01 1.5.0 De Clarke noted that file upload broke with Opera. Problem + was lack of a \r at the end of the input file. At the same + time protected regexp-specials in the boundary string. + Both of were due to unusual but legal interpretations. + + Added HELO interaction to smtp dialogue. + + Jonathan Lennox <lennox@cs.columbia.edu> provided fix for + finding sendmail on BSD 4.4 systems. + + Modified cgi_html and _start to support optional attributes. + + Extended auto-attr quoting for XHTML support. + Added end tags for XHTML support. + + Added cgi_link_url/label per John Koontz and rewrote cgi_link + to accomodate them. Also added his cgi_button_link + temporarily. Will experiment with this to test merit. + +11/3/00 1.4.3 Removed HTML formatted manual. It lags the text version and + just caused more confusion than it's worth. + +11/2/00 1.4.2 John Koontz observed that the versions between home page and + package didn't match. Added version.in to fix this once and + for all. + +10/19/00 1.4.1 Carlos Vidal <carlos@tarkus.se> fixed cgi_cookie_get -all. + + Anton Osennikov <ant@ccl.ru> provided patch to propagate + errorCode back through cgi_body. + + Fixed display_in_frame to allow app_body_end to execute. + +6/14/00 1.4.0 Tomas Soucek requested a mechanism for saving content-type + from file uploads. Seemed appropriate to do this by renaming + cgi_import_filename to ..._file and adding -type flag. + + Petrus Vloet noted vote.cnt missing from distrib. He also + noted getting warnings regarding missing newlines. + +5/19/00 1.3.0 Changed many cgi_puts to cgi_put in hopes of addressing more + of Zygo's 5/9/00 complaint (i.e., same problem in tables). + +5/9/00 1.2.2 Zygo Blaxell <zblaxell@feedme.hungrycats.org> provided signif. + cgi_input regexp speedup for long x=y-style values. He also + noted that some browsers are sensitive to leading/following + \n's in textarea and provided a patch to avoid adding them in + the first place. + + James Ward <jew@rincon.com> noted absence of pkgIndex.tcl + (presumably due to really old Tcl) broke installation. Fixed + pkgcreate to create stub file to allow Make to complete. + + Robin Lauren <robin.lauren@novostore.com> contributed the doc + in HTML form. Really need to automate this now, sigh. + + Jan.Vlcek@sasprg.cz observed that converting %XX to \u00XX + and then using subst is only good for us-ascii and corrupts + iso8859-1, iso8859-2, etc. He provided a patch for + cgi_unquote_input. + + Ross Mohn <rpmohn@waxandwane.com> corrected syntax error in + cgi_span and made <hr> handle width= better. + + Tore Morkemo provided a patch to his prior patch for cgi_eval. + + Asari Hirotsugu <asari@math.uiuc.edu> provided additional + installation advice for Mac. + +12/27/99 1.2.1 Tore Morkemo noted expires=never value of 9999 inappropriate + as Netscape ignores anything beyond mid-January 2038. + + Tore also provided patch for cgi_eval when running inside of + a proc. + +12/20/99 1.2.0 Keith Lea <keith@cs.oswego.edu> noted 2-digit years as per + RFC2109. Despite RFC, Netscape now accepts 4-digit years. + Some browsers won't like this but it hardly matters anyway + since they'll do the wrong thing on old 2-digit years come + Y2K anyway. + + Petrus Vloet noted example/nistguest missing from distrib. + +12/18/99 1.1.0 Tomas Soucek" <tomas.soucek@sasprg.cz> noted cgi_input was + adding eol characters to uploaded files if they didn't + contain them. Fixed this and also enhanced file upload + example so that it could do both cat/od and also warn when + Tcl couldn't do binary upload. + + Added braces around unprotected expressions. + + Added check to unimail example for HTTP_REFERER. + + Petrus Vloet requested Makefile install example data files. + + Added img.cgi example and modified frame example so it accepts + "example=whatever" so that I can post URLs that go right to a + particular example and have it framed. + +9/12/99 1.0.0 Bumped version to 1 to pacify management. + + Jeffrey Hobbs rewrote cgi_unquote_input to take advantage of + 8.2 features. 300% speed improvement! + +7/16/99 0.8.1 Douglas Ridgway provided mod to make cgi_image_button handle + optional args. + + Made code use straight cgi_input_multipart if on Tcl 8.1. + + Jeffrey Hobbs provided cgi_unquote_input that works better for + 8.1. + + Petrus Vloet <petrus.vloet@siemens.at> requested sample data + files for examples that need them; ability to change example + install destination. + +2/22/98 0.8.0 Tore Morkemo noted that cookied_encode needed to convert \n's. + + Added example of how to produce a raw image. + + Upon suggestion of Jean-Yves Terrien + <jeanyves.terrien@cnet.francetelecom.fr> experimented with + version of cgi_puts that would indent HTML for readability. + Code looked something like this: + + proc NEW_cgi_puts {args} { + global _cgi + + if {$_cgi(preformatted)} { + eval puts $args + } else { + set indent_full [format "%-$_cgi(indent)s" ""] + + # if we're at the beginning of the line, use a full indent + if {$_cgi(bol)} { + set indent $indent_full + } else { + set indent "" + } + + set tail [lindex $args end] + set output "" + + # loop through output, breaking into \n-delimited lines + while {[string length $tail]} { + # this regexp will always match + regexp "^(\[^\n]*)(\n?)(.*)" $tail dummy line nl tail + append output $indent$line + if {$nl == ""} { + set _cgi(bol) 0 + break + } + append output \n + set $_cgi(bol) 1 + set indent $indent_full + } + + # handle optional -nonewline + if {[llength $args] == 1} { + append output \n + set _cgi(bol) 1 + } + puts -nonewline $output + } + } + + Unfortunately, some tags are whitespace-sensitive such as + textarea. If you do cgi_buffer {p;textarea ...} how can cgi_ + puts possibly know that part of the buffer shouldn't be + modified? A user-level flag could be added to avoid corrupting + the HTML but the source display could never be made perfect. + Considering that programmers would have to be aware of these + issues (via flags or options) and the payoff is so minute, it's + just not worth it. I think. As an aside, does regexp on every + line of output cost too much? I doubt anyone would notice but + it's something to ponder. + + Renamed internal cgi routines with _ prefix. + + Matthew Levine <mlevine@cisco.com> observed that cgi_eval + did a #0 eval but a plain eval is more appropriate. + + Anthony Martin <anthony.n.martin@marconicomms.com> noted that + cgi_cgi_set needs to rewrite #. + + Removed cgi_http_get. + + Added registry support to uid_check. + + Eddy Kim <ehkim@ibm.net> noted bug in doc regarding cgi_puts. + + cgi_file_button now verifies that form has correct encoding. + + Fixed doc to reflect more precise use of selected_if_equal. + + Ralph Billes <echo@iinet.net.au> fixed bug in cgi_uid_check. + + Began adding stylesheet support. Made cgi_stylesheet and + cgi_span. Not yet documented. + + Douglas Ridgway <ridgway@gmcl.com> noted that lynx doesn't + respond correctly to multipart form requests. Added check and + diagnostic. Doug also found a bug in the multipart_binary + because I forgot to turn off the timeout. + + Stefan Hornburg <racke@gundel.han.de> writes: + "I've made a RPM package for cgi.tcl. Available at: + http://www.han.de/~racke/linuxia/noarch/cgi.tcl-0.7.5-1.noarch.rpm + http://www.han.de/~racke/linuxia/srpms/cgi.tcl-0.7.5-1.src.rpm + http://www.han.de/~racke/linuxia/specs/cgitcl.spec + and hopefully soon at Redhat/Contrib." + He also noted a missing example: download.cgi. + +6/25/98 0.7.5 Henk-Jan Kooiman <hjk@cable.a2000.nl> fixed bugs in + cgi_relationship and also provided MacOS instructions. + + Martin Schwenke <Martin.Schwenke@cs.anu.edu.au> and Ryan + McCormack <ryanm@cam.nist.gov> both reported textarea lost + newlines when using multipart. + + At urging of Robert Baptista <Robert.Baptista@vanmail.amd.com>, + began adding HTML 4.0 support. Changed cgi_center to avoid + <center>. + + Added download.cgi example. + + John Koontz noted example in file upload documentation still + used deprecated flags. + + 0.7.4 Fixed bug in cgi_refresh. + + Added alt attr to cgi_area. + + Added vote.cgi example. + + Localized some init-time vars to avoid stomping on user's. + + Made cgi_quote_url also quote {"} so URLs. This isn't strictly + necessary, but since URLs will usually be embedded inside HTML, + this simplifies embedding and doesn't hurt anything else. + + Tom Poindexter <tpoindex@nyx.net> added cgi_suffix. + + Removed reference to sendmail from documentation since sendmail + is no longer required. + +12/16/97 0.7.3 Provided SMTP dialogue to replace call to sendmail and removed + all other UNIXisms (exec and direct refs to file system). + + Rewrote LUHN proc in credit card example to work correctly! + + Added type tag support to cgi_relationship. + +11/10/97 0.7.2 Massaged documentation to describe installation on W95/NT.... + Made example.tcl and date.cgi portable. + + Added rm.cgi example. + + Beat Jucker <bj@glue.ch> fixed syntax error in oratcl.cgi + example. + +10/20/97 0.7.1 Fixed cgi_option so that value strings are quoted. Also made + selected_if_equal check value rather than visible string. + + Tore Morkemo <tore@bibsyst.no> provided patch so that cgi_set + translated "=". + + Fixed buffering bug in push example. + + Added credit card example. + + Paul Saxe <saxe@connectnet.com> noted cgi_embed broke due to + unprotected regexp pattern beginning with -. + + +8/22/97 0.7.0 INCOMPATIBILITY: cgi_anchor_name now returns the anchor tag + instead of printing it. Only after some experience do I see + now that anchors always need to be embedded in something else + for accuracy in the jump. + + Josh Lubell noted that file upload failed if there was + whitespace in filename. Problem was that filename-encoding + doesn't encode whitespace or otherwise protect it. There is + no perfect fix since the spec doesn't explain how to know when + fields end. The implication is that they are delimited by + " however an embedded " is not encoded either! For now, assume + filename field is at end of line. This isn't the greatest idea + for it allows future encoding changes to break the code, but + for now it will pick up all filenames including really weird + ones like 'a b"; foo="bar' that would otherwise appear to be + additional fields! + + Jon Leech <leech@cs.unc.edu> provided code to allow user to + temporarily use existing links but displaying differently. + + Alvaro Santamaria <alvaro.santamaria@stest.ch> noted that I + forgot to include kill.cgi and oratcl.cgi in example directory. + + John Koontz noted cgi_buffer's defn of cgi_puts assumed "usual" + newline generation - interacted badly inside of <pre> tags. + Added cgi_buffer_nl to control this. + + James Ward requested option to change ".cgi" suffix. Added + -suffix to cgi_cgi. + + Someone's browser (Mozilla/4.01 [en] (WinNT; I) via proxy + gateway CERN-HTTPD/3.0 libwww/2.17) supplied a boundary defn + but no actual boundary. Added test to + cgi_input_multipart_binary. + + James Ward found cgi_import_list didn't return List vars. + + Diagnostics about broken multipart responses are now returned + to users (who are using old browsers). + + Changed nbsp to numeric equiv to support NS2. + + Made cgi_debug always return old value. + +6/4/97 0.6.6 Added cgi_buffer - force commands that normally generate output + to return strings. + + Deprecated -local & -remote flags to import_filename. Added + support for -server & -client which are less confusing. + + Improved examples in numerous ways. + + James Ward <jew@mcmuse.mc.maricopa.edu> noted I forgot to + document cgi_img. + + Upgraded cgi_quote as per HTML 3.2 + + Mark Diekhans <markd@Grizzly.COM> provided bug fix to cgi_tr + and optional level arg to all uplevel/upvar calls to avoid + misinterpretation. Also added cgi_th. + + Appears that NS3.0 has a bug wrt multipart. It won't display + last fragment on page unless followed by a <br> (even if it + sees </body>). Added cgi_br to multipart support code. + +5/26/97 0.6.5 Added server-push example which required mods to cgi_title + (bug fix actually), cgi_head, and related code to detect and + handle multipart mime type. + + Added HTTP_HOST to list of things reported_HOST during errors. + + Looks like MS IE can generate cookies without an "=val" part. + + Added Oratcl example. + + Documented cgi_url. + + Fixed search for Tcl executable when look in Tcl's srcdir. + + Added support for detection/reporting of client errors. For + now this means missing CONTENT_LENGTH. + + Created cgi_redirect and deprecated cgi_location. cgi_redirect + is better named and more functional. Added cgi_status. + + Modified unimail example so that it shows diagnostics about + form problems to client - doesn't make sense to send them to + unimail admin. + + Improved form-tour in various ways including making a backend + that actually reports value. + + Fixed bug in textvar that caused args to be generated twice. + +4/8/97 0.6.4 John LoVerso fixed regsub quote bug in cgi_quote_url. Fixed + similar bug cgi_cgi_set. + + Most general path cookies were being returned. Changed to most + specific and added -all to cookie_get so that all values could + be retrieved. Added cookie support to passwd example since + that's a very reasonable use of it. + +4/7/97 0.6.3 John LoVerso fixed bugs in cgi_meta and cgi_map. + + INCOMPATIBILITY: cgi_quote_url was inappropriate for non-cgi + urls. cgi_cgi and cgi_cgi_set should now be used for building + GET-style cgi urls. + + Forgot to switch to cgi.tcl.in in distribution. + +3/28/97 0.6.2 Made cgi.tcl.in autohandle embedded version number (see 0.6.1). + + Fixed display.cgi to prevent display of "." or ".." or "". + + Added cgi.tcl version to diagnostics. + Fixed diagnostics to correctly print input. (Totally missing!) + + John Koontz noted extra \r\n at end of uploaded text files. + +3/24/97 0.6.1 Updated package provide version. (Gotta automate this!) + +3/20/97 0.6.0 Added kill.cgi example to kill/suspend runaway CGI processes. + + Modified passwd.cgi example to quote shell arg. + + Kevin.Christian requested hook for defining doctypes. + + John Robert LoVerso <john@loverso.southborough.ma.us> provided + fixes to allow array-style variables names to be rewritten by + cgi_input. Parens had been left with embedded %s substituted. + My research indicates cookies have similar problems but file- + style encoding does not. + + Josh Lubell found bug in binary upload that would drop \r\n + and \r*. + +2/28/97 0.5.5 Combined many regexps that had parameterizably-common actions. + The old regexps had some bugs in them, so it's a good thing. + + M. Katherine Pagoaga <pagoaga@boulder.nist.gov> and John + Koontz <koontz@boulder.nist.gov> noted cgi_uid_check used + whoami which isn't very portable. Switched to "who am i". + Its output isn't very portable but at least its existence is! + + Removed default call to cgi_uid_check. It's my impression that + most people turn this off anyway. If you want it back, just + call it yourself. + + Added cgi_import_filename to guarantee that a filename really + did come from an upload. This removes the security check that + the user was responsible for - and which I forgot in the + upload examples! + + Rolf Ade <rolf@storz.de> noted that configure could look for + tcl executable in a few more locations. + +2/26/97 0.5.4 Backed out type=text from 0.4.4. This ruined type=password. + If people demand, I'll make the code put in type=text but I now + regret the detour. + + Made cgi_import_list return variables in order originally + appearing in form. + +2/24/97 0.5.3 Added tr/td as shortcut for simple table rows. + + Made cookie code look in COOKIE (O'Reilly's web server uses + that instead of HTTP_COOKIE). + + Kevin.Christian@symbio.com requested warning when form + incorrectly uses select without "List" suffix. Also provided + more obvious diagnostics when applying cgi_import* to non- + existent variable. At same time, I also noticed bug in + cgi_import_cookie* preventing it from seeing user variables. + + Forgot to have cgi_root return root with no args. + +2/11/97 0.5.2 Josh Lubell found binary upload broke, due to one send missing + "--" protection. + + Massaged home page so that it works more intelligently with + frames. Massaged examples for both function and appearance. + +2/10/97 0.5.1 Fixed display of validate example. + + Added cgi_unbreakable_string so that it returns a string. + Compare with cgi_unbreakable. + + Added cgi_javascript and noscript. javascript is like script + but does the javascript-compatible hiding of <script> tags for + older browsers. Added some javascript examples. Added support + for java event types. Netscape documentation is very unclear + as to which tags support which attributions - so I guessed a + lot! + +2/4/97 0.5.0 Added cgi_body_args to make it easier to share and change body + attributes. + + Fixed bug in cookie encoder that caused double %-expansion. + + INCOMPATIBILITY: Modified cgi_preformatted to evaluate last + argument. More flexible this way. Since <pre> forces line + breaks, it's not like inline formatting commands. + Removed cgi_code since it used the xmp tag which is gone. + See documentation for workaround. + + INCOMPATIBILITY: Changed cgi_division to take a command list + rather than a string. + + Added cgi_nl for inline breaks. (Compare with cgi_br.) + +2/3/97 0.4.9 Added support for package loading, now you just say: + "package require cgi" + + Added/modified examples so that they could be put up on + web servers. + + Added support to suppress binary upload when using Expect. + +1/31/97 0.4.8 Andreas Kupries <a.kupries@westend.com> needed dynamic control + of ouput. Added user-defineable cgi_puts. + + Josh Lubell <lubell@cme.nist.gov> reported binary file upload + was losing chars on large files. Fixed. + + Fixed cgi_input to understand REQUEST_METHOD == HEAD should + set input to "". + +1/13/97 0.4.7 Braces in password script was wrong. + + Simplified command aliasing mechanism. + + Add some more bulletproofing to catch broken boundary defns... + + Evidentally QUERY_STRING doesn't have to be set even with GET. + CGI spec is vague enough to permit this. + +12/16/96 0.4.6 Giorgetti Federico <gio@egeo.unipg.it> noted text file upload + wasn't working - forgot "_binary" on new upload proc name. + +12/10/96 0.4.5 Added support for binary file upload if using Expect extension. + + Removed check for missing filenames in file upload. This + can evidentally happen. It is now the programmer's + reptysponsibility to check for the length if null filenames are + unwanted. + + Created HTML home page for cgi.tcl. + +11/26/96 0.4.4 Added type=text for pedantic html checkers. + Bob Lipman noted new if_equal handlers used name instead of + value. + +10/24/96 0.4.3 Forgot global _cgi decls in cgi_refresh and some other procs. + + Bob Lipman noted cgi_radio_button needs checked_if_equal. + Added that and same to cgi_checkbox. + +10/15/96 0.4.2 Remove line-delimiters in non-file elements in multipart enc. + + Added support for additional args to cgi_file_button. + +9/19/96 0.4.1 Bob Lipman noted cookie containing = could not be imported. + + Fixed examples to reference .4 source. + +9/9/96 0.4.0 Added cgi_error_occurred. + In multipart handler, added test for "--" because some + servers(?) don't provide explicit eof, but just hang. + Bugs in close_procs support. + Added auto-htmlquoting to cgi_option. + Removed auto-quoting in cgi_cgi. + Made cgi_root also return root if no arg. + Messed up quoting in cgi_anchor_name and cgi_applet. + cgi_parray was missing <xmp> tag. How odd. + +8/12/96 0.3.5 Mark Pahlavan <mark@vestek.com> provided new cgi_caption defn + after noting that it must allow executable code. + + File upload broke in Tcl 7.5 due to auto-eol translation + +6/19/96 0.3.4 Mark Harrison <mharriso@spdmail.spd.dsccc.com> noted ref to + obsolete cgi_uid_ignore. + +6/19/96 0.3.3 Was wrongly cookie-encoding cookie expiration. cgi_imglink + was confused. Thanks again, Bob. + +6/17/96 0.3.2 Reports from Bob Lipman <lipman@cam.nist.gov> about bad + tables and missing </head>. Fixed. + +6/13/96 0.3.1 Added ";" to &-escapes. Fixed bugs in cgi_unquote_input. + Added cgi_embed. Added doc directory with ref manual. + diff --git a/web/src/cgi.tcl-1.10/INSTALL b/web/src/cgi.tcl-1.10/INSTALL new file mode 100644 index 00000000..4a7f8a76 --- /dev/null +++ b/web/src/cgi.tcl-1.10/INSTALL @@ -0,0 +1,96 @@ +This file is INSTALL. It contains installation instructions for cgi.tcl. + +If you do not have Tcl, get it (the README explains how) and install +it. The rest of these instructions assume that you have Tcl +installed. + +-------------------- +Installation +-------------------- + +By default, the Tcl source directory is assumed to be in the same +directory as the cgi.tcl source directory. For example, in this +listing, cgi.tcl and Tcl are both stored in /usr/local/src: + + /usr/local/src/tcl7.5 (actual version may be different) + /usr/local/src/cgi.tcl-1.0 (actual version may be different) + +If Tcl is stored elsewhere, the easiest way to deal with this is to +create a symbolic link to its real directory. For example, from the +cgi.tcl directory, type: + + ln -s /some/where/else/src/tcl7.5 .. + +Run "./configure". This will generate a Makefile (from a prototype +called "Makefile.in") appropriate to your system. Make sure you run +configure with the same arguments as when you ran Tcl's configure +script. (If you don't, package loading won't work.) + +Most people will not need to make any changes to the generated +Makefile and can go on to the next step. If you want though, you can +edit the Makefile and change any definitions as appropriate for your +site. All the definitions you are likely to want to change are +clearly identified and described at the beginning of the file. + +Run "make". + +It is useful (although not necessary) for cgi.tcl to understand how to +send mail. By default, cgi.tcl tries to use /usr/lib/sendmail, +otherwise it falls back to carrying out the raw SMTP dialogue itself. +Any mailer can be substituted by modifying cgi.tcl appropriately. It +is easy to do. Edit cgi.tcl and look at the cgi_mail_end procedure. +It should be obvious what to do at that point. The ability to send +mail isn't required for basic use of cgi.tcl, but it is especially +useful for in-the-field debugging so I encourage you to enable it. + +You can now "source cgi.tcl" if you want to try things out by hand +before installing (or if you want to use the package without +installing it). Example: + + $ tclsh7.6 (or whatever your Tcl interpreter is called) + % source cgi.tcl + % h4 "Don Libes" + <h4>Don Libes</h4> + % + +Once you're done playing, go ahead and install it. To install everything: + + make install + +You're done! Now you can use cgi.tcl. + +-------------------- +Examples +-------------------- + +The example directory has some examples. See the README in there. + +-------------------- +Test Suite +-------------------- + +There is no test suite. + +-------------------- +Uninstalling +-------------------- + +"make uninstall" removes all the files that "make install" creates +(excluding those in the current directory). + +-------------------- +Cleaning Up +-------------------- + +Several "clean" targets are available to reduce space consumption of +the cgi.tcl source. The two most useful are as follows: + +"make clean" deletes all files from the current directory that were +created by "make" + +"make distclean" is like "make clean", but it also deletes files +created by "configure" + +Other targets can be found in the Makefile. They follow the GNU +Makefile conventions. + diff --git a/web/src/cgi.tcl-1.10/Makefile.in b/web/src/cgi.tcl-1.10/Makefile.in new file mode 100644 index 00000000..3f818f2c --- /dev/null +++ b/web/src/cgi.tcl-1.10/Makefile.in @@ -0,0 +1,273 @@ +# +# Makefile for Don Libes' cgi.tcl - routines for writing CGI scripts in Tcl +# + +VERSION = \"@CGI_VERSION_FULL@\" +SHORT_VERSION = @CGI_VERSION@ + +srcdir = @srcdir@ +VPATH = @srcdir@ +SUBDIRS = @subdirs@ + +###################################################################### +# The following lines are things you may want to change +###################################################################### + +# By default, "make install" will install the appropriate files in +# /usr/local/bin, /usr/local/lib, /usr/local/man, etc. By changing this +# variable, you can specify an installation prefix other than /usr/local. +# You may find it preferable to call configure with the --prefix option +# to control this information. This is especially handy if you are +# installing this several times (perhaps on a number of machines or +# in different places). Then you don't have to hand-edit this file. +# See the INSTALL file for more information. (Analogous information +# applies to the next variable as well.) +prefix = @prefix@ + +# You can specify a separate installation prefix for architecture-specific +# files such as binaries and libraries. +exec_prefix = @exec_prefix@ + +# Short directory path where binaries can be found to support #! hack. +# This directory path can be the same as the directory in which the binary +# actually sits except when the path is so long that the #! mechanism breaks +# (usually at 32 characters). +# The solution is to create a directory with a very short name, which consists +# only of symbolic links back to the true binaries. Subtracting two for "#!" +# and a couple more for arguments (typically " -f" or " --") gives you 27 +# characters. Pathnames over this length won't be able to use the #! magic. +# For more info on this, see the execve(2) man page. +SHORT_BINDIR = $(exec_prefix)/bin + +# Tcl interpreter for utility work. +CGI_TCL_EXECUTABLE = @CGI_TCL_EXECUTABLE@ + +# Where to put the examples - a directory in which your web server has +# permission to execute CGI scripts. +exampledir = /tmp/cgi-bin/cgi-tcl-examples + +###################################################################### +# End of things you may want to change +# +# Do not change anything after this +###################################################################### + +bindir_arch_indep = $(prefix)/bin +libdir = $(exec_prefix)/lib +datadir = $(prefix)/lib + +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man3dir = $(mandir)/man3 +docdir = $(datadir)/doc + +# utility script directories - arch-independent and arch-non- +# independent. +SCRIPTDIR = $(datadir)/cgi$(SHORT_VERSION) +EXECSCRIPTDIR = $(execdatadir)/cgi$(SHORT_VERSION) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# To install the following examples: make examples +EXAMPLES=cookie.cgi creditcard.cgi \ + display.cgi display-in-frame.cgi download.cgi \ + echo.cgi error.cgi evaljs.cgi example.tcl examples.cgi \ + form-tour.cgi form-tour-result.cgi format-tour.cgi frame.cgi \ + image.cgi img.cgi kill.cgi nistguest.cgi oratcl.cgi \ + parray.cgi passwd.tcl passwd-form.cgi passwd.cgi \ + push.cgi rm.cgi stopwatch.cgi \ + unimail.cgi upload.cgi uploadbin.cgi \ + validate.cgi vclock.cgi vclock.pl vclock-src-frame.cgi visitor.cgi \ + vote.cgi + +EXAMPLES_DATA=nistguest vote.cnt + +all: cgi.tcl pkgIndex.tcl + +info: +dvi: + +# Delete all the installed files that the `install' target creates +# (but not the noninstalled files such as `make all' creates) +uninstall: + -rm -f $(SCRIPTDIR)/cgi.tcl + -rm -f $(man3dir)/cgi.tcl.3 + -rm -f $(SCRIPTDIR)/pkgIndex.tcl + +.PHONY: install-info install info +install-info: + +install: all + ${srcdir}/mkinstalldirs $(man3dir) $(SCRIPTDIR) $(exampledir) $(exampledir)/data +# install scripts + $(INSTALL_DATA) cgi.tcl $(SCRIPTDIR) +# install library man page + $(INSTALL_DATA) cgi.tcl.man $(man3dir)/cgi.tcl.3 + $(INSTALL_DATA) pkgIndex.tcl $(SCRIPTDIR) + +examples: + for i in $(EXAMPLES) ; do \ + $(CGI_TCL_EXECUTABLE) $(srcdir)/fixline1 $(SHORT_BINDIR) < $(srcdir)/example/$$i > $$i ; \ + $(INSTALL_PROGRAM) $$i $(exampledir) ; \ + rm -f $$i ; \ + done + for i in $(EXAMPLES_DATA) ; do \ + $(INSTALL) -m 666 $(srcdir)/example/$$i $(exampledir)/data ; \ + done + +cgi.tcl: $(srcdir)/cgi.tcl.in + @echo "Rebuilding cgi.tcl..." + $(SHELL) ./config.status + +################################### +# Targets for Makefile and configure +################################### + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) config.status + @echo "Rebuilding the Makefile..." + $(SHELL) ./config.status + +# Let "make -f Makefile.in" produce a configure file +configure: $(srcdir)/configure.in $(srcdir)/Makefile.in + @echo "Rebuilding configure..." + if [ x"${srcdir}" = x"@srcdir@" ] ; then \ + srcdir=. ; export srcdir ; \ + else true ; fi ; \ + (cd $${srcdir}; autoconf) + +config.status: $(srcdir)/configure + @echo "Rebuilding config.status..." + $(SHELL) ./config.status --recheck + +check: + @if [ -f testsuite/Makefile ]; then \ + cd testsuite && $(MAKE) $(FLAGS_TO_PASS) check; \ + else true; fi + +# updating of pkgIndex.tcl has not yet been totally automated +# Instructions: +# 1) Replace version # in cgi.tcl with updated version. +# (Gad, I'd have to turn the whole source into .in file to automate this +# and it'd be a major nuisance when developing!) +pkgIndex.tcl: cgi.tcl + $(CGI_TCL_EXECUTABLE) pkgcreate + +################################################ +# Various "clean" targets follow GNU conventions +################################################ + +# delete all files from current directory that are created by "make" +clean: + -rm -f *~ *.o core + +# like "clean", but also delete files created by "configure" +distclean: clean + -rm -f Makefile config.status config.cache config.log + -rm -f Dbg_cf.h + +# like "clean", but doesn't delete test utilities or massaged scripts +# because most people don't have to worry about them +mostlyclean: + -rm -f *~ *.o core + +# delete everything from current directory that can be reconstructed +# except for configure +realclean: distclean + +###################################### +# Targets for pushing out releases +###################################### + +FTPDIR = /itl/www/div826/subject/expect/cgi.tcl + +# make a private tar file for myself +tar: cgi.tcl-$(SHORT_VERSION).tar + mv cgi.tcl-$(SHORT_VERSION).tar cgi.tcl.tar + +# Make a release and install it on ftp server +# Note that we run configure on our end to make sure that cgi.tcl is usable +# for people who don't have configure at the destination end (non-UNIX folks). +ftp: cgi.tcl cgi.tcl-$(SHORT_VERSION).tar.Z cgi.tcl-$(SHORT_VERSION).tar.gz install-html + cp cgi.tcl-$(SHORT_VERSION).tar.Z $(FTPDIR)/cgi.tcl.tar.Z + cp cgi.tcl-$(SHORT_VERSION).tar.gz $(FTPDIR)/cgi.tcl.tar.gz + cp HISTORY $(FTPDIR) + cp README $(FTPDIR)/README.distribution + cp doc/ref.txt $(FTPDIR) + cp doc/ref.html $(FTPDIR) + cp example/README $(FTPDIR)/example + cp `pubfile example` $(FTPDIR)/example + ls -l $(FTPDIR)/cgi.tcl.tar* +# delete temp files + rm cgi.tcl-$(SHORT_VERSION).tar* + +cgi.tcl-$(SHORT_VERSION).tar: configure + rm -f ../cgi.tcl-$(SHORT_VERSION) + ln -s `pwd` ../cgi.tcl-$(SHORT_VERSION) + cd ..;tar cvfh $@ `pubfile cgi.tcl-$(SHORT_VERSION)` + mv ../$@ . + +cgi.tcl-$(SHORT_VERSION).tar.Z: cgi.tcl-$(SHORT_VERSION).tar + compress -fc cgi.tcl-$(SHORT_VERSION).tar > $@ + +cgi.tcl-$(SHORT_VERSION).tar.gz: cgi.tcl-$(SHORT_VERSION).tar + gzip -fc cgi.tcl-$(SHORT_VERSION).tar > $@ + +########################### +# Targets for producing FAQ and homepage +########################### + +NISTCGI_PREFIX = /local +NISTCGI_HOST = ats.nist.gov +NISTCGI_INTERPDIR = $(NISTCGI_PREFIX)/bin +NISTCGI_LIBDIR = $(NISTCGI_PREFIX)/lib/cgi$(SHORT_VERSION) +NISTCGI_EXAMPLEDIR = $(NISTCGI_HOST):/private/home/http/cgi-bin/cgi.tcl +NISTCGI_HTMLDIR = /itl/www/div826/subject/expect/cgi.tcl + +# create the FAQ in html form +FAQ.html: FAQ.src FAQ.tcl + FAQ.src > FAQ.html + +# create the FAQ in text form +#FAQ: FAQ.src FAQ.tcl +# FAQ.src text > FAQ + +# generate home page +homepage.html: homepage.src common.tcl configure + homepage.src > homepage.html + +realapps.html: realapps.src common.tcl + realapps.src > realapps.html + +RSH = ssh +RCP = scp + +# install various html docs on our web server +install-html: FAQ.html homepage.html realapps.html pkgIndex.tcl cgi.tcl + cp FAQ.html $(NISTCGI_HTMLDIR)/ + cp homepage.html $(NISTCGI_HTMLDIR)/index.html + cp realapps.html $(NISTCGI_HTMLDIR)/ + -$(RSH) $(NISTCGI_HOST) mkdir $(NISTCGI_LIBDIR)/ + $(RCP) cgi.tcl pkgIndex.tcl $(NISTCGI_HOST):$(NISTCGI_LIBDIR)/ + for i in $(EXAMPLES) ; do \ + $(CGI_TCL_EXECUTABLE) $(srcdir)/fixline1 $(NISTCGI_INTERPDIR) < $(srcdir)/example/$$i > $$i ; \ + $(RCP) $$i $(NISTCGI_EXAMPLEDIR)/ ; \ + rm -f $$i ; \ + done + +# add recursive support to the build process. +subdir_do: force + @for i in $(SUBDIRS); do \ + echo "Making $(DO) in $${i}..." ; \ + if [ -d ./$$i ] ; then \ + if (rootme=`pwd`/ ; export rootme ; \ + rootsrc=`cd $(srcdir); pwd`/ ; export rootsrc ; \ + cd ./$$i; \ + $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \ + else exit 1 ; fi ; \ + else true ; fi ; \ + done +force: + +## dependencies will be put after this line... ## diff --git a/web/src/cgi.tcl-1.10/PATCH.UW b/web/src/cgi.tcl-1.10/PATCH.UW new file mode 100644 index 00000000..0288cb72 --- /dev/null +++ b/web/src/cgi.tcl-1.10/PATCH.UW @@ -0,0 +1,230 @@ +*** ./cgi.tcl.in.orig 2006-05-01 11:15:52.000000000 -0700 +--- ./cgi.tcl.in 2006-11-14 16:01:51.000000000 -0800 +*************** +*** 52,58 **** + + if {[info exists _cgi(http_status_done)]} return + set _cgi(http_status_done) 1 +! puts "Status: $num $str" + } + + # If these are called manually, they automatically generate the extra newline +--- 52,58 ---- + + if {[info exists _cgi(http_status_done)]} return + set _cgi(http_status_done) 1 +! cgi_puts "Status: $num $str" + } + + # If these are called manually, they automatically generate the extra newline +*************** +*** 1342,1348 **** + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + # explicitly flush all writes to fout, because sometimes the writer + # can hang and we won't get to the termination code +! set dbg_fout [open $dbg_filename w] + set _cgi(input) $dbg_filename + catch {fconfigure $dbg_fout -translation binary} + } +--- 1342,1348 ---- + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + # explicitly flush all writes to fout, because sometimes the writer + # can hang and we won't get to the termination code +! set dbg_fout [open $dbg_filename w $_cgi(tmpperms)] + set _cgi(input) $dbg_filename + catch {fconfigure $dbg_fout -translation binary} + } +*************** +*** 1409,1415 **** + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] +! set fout [open $foutname w] + # "catch" permits this to work with Tcl 7.4 + catch {fconfigure $fout -translation binary} + _cgi_set_uservar $varname [list $foutname $filename $conttype] +--- 1409,1415 ---- + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] +! set fout [open $foutname w $_cgi(tmpperms)] + # "catch" permits this to work with Tcl 7.4 + catch {fconfigure $fout -translation binary} + _cgi_set_uservar $varname [list $foutname $filename $conttype] +*************** +*** 1452,1457 **** +--- 1452,1458 ---- + } else { + # read the part into a variable + set val "" ++ set blanks 0 + while {1} { + if {-1 == [gets $fin buf]} break + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} +*************** +*** 1463,1468 **** +--- 1464,1479 ---- + append val \n + } + regexp (.*)\r$ $buf dummy buf ++ if {[info exists blanks]} { ++ if {0!=[string compare $buf ""]} { ++ if {$blanks} { ++ append val [string repeat \n [incr blanks]] ++ } ++ unset blanks ++ } else { ++ incr blanks ++ } ++ } + append val $buf + } + _cgi_set_uservar $varname $val +*************** +*** 1482,1488 **** + # save file for debugging purposes + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + set _cgi(input) $dbg_filename +! spawn -open [open $dbg_filename w] + set dbg_sid $spawn_id + } + spawn -open $fin +--- 1493,1499 ---- + # save file for debugging purposes + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + set _cgi(input) $dbg_filename +! spawn -open [open $dbg_filename w $_cgi(tmpperms)] + set dbg_sid $spawn_id + } + spawn -open $fin +*************** +*** 1579,1585 **** + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] +! spawn -open [open $foutname w] + set fout_sid $spawn_id + + _cgi_set_uservar $varname [list $foutname $filename $conttype] +--- 1590,1596 ---- + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] +! spawn -open [open $foutname w $_cgi(tmpperms)] + set fout_sid $spawn_id + + _cgi_set_uservar $varname [list $foutname $filename $conttype] +*************** +*** 2187,2202 **** + + flush $_cgi(mailfid) + +! if {[file executable /usr/lib/sendmail]} { +! exec /usr/lib/sendmail -t -odb < $_cgi(mailfile) +! # Explanation: +! # -t means: pick up recipient from body +! # -odb means: deliver in background +! # note: bogus local address cause sendmail to fail immediately +! } elseif {[file executable /usr/sbin/sendmail]} { +! exec /usr/sbin/sendmail -t -odb < $_cgi(mailfile) +! # sendmail is in /usr/sbin on some BSD4.4-derived systems. +! } else { + # fallback for sites without sendmail + + if {0==[info exists _cgi(mail_relay)]} { +--- 2198,2215 ---- + + flush $_cgi(mailfid) + +! foreach sendmail in $_cgi(sendmail) { +! if {[file executable $sendmail]} { +! exec $sendmail -t -odb < $_cgi(mailfile) +! # Explanation: +! # -t means: pick up recipient from body +! # -odb means: deliver in background +! # note: bogus local address cause sendmail to fail immediately +! set sent 1 +! } +! } +! +! if {0==[info exists sent]} { + # fallback for sites without sendmail + + if {0==[info exists _cgi(mail_relay)]} { +*************** +*** 2241,2246 **** +--- 2254,2265 ---- + set _cgi(mail_relay) $host + } + ++ proc cgi_sendmail {path} { ++ global _cgi ++ ++ set _cgi(sendmail) $path ++ } ++ + ################################################## + # cookie support + ################################################## +*************** +*** 2416,2422 **** + ################################################## + + proc cgi_stylesheet {href} { +! puts "<link rel=stylesheet href=\"$href\" type=\"text/css\"/>" + } + + proc cgi_span {args} { +--- 2435,2441 ---- + ################################################## + + proc cgi_stylesheet {href} { +! cgi_puts "<link rel=stylesheet href=\"$href\" type=\"text/css\"/>" + } + + proc cgi_span {args} { +*************** +*** 2545,2550 **** +--- 2564,2584 ---- + } + + ################################################## ++ # temporary file procedures ++ ################################################## ++ ++ # set appropriate temporary file modes ++ proc cgi_tmpfile_permissions {{mode ""}} { ++ global _cgi ++ ++ if {[string length $mode]} { ++ set _cgi(tmpperms) $mode ++ } ++ ++ return $_cgi(tmpperms) ++ } ++ ++ ################################################## + # user-defined procedures + ################################################## + +*************** +*** 2604,2615 **** +--- 2638,2655 ---- + switch $tcl_platform(platform) { + unix { + set _cgi(tmpdir) /tmp ++ set _cgi(tmpperms) 0644 ++ set _cgi(sendmail) [list /usr/lib/sendmail /usr/sbin/sendmail] + } macintosh { + set _cgi(tmpdir) [pwd] ++ set _cgi(tmpperms) {} ++ set _cgi(sendmail) {} + } default { + set _cgi(tmpdir) [pwd] + catch {set _cgi(tmpdir) $env(TMP)} + catch {set _cgi(tmpdir) $env(TEMP)} ++ set _cgi(tmpperms) {} ++ set _cgi(sendmail) {} + } + } + diff --git a/web/src/cgi.tcl-1.10/README b/web/src/cgi.tcl-1.10/README new file mode 100644 index 00000000..4c7381fe --- /dev/null +++ b/web/src/cgi.tcl-1.10/README @@ -0,0 +1,140 @@ +This is the README to cgi.tcl, a library of Tcl procedures to assist +in writing CGI scripts. Review the HISTORY file for significant changes. + +The cgi.tcl home page is http://expect.nist.gov/cgi.tcl + +-------------------- +Introduction +-------------------- + +This is the README file for cgi.tcl, a set of procedures for writing +CGI scripts in Tcl. The procedures implement the code described in +the paper "Writing CGI scripts in Tcl" which was published in the +Proceedings of the Fourth Tcl Workshop (Tcl '96). + +-------------------- +Getting Started +-------------------- + +First, read the paper "Writing CGI Scripts in Tcl", from Tcl '96. If +you can't find the paper in this archive, it can also be found at: + + http://www.nist.gov/msidlibrary/doc/libes96c.ps + +That paper will give you a lot of good ideas for using Tcl, not only +with CGI but plain everyday HTML as well. + +Next, try some of the examples in the example directory. Please read +the "Instructions" section in example/README first. + +A rough draft of complete documentation of the individual functions +can be found in ref.txt in the doc directory. + +Note that you are expected to understand Tcl. I'm not going to +explain how to write Tcl scripts here. (If you're looking for a Tcl +tutorial, please consider my Expect book which includes a very nice +tutorial on Tcl.) + +Similarly, you are expected to understand HTML. There are plenty of +web tutorials and books on it. Go read one. You don't have to become +an expert on HTML, but it is important to get a feel for it. (The +cgi.tcl package will take care of the details.) If you plan to do +CGI, you should know a couple more basic things. Here's a simple CGI +intro: + + http://hoohoo.ncsa.uiuc.edu/cgi/intro.html + + +-------------------- +Status +-------------------- + +The library is reasonably complete. It supports forms, tables, +cookies, Netscape extensions, file upload, plug-ins, etc, etc. On the +other hand, there are some things missing - such as certain deprecated +things in HTML, things I can't believe anyone would use, things that +are special extensions to a browser I'm not familiar with, etc. + +This library should run on any system (UNIX, Win, or Mac) which +supports Tcl 8.1 or later. + +---------------------- +Examples +---------------------- + +This distribution contains example scripts. They can be found in the +example directory of this distribution. Please read the +"Instructions" section in example/README first. + +-------------------- +Installation +-------------------- + +If you are on UNIX, read the INSTALL file. +If you are on W95/NT, read the install.win file. +If you are on Mac, read the install.mac file. + +-------------------- +How to get the latest version of this code +-------------------- + +The latest version of this code may be received from: + + http://expect.nist.gov/cgi.tcl/cgi.tcl.tar.gz +or ftp://ftp.nist.gov/mel/div826/subject/expect/cgi.tcl/cgi.tcl.tar.gz + +-------------------- +Support from Don Libes or NIST +-------------------- + +Although I can't promise anything in the way of support, I'd be +interested to hear about your experiences using it (good or bad). I'm +also interested in hearing bug reports and suggestions for improvement +even though I can't promise to implement them. + +If you send me a bug, fix, or question, include the version of +cgi.tcl, version of Tcl, and name and version of the OS that you are +using. Before sending mail, it may be helpful to verify that your +problem still exists in the latest version. You can check on the +current release and whether it addresses your problems by retrieving +the latest HISTORY file (see "History" above). + + +Awards, love letters, and bug reports may be sent to: + +Don Libes +National Institute of Standards and Technology +Bldg 220, Rm A-127 +Gaithersburg, MD 20899 +(301) 975-3535 +libes@nist.gov + +I hereby place this software in the public domain. NIST and I would +appreciate credit if this program or parts of it are used. + +Design and implementation of this program was funded primarily by +myself. Funding contributors include the NIST Automated Manufacturing +Research Facility (funded by the Navy Manufacturing Technology +Program), the NIST Scientific and Technical Research Services, the +ARPA Persistent Object Bases project and the Computer-aided +Acquisition and the Logistic Support (CALS) program of the Office of +the Secretary of Defense. + +-------------------- +Support for Don Libes or NIST +-------------------- + +NIST accepts external funding and other resources (hardware, software, +and personnel). This can be a fine way to work more closely with NIST +and encourage particular areas of research. + +Funding can be earmarked for specific purposes or for less-specific +purposes. For example, if you simply like the work I do, you can +contribute directly to my funding which will reduce the amount of time +I have to spend writing proposals and submitting them to other people +for funding on my own. + +I can also participate in the NIST Fellows program allowing me to +spend several months to a year working directly with your company and +potentially even at your location. + diff --git a/web/src/cgi.tcl-1.10/README.UW b/web/src/cgi.tcl-1.10/README.UW new file mode 100644 index 00000000..7dfe161c --- /dev/null +++ b/web/src/cgi.tcl-1.10/README.UW @@ -0,0 +1,23 @@ +This is the README.UW of the cgi.tcl library as included with the Web +Alpine distribution. + +Web Alpine page generation is based heavily on the routines provided +by the cgi.tcl library. It's shown to be a robust and flexible +platform for generating dynamic web-based content. + +This cgi.tcl library as included with the Web Alpine application has +been slightly modified. The small changes, which can be found in +PATCH.UW, amount to a few things: + + 1) A hook to allow for temporary file permission setting + + 2) A hook to allow for resetting (and specifically, unsetting) + the path to sendmail used for error reporting + + 3) A few fixes for misdirected output ("puts" --> "cgi_puts") + + 4) Change to _cgi_input_multipart to preserve leading + newlines + +For comments or questions regarding the Web Alpine application +send comments to <alpine-contact@cac.washington.edu> diff --git a/web/src/cgi.tcl-1.10/cgi.tcl.in b/web/src/cgi.tcl-1.10/cgi.tcl.in new file mode 100644 index 00000000..df426c08 --- /dev/null +++ b/web/src/cgi.tcl-1.10/cgi.tcl.in @@ -0,0 +1,2659 @@ +################################################## +# +# cgi.tcl - routines for writing CGI scripts in Tcl +# Author: Don Libes <libes@nist.gov>, January '95 +# +# These routines implement the code described in the paper +# "Writing CGI scripts in Tcl" which appeared in the Tcl '96 conference. +# Please read the paper before using this code. The paper is: +# http://expect.nist.gov/doc/cgi.pdf +# +################################################## + +################################################## +# http header support +################################################## + +proc cgi_http_head {args} { + global _cgi env errorInfo + + if {[info exists _cgi(http_head_done)]} return + + set _cgi(http_head_in_progress) 1 + + if {0 == [llength $args]} { + cgi_content_type + } else { + if {[catch {uplevel 1 [lindex $args 0]} errMsg]} { + set savedInfo $errorInfo + cgi_content_type + } + } + cgi_puts "" + + unset _cgi(http_head_in_progress) + set _cgi(http_head_done) 1 + + if {[info exists savedInfo]} { + error $errMsg $savedInfo + } +} + +# avoid generating http head if not in CGI environment +# to allow generation of pure HTML files +proc _cgi_http_head_implicit {} { + global env + + if {[info exists env(REQUEST_METHOD)]} cgi_http_head +} + +proc cgi_status {num str} { + global _cgi + + if {[info exists _cgi(http_status_done)]} return + set _cgi(http_status_done) 1 + cgi_puts "Status: $num $str" +} + +# If these are called manually, they automatically generate the extra newline + +proc cgi_content_type {args} { + global _cgi + + if {0==[llength $args]} { + set t text/html + } else { + set t [lindex $args 0] + if {[regexp ^multipart/ $t]} { + set _cgi(multipart) 1 + } + } + + if {[info exists _cgi(http_head_in_progress)]} { + cgi_puts "Content-type: $t" + } else { + cgi_http_head [list cgi_content_type $t] + } +} + +proc cgi_redirect {t} { + global _cgi + + if {[info exists _cgi(http_head_in_progress)]} { + cgi_status 302 Redirected + cgi_puts "Uri: $t" + cgi_puts "Location: $t" + } else { + cgi_http_head { + cgi_redirect $t + } + } +} + +# deprecated, use cgi_redirect +proc cgi_location {t} { + global _cgi + + if {[info exists _cgi(http_head_in_progress)]} { + cgi_puts "Location: $t" + } else { + cgi_http_head "cgi_location $t" + } +} + +proc cgi_target {t} { + global _cgi + + if {![info exists _cgi(http_head_in_progress)]} { + error "cgi_target must be set from within cgi_http_head." + } + cgi_puts "Window-target: $t" +} + +# Make client retrieve url in this many seconds ("client pull"). +# With no 2nd arg, current url is retrieved. +proc cgi_refresh {seconds {url ""}} { + global _cgi + + if {![info exists _cgi(http_head_in_progress)]} { + error "cgi_refresh must be set from within cgi_http_head. Try using cgi_http_equiv instead." + } + cgi_put "Refresh: $seconds" + + if {0!=[string compare $url ""]} { + cgi_put "; $url" + } + cgi_puts "" +} + +# Example: cgi_pragma no-cache +proc cgi_pragma {arg} { + global _cgi + + if {![info exists _cgi(http_head_in_progress)]} { + error "cgi_pragma must be set from within cgi_http_head." + } + cgi_puts "Pragma: $arg" +} + +################################################## +# support for debugging or other crucial things we need immediately +################################################## + +proc cgi_comment {args} {} ;# need this asap + +proc cgi_html_comment {args} { + regsub -all {>} $args {\>} args + cgi_put "<!--[_cgi_list_to_string $args] -->" +} + +set _cgi(debug) -off +proc cgi_debug {args} { + global _cgi + + set old $_cgi(debug) + set arg [lindex $args 0] + if {$arg == "-on"} { + set _cgi(debug) -on + set args [lrange $args 1 end] + } elseif {$arg == "-off"} { + set _cgi(debug) -off + set args [lrange $args 1 end] + } elseif {[regexp "^-t" $arg]} { + set temp 1 + set _cgi(debug) -on + set args [lrange $args 1 end] + } elseif {[regexp "^-noprint$" $arg]} { + set noprint 1 + set args [lrange $args 1 end] + } + + set arg [lindex $args 0] + if {$arg == "--"} { + set args [lrange $args 1 end] + } + + if {[llength $args]} { + if {$_cgi(debug) == "-on"} { + + _cgi_close_tag + # force http head and open html, head, body + catch { + if {[info exists noprint]} { + uplevel 1 [lindex $args 0] + } else { + cgi_html { + cgi_head { + cgi_title "debugging before complete HTML head" + } + # force body open and leave open + _cgi_body_start + uplevel 1 [lindex $args 0] + # bop back out to catch, so we don't close body + error "ignore" + } + } + } + } + } + + if {[info exists temp]} { + set _cgi(debug) $old + } + return $old +} + +proc cgi_uid_check {user} { + global env + + # leave in so old scripts don't blow up + if {[regexp "^-off$" $user]} return + + if {[info exists env(USER)]} { + set whoami $env(USER) + } elseif {0==[catch {exec whoami} whoami]} { + # "who am i" on some Linux hosts returns "" so try whoami first + } elseif {0==[catch {exec who am i} whoami]} { + # skip over "host!" + regexp "(.*!)?(\[^ \t]*)" $whoami dummy dummy whoami + } elseif {0==[catch {package require registry}]} { + set whoami [registry get HKEY_LOCAL_MACHINE\\Network\\Logon username] + } else { + set whoami $user ;# give up and let go + } + if {$whoami != "$user"} { + error "Warning: This CGI script expects to run with uid \"$user\". However, this script is running as \"$whoami\"." + } +} + +# print out elements of an array +# like Tcl's parray, but formatted for browser +proc cgi_parray {a {pattern *}} { + upvar 1 $a array + if {![array exists array]} { + error "\"$a\" isn't an array" + } + + set maxl 0 + foreach name [lsort [array names array $pattern]] { + if {[string length $name] > $maxl} { + set maxl [string length $name] + } + } + cgi_preformatted { + set maxl [expr {$maxl + [string length $a] + 2}] + foreach name [lsort [array names array $pattern]] { + set nameString [format %s(%s) $a $name] + cgi_puts [cgi_quote_html [format "%-*s = %s" $maxl $nameString $array($name)]] + } + } +} + +proc cgi_eval {cmd} { + global env _cgi + + # put cmd somewhere that uplevel can find it + set _cgi(body) $cmd + + uplevel 1 { + global env _cgi errorInfo + + if {1==[catch $_cgi(body) errMsg]} { + # error occurred, handle it + set _cgi(errorInfo) $errorInfo + + if {![info exists env(REQUEST_METHOD)]} { + puts stderr $_cgi(errorInfo) + return + } + # the following code is all to force browsers into a state + # such that diagnostics can be reliably shown + + # close irrelevant things + _cgi_close_procs + # force http head and open html, head, body + cgi_html { + cgi_body { + if {[info exists _cgi(client_error)]} { + cgi_h3 "Client Error" + cgi_p "$errMsg Report this to your system administrator or browser vendor." + } else { + cgi_put [cgi_anchor_name cgierror] + cgi_h3 "An internal error was detected in the service\ + software. The diagnostics are being emailed to\ + the service system administrator ($_cgi(admin_email))." + + if {$_cgi(debug) == "-on"} { + cgi_puts "Heck, since you're debugging, I'll show you the\ + errors right here:" + # suppress formatting + cgi_preformatted { + cgi_puts [cgi_quote_html $_cgi(errorInfo)] + } + } else { + cgi_mail_start $_cgi(admin_email) + cgi_mail_add "Subject: [cgi_name] CGI problem" + cgi_mail_add + cgi_mail_add "CGI environment:" + cgi_mail_add "REQUEST_METHOD: $env(REQUEST_METHOD)" + cgi_mail_add "SCRIPT_NAME: $env(SCRIPT_NAME)" + # this next few things probably don't need + # a catch but I'm not positive + catch {cgi_mail_add "HTTP_USER_AGENT: $env(HTTP_USER_AGENT)"} + catch {cgi_mail_add "HTTP_REFERER: $env(HTTP_REFERER)"} + catch {cgi_mail_add "HTTP_HOST: $env(HTTP_HOST)"} + catch {cgi_mail_add "REMOTE_HOST: $env(REMOTE_HOST)"} + catch {cgi_mail_add "REMOTE_ADDR: $env(REMOTE_ADDR)"} + cgi_mail_add "cgi.tcl version: @CGI_VERSION_FULL@" + cgi_mail_add "input:" + catch {cgi_mail_add $_cgi(input)} + cgi_mail_add "cookie:" + catch {cgi_mail_add $env(HTTP_COOKIE)} + cgi_mail_add "errorInfo:" + cgi_mail_add "$_cgi(errorInfo)" + cgi_mail_end + } + } + } ;# end cgi_body + } ;# end cgi_html + } ;# end catch + } ;# end uplevel +} + +# return true if cgi_eval caught an error +proc cgi_error_occurred {} { + global _cgi + + return [info exists _cgi(errorInfo)] +} + +################################################## +# CGI URL creation +################################################## + +# declare location of root of CGI files +# this allows all CGI references to be relative in the source +# making it easy to move everything in the future +# If you have multiple roots, just don't call this. +proc cgi_root {args} { + global _cgi + + if {[llength $args]} { + set _cgi(root) [lindex $args 0] + } else { + set _cgi(root) + } +} + +# make a URL for a CGI script +proc cgi_cgi {args} { + global _cgi + + set root $_cgi(root) + if {0!=[string compare $root ""]} { + if {![regexp "/$" $root]} { + append root "/" + } + } + + set suffix [cgi_suffix] + + set arg [lindex $args 0] + if {0==[string compare $arg "-suffix"]} { + set suffix [lindex $args 1] + set args [lrange $args 2 end] + } + + if {[llength $args]==1} { + return $root[lindex $args 0]$suffix + } else { + return $root[lindex $args 0]$suffix?[join [lrange $args 1 end] &] + } +} + +proc cgi_suffix {args} { + global _cgi + if {[llength $args] > 0} { + set _cgi(suffix) [lindex $args 0] + } + if {![info exists _cgi(suffix)]} { + return .cgi + } else { + return $_cgi(suffix) + } +} + +proc cgi_cgi_set {variable value} { + regsub -all {%} $value "%25" value + regsub -all {&} $value "%26" value + regsub -all {\+} $value "%2b" value + regsub -all { } $value "+" value + regsub -all {=} $value "%3d" value + regsub -all {#} $value "%23" value + regsub -all {/} $value "%2f" value ;# Added... + return $variable=$value +} + +################################################## +# URL dictionary support +################################################## + +proc cgi_link {args} { + global _cgi_link + + set tag [lindex $args 0] + switch -- [llength $args] { + 1 { + set label $_cgi_link($tag,label) + } 2 { + set label [lindex $args end] + } default { + set _cgi_link($tag,label) [set label [lindex $args 1]] + set _cgi_link($tag,url) [lrange $args 2 end] + } + } + + return [eval cgi_url [list $label] $_cgi_link($tag,url)] +} + +# same as above but for images +# note: uses different namespace +proc cgi_imglink {args} { + global _cgi_imglink + + set tag [lindex $args 0] + if {[llength $args] >= 2} { + set _cgi_imglink($tag) [eval cgi_img [lrange $args 1 end]] + } + return $_cgi_imglink($tag) +} + +proc cgi_link_label {tag} { + global _cgi_link + return $_cgi_link($tag,label) +} + +proc cgi_link_url {tag} { + global _cgi_link + return $_cgi_link($tag,url) +} + +################################################## +# hyperlink support +################################################## + +# construct a hyperlink labeled "display" +# last arg is the link destination +# any other args are passed through into <a> display +proc cgi_url {display args} { + global _cgi + + set buf "<a href=\"[lindex $args 0]\"" + foreach a [lrange $args 1 end] { + if {[regexp $_cgi(attr,regexp) $a dummy attr str]} { + append buf " $attr=\"$str\"" + } else { + append buf " $a" + } + } + return "$buf>$display</a>" +} + +# generate an image reference (<img ...>) +# first arg is image url +# other args are passed through into <img> tag +proc cgi_img {args} { + global _cgi + + set buf "<img src=\"[lindex $args 0]\"" + foreach a [lrange $args 1 end] { + if {[regexp "^(alt|lowsrc|usemap)=(.*)" $a dummy attr str]} { + append buf " $attr=[cgi_dquote_html $str]" + } elseif {[regexp $_cgi(attr,regexp) $a dummy attr str]} { + append buf " $attr=\"$str\"" + } else { + append buf " $a" + } + } + return "$buf />" +} + +# names an anchor so that it can be linked to +proc cgi_anchor_name {name} { + return "<a name=\"$name\"/>" +} + +proc cgi_base {args} { + global _cgi + + cgi_put "<base" + foreach a $args { + if {[regexp "^href=(.*)" $a dummy str]} { + cgi_put " href=[cgi_dquote_html $str]" + } elseif {[regexp $_cgi(attr,regexp) $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_puts " />" +} + +################################################## +# quoting support +################################################## + +if {[info tclversion] >= 8.2} { + proc cgi_unquote_input buf { + # rewrite "+" back to space + # protect \ from quoting another \ and throwing off other things + # replace line delimiters with newlines + set buf [string map -nocase [list + { } "\\" "\\\\" %0d%0a \n] $buf] + + # prepare to process all %-escapes + regsub -all -nocase {%([a-f0-9][a-f0-9])} $buf {\\u00\1} buf + + # process \u unicode mapped chars + encoding convertfrom $::_cgi(queryencoding) \ + [subst -novar -nocommand $buf] + } +} elseif {[info tclversion] >= 8.1} { + proc cgi_unquote_input buf { + # rewrite "+" back to space + regsub -all {\+} $buf { } buf + # protect \ from quoting another \ and throwing off other things + regsub -all {\\} $buf {\\\\} buf + + # replace line delimiters with newlines + regsub -all -nocase "%0d%0a" $buf "\n" buf + + # prepare to process all %-escapes + regsub -all -nocase {%([a-f0-9][a-f0-9])} $buf {\\u00\1} buf + # process \u unicode mapped chars + return [subst -novar -nocommand $buf] + } +} else { + proc cgi_unquote_input {buf} { + # rewrite "+" back to space + regsub -all {\+} $buf { } buf + # protect \ from quoting another \ and throwing off other things first + # protect $ from doing variable expansion + # protect [ from doing evaluation + # protect " from terminating string + regsub -all {([\\["$])} $buf {\\\1} buf + + # replace line delimiters with newlines + regsub -all -nocase "%0d%0a" $buf "\n" buf + # Mosaic sends just %0A. This is handled in the next command. + + # prepare to process all %-escapes + regsub -all -nocase {%([a-f0-9][a-f0-9])} $buf {[format %c 0x\1]} buf + # process %-escapes and undo all protection + eval return \"$buf\" + } +} + +# return string but with html-special characters escaped, +# necessary if you want to send unknown text to an html-formatted page. +proc cgi_quote_html {s} { + regsub -all {&} $s {\&} s ;# must be first! + regsub -all {"} $s {\"} s + regsub -all {<} $s {\<} s + regsub -all {>} $s {\>} s + return $s +} + +proc cgi_dquote_html {s} { + return \"[cgi_quote_html $s]\" +} + +# return string quoted appropriately to appear in a url +proc cgi_quote_url {in} { + regsub -all {%} $in "%25" in + regsub -all {\+} $in "%2b" in + regsub -all { } $in "%20" in + regsub -all {"} $in "%22" in + regsub -all {\?} $in "%3f" in + return $in +} + +################################################## +# short or single paragraph support +################################################## + +proc cgi_br {args} { + cgi_put "<br" + if {[llength $args]} { + cgi_put "[_cgi_list_to_string $args]" + } + cgi_put " />" +} + +# generate cgi_h1 and others +for {set _cgi(tmp) 1} {$_cgi(tmp)<8} {incr _cgi(tmp)} { + proc cgi_h$_cgi(tmp) {{args}} "eval cgi_h $_cgi(tmp) \$args" +} +proc cgi_h {num args} { + cgi_put "<h$num" + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + set args [lrange $args end end] + } + cgi_put ">[lindex $args 0]</h$num>" +} + +proc cgi_p {args} { + cgi_put "<p" + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + set args [lrange $args end end] + } + cgi_put ">[lindex $args 0]</p>" +} + +proc cgi_address {s} {cgi_put <address>$s</address>} +proc cgi_blockquote {s} {cgi_puts <blockquote>$s</blockquote>} + +################################################## +# long or multiple paragraph support +################################################## + +# Shorthand for <div align=center>. We used to use <center> tags but that +# is now officially unsupported. +proc cgi_center {cmd} { + uplevel 1 "cgi_division align=center [list $cmd]" +} + +proc cgi_division {args} { + cgi_put "<div" + _cgi_close_proc_push "cgi_put </div>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr {[llength $args]-2}]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_preformatted {args} { + cgi_put "<pre" + _cgi_close_proc_push "cgi_put </pre>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +################################################## +# list support +################################################## + +proc cgi_li {args} { + cgi_put <li + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">[lindex $args end]</li>" +} + +proc cgi_number_list {args} { + cgi_put "<ol" + _cgi_close_proc_push "cgi_put </ol>" + + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + + _cgi_close_proc +} + +proc cgi_bullet_list {args} { + cgi_put "<ul" + _cgi_close_proc_push "cgi_put </ul>" + + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + + _cgi_close_proc +} + +# Following two are normally used from within definition lists +# but are actually paragraph types on their own. +proc cgi_term {s} {cgi_put <dt>$s</dt>} +proc cgi_term_definition {s} {cgi_put <dd>$s</dd>} + +proc cgi_definition_list {cmd} { + cgi_put "<dl>" + _cgi_close_proc_push "cgi_put </dl>" + + uplevel 1 $cmd + _cgi_close_proc +} + +proc cgi_menu_list {cmd} { + cgi_put "<menu>" + _cgi_close_proc_push "cgi_put </menu>" + + uplevel 1 $cmd + _cgi_close_proc +} +proc cgi_directory_list {cmd} { + cgi_put "<dir>" + _cgi_close_proc_push "cgi_put </dir>" + + uplevel 1 $cmd + _cgi_close_proc +} + +################################################## +# text support +################################################## + +proc cgi_put {s} {cgi_puts -nonewline $s} + +# some common special characters +proc cgi_lt {} {return "<"} +proc cgi_gt {} {return ">"} +proc cgi_amp {} {return "&"} +proc cgi_quote {} {return """} +proc cgi_enspace {} {return " "} +proc cgi_emspace {} {return " "} +proc cgi_nbspace {} {return " "} ;# nonbreaking space +proc cgi_tm {} {return "®"} ;# registered trademark +proc cgi_copyright {} {return "©"} +proc cgi_isochar {n} {return "&#$n;"} +proc cgi_breakable {} {return "<wbr />"} + +proc cgi_unbreakable_string {s} {return "<nobr>$s</nobr>"} +proc cgi_unbreakable {cmd} { + cgi_put "<nobr>" + _cgi_close_proc_push "cgi_put </nobr>" + uplevel 1 $cmd + _cgi_close_proc +} + +proc cgi_nl {args} { + set buf "<br" + if {[llength $args]} { + append buf "[_cgi_list_to_string $args]" + } + return "$buf />" +} + +proc cgi_bold {s} {return "<b>$s</b>"} +proc cgi_italic {s} {return "<i>$s</i>"} +proc cgi_underline {s} {return "<u>$s</u>"} +proc cgi_strikeout {s} {return "<s>$s</s>"} +proc cgi_subscript {s} {return "<sub>$s</sub>"} +proc cgi_superscript {s} {return "<sup>$s</sup>"} +proc cgi_typewriter {s} {return "<tt>$s</tt>"} +proc cgi_blink {s} {return "<blink>$s</blink>"} +proc cgi_emphasis {s} {return "<em>$s</em>"} +proc cgi_strong {s} {return "<strong>$s</strong>"} +proc cgi_cite {s} {return "<cite>$s</cite>"} +proc cgi_sample {s} {return "<samp>$s</samp>"} +proc cgi_keyboard {s} {return "<kbd>$s</kbd>"} +proc cgi_variable {s} {return "<var>$s</var>"} +proc cgi_definition {s} {return "<dfn>$s</dfn>"} +proc cgi_big {s} {return "<big>$s</big>"} +proc cgi_small {s} {return "<small>$s</small>"} + +proc cgi_basefont {size} {cgi_put "<basefont size=$size />"} + +proc cgi_font {args} { + global _cgi + + set buf "<font" + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp $_cgi(attr,regexp) $a dummy attr str]} { + append buf " $attr=\"$str\"" + } else { + append buf " $a" + } + } + return "$buf>[lindex $args end]</font>" +} + +# take a cgi func and have it return what would normally print +# This command is reentrant (that's why it's so complex). +proc cgi_buffer {cmd} { + global _cgi + + if {0==[info exists _cgi(returnIndex)]} { + set _cgi(returnIndex) 0 + } + + rename cgi_puts cgi_puts$_cgi(returnIndex) + incr _cgi(returnIndex) + set _cgi(return[set _cgi(returnIndex)]) "" + + proc cgi_puts args { + global _cgi + upvar #0 _cgi(return[set _cgi(returnIndex)]) buffer + + append buffer [lindex $args end] + if {[llength $args] == 1} { + append buffer $_cgi(buffer_nl) + } + } + + # must restore things before allowing the eval to fail + # so catch here and rethrow later + if {[catch {uplevel 1 $cmd} errMsg]} { + global errorInfo + set savedInfo $errorInfo + } + + # not necessary to put remainder of code in close_proc_push since it's + # all buffered anyway and hasn't yet put browser into a funky state. + + set buffer $_cgi(return[set _cgi(returnIndex)]) + + incr _cgi(returnIndex) -1 + rename cgi_puts "" + rename cgi_puts$_cgi(returnIndex) cgi_puts + + if {[info exists savedInfo]} { + error $errMsg $savedInfo + } + return $buffer +} + +set _cgi(buffer_nl) "\n" +proc cgi_buffer_nl {nl} { + global _cgi + + set old $_cgi(buffer_nl) + set _cgi(buffer_nl) $nl + return $old +} + +################################################## +# html and tags that can appear in html top-level +################################################## + +proc cgi_html {args} { + set html [lindex $args end] + set argc [llength $args] + if {$argc > 1} { + eval _cgi_html_start [lrange $args 0 [expr {$argc-2}]] + } else { + _cgi_html_start + } + uplevel 1 $html + _cgi_html_end +} + +proc _cgi_html_start {args} { + global _cgi + + if {[info exists _cgi(html_in_progress)]} return + _cgi_http_head_implicit + + set _cgi(html_in_progress) 1 + cgi_doctype + + append buf "<html" + foreach a $args { + if {[regexp $_cgi(attr,regexp) $a dummy attr str]} { + append buf " $attr=\"$str\"" + } else { + append buf " $a" + } + } + cgi_puts "$buf>" +} + +proc _cgi_html_end {} { + global _cgi + unset _cgi(html_in_progress) + set _cgi(html_done) 1 + cgi_puts "</html>" +} + +# force closure of all tags and exit without going through normal returns. +# Very useful if you want to call exit from a deeply stacked CGI script +# and still have the HTML be correct. +proc cgi_exit {} { + _cgi_close_procs + cgi_html {cgi_body {}} + exit +} + +################################################## +# head support +################################################## + +proc cgi_head {{head {}}} { + global _cgi + + if {[info exists _cgi(head_done)]} { + return + } + + # allow us to be recalled so that we can display errors + if {0 == [info exists _cgi(head_in_progress)]} { + _cgi_http_head_implicit + set _cgi(head_in_progress) 1 + cgi_puts "<head>" + } + + # prevent cgi_html (during error handling) from generating html tags + set _cgi(html_in_progress) 1 + # don't actually generate html tags since there's nothing to clean + # them up + + if {0 == [string length $head]} { + if {[catch {cgi_title}]} { + set head "cgi_title untitled" + } + } + uplevel 1 $head + if {![info exists _cgi(head_suppress_tag)]} { + cgi_puts "</head>" + } else { + unset _cgi(head_suppress_tag) + } + + set _cgi(head_done) 1 + + # debugging can unset this in the uplevel above + catch {unset _cgi(head_in_progress)} +} + +# with one arg: set, print, and return title +# with no args: return title +proc cgi_title {args} { + global _cgi + + set title [lindex $args 0] + + if {[llength $args]} { + _cgi_http_head_implicit + + # we could just generate <head></head> tags, but head-level commands + # might follow so just suppress the head tags entirely + if {![info exists _cgi(head_in_progress)]} { + set _cgi(head_in_progress) 1 + set _cgi(head_suppress_tag) 1 + } + + set _cgi(title) $title + cgi_puts "<title>$title</title>" + } + return $_cgi(title) +} + +# This tag can only be called from with cgi_head. +# example: cgi_http_equiv Refresh 1 +# There's really no reason to call this since it can be done directly +# from cgi_http_head. +proc cgi_http_equiv {type contents} { + _cgi_http_head_implicit + cgi_puts "<meta http-equiv=\"$type\" content=[cgi_dquote_html $contents]/>" +} + +# Do whatever you want with meta tags. +# Example: <meta name="author" content="Don Libes"> +proc cgi_meta {args} { + cgi_put "<meta" + foreach a $args { + if {[regexp "^(name|content|http-equiv)=(.*)" $a dummy attr str]} { + cgi_put " $attr=[cgi_dquote_html $str]" + } else { + cgi_put " $a" + } + } + cgi_puts " />" +} + +proc cgi_relationship {rel href args} { + cgi_puts "<link rel=$rel href=\"$href\"" + foreach a $args { + if {[regexp "^title=(.*)" $a dummy str]} { + cgi_put " title=[cgi_dquote_html $str]" + } elseif {[regexp "^type=(.*)" $a dummy str]} { + cgi_put " type=[cgi_dquote_html $str]" + } else { + cgi_put " $a" + } + } + cgi_puts "/>" +} + +proc cgi_name {args} { + global _cgi + + if {[llength $args]} { + set _cgi(name) [lindex $args 0] + } + return $_cgi(name) +} + +################################################## +# body and other top-level support +################################################## + +proc cgi_body {args} { + global errorInfo errorCode _cgi + + # allow user to "return" from the body without missing _cgi_body_end + if {1==[catch { + eval _cgi_body_start [lrange $args 0 [expr [llength $args]-2]] + uplevel 1 [lindex $args end] + } errMsg]} { + set savedInfo $errorInfo + set savedCode $errorCode + error $errMsg $savedInfo $savedCode + } + _cgi_body_end +} + +proc _cgi_body_start {args} { + global _cgi + if {[info exists _cgi(body_in_progress)]} return + + cgi_head + + set _cgi(body_in_progress) 1 + + cgi_put "<body" + foreach a "$args $_cgi(body_args)" { + if {[regexp "^(background|bgcolor|text|link|vlink|alink|onLoad|onUnload)=(.*)" $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_puts ">" + + cgi_debug { + global env + catch {cgi_puts "Input: <pre>$_cgi(input)</pre>"} + catch {cgi_puts "Cookie: <pre>$env(HTTP_COOKIE)</pre>"} + } + + if {![info exists _cgi(errorInfo)]} { + uplevel 2 app_body_start + } +} + +proc _cgi_body_end {} { + global _cgi + if {![info exists _cgi(errorInfo)]} { + uplevel 2 app_body_end + } + unset _cgi(body_in_progress) + cgi_puts "</body>" + + if {[info exists _cgi(multipart)]} { + unset _cgi(http_head_done) + catch {unset _cgi(http_status_done)} + unset _cgi(head_done) + catch {unset _cgi(head_suppress_tag)} + } +} + +proc cgi_body_args {args} { + global _cgi + + set _cgi(body_args) $args +} + +proc cgi_script {args} { + cgi_puts "<script[_cgi_lrange $args 0 [expr [llength $args]-2]]>" + _cgi_close_proc_push "cgi_puts </script>" + + uplevel 1 [lindex $args end] + + _cgi_close_proc +} + +proc cgi_javascript {args} { + cgi_puts "<script[_cgi_lrange $args 0 [expr [llength $args]-2]]>" + cgi_puts "<!--- Hide script from browsers that don't understand JavaScript" + _cgi_close_proc_push {cgi_puts "// End hiding -->\n</script>"} + + uplevel 1 [lindex $args end] + + _cgi_close_proc +} + +proc cgi_noscript {args} { + cgi_puts "<noscript[_cgi_lrange $args 0 [expr [llength $args]-2]]>" + _cgi_close_proc_push {cgi_puts "</noscript>"} + + uplevel 1 [lindex $args end] + + _cgi_close_proc +} + +proc cgi_applet {args} { + cgi_puts "<applet[_cgi_lrange $args 0 [expr [llength $args]-2]]>" + _cgi_close_proc_push "cgi_puts </applet>" + + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_param {nameval} { + regexp "(\[^=]*)(=?)(.*)" $nameval dummy name q value + + if {$q != "="} { + set value "" + } + cgi_puts "<param name=\"$name\" value=[cgi_dquote_html $value]/>" +} + +# record any proc's that must be called prior to displaying an error +proc _cgi_close_proc_push {p} { + global _cgi + if {![info exists _cgi(close_proc)]} { + set _cgi(close_proc) "" + } + set _cgi(close_proc) "$p; $_cgi(close_proc)" +} + +proc _cgi_close_proc_pop {} { + global _cgi + regexp "^(\[^;]*);(.*)" $_cgi(close_proc) dummy lastproc _cgi(close_proc) + return $lastproc +} + +# generic proc to close whatever is on the top of the stack +proc _cgi_close_proc {} { + eval [_cgi_close_proc_pop] +} + +proc _cgi_close_procs {} { + global _cgi + + _cgi_close_tag + if {[info exists _cgi(close_proc)]} { + uplevel #0 $_cgi(close_proc) + } +} + +proc _cgi_close_tag {} { + global _cgi + + if {[info exists _cgi(tag_in_progress)]} { + cgi_put ">" + unset _cgi(tag_in_progress) + } +} + +################################################## +# hr support +################################################## + +proc cgi_hr {args} { + set buf "<hr" + foreach a $args { + if {[regexp "^width=(.*)" $a dummy str]} { + append buf " width=\"$str\"" + } else { + append buf " $a" + } + } + cgi_put "$buf />" +} + +################################################## +# form & isindex +################################################## + +proc cgi_form {action args} { + global _cgi + + _cgi_form_multiple_check + set _cgi(form_in_progress) 1 + + _cgi_close_proc_push _cgi_form_end + cgi_put "<form action=" + if {[regexp {^[a-z]*:} $action]} { + cgi_put "\"$action\"" + } else { + cgi_put "\"[cgi_cgi $action]\"" + } + set method "method=post" + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp "^method=" $a]} { + set method $a + } elseif {[regexp "^(target|onReset|onSubmit)=(.*)" $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } elseif {[regexp "^enctype=(.*)" $a dummy str]} { + cgi_put " enctype=\"$str\"" + set _cgi(form,enctype) $str + } else { + cgi_put " $a" + } + } + cgi_put " $method>" + uplevel 1 [lindex $args end] + catch {unset _cgi(form,enctype)} + _cgi_close_proc +} + +proc _cgi_form_end {} { + global _cgi + unset _cgi(form_in_progress) + cgi_put "</form>" +} + +proc _cgi_form_multiple_check {} { + global _cgi + if {[info exists _cgi(form_in_progress)]} { + error "Cannot create form (or isindex) with form already in progress." + } +} + +proc cgi_isindex {args} { + _cgi_form_multiple_check + + cgi_put "<isindex" + foreach a $args { + if {[regexp "^href=(.*)" $a dummy str]} { + cgi_put " href=\"$str\"" + } elseif {[regexp "^prompt=(.*)" $a dummy str]} { + cgi_put " prompt=[cgi_dquote_html $str]" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +################################################## +# argument handling +################################################## + +proc cgi_input {{fakeinput {}} {fakecookie {}}} { + global env _cgi _cgi_uservar _cgi_cookie _cgi_cookie_shadowed + + set _cgi(uservars) {} + set _cgi(uservars,autolist) {} + + if {[info exists env(CONTENT_TYPE)] && [regexp ^multipart/form-data $env(CONTENT_TYPE)]} { + if {![info exists env(REQUEST_METHOD)]} { + # running by hand + set fid [open $fakeinput] + } else { + set fid stdin + } + if {([info tclversion] >= 8.1) || [catch exp_version] || [info exists _cgi(no_binary_upload)]} { + _cgi_input_multipart $fid + } else { + _cgi_input_multipart_binary $fid + } + } else { + if {![info exists env(REQUEST_METHOD)]} { + set input $fakeinput + set env(HTTP_COOKIE) $fakecookie + } elseif { $env(REQUEST_METHOD) == "GET" } { + set input "" + catch {set input $env(QUERY_STRING)} ;# doesn't have to be set + } elseif { $env(REQUEST_METHOD) == "HEAD" } { + set input "" + } elseif {![info exists env(CONTENT_LENGTH)]} { + set _cgi(client_error) 1 + error "Your browser failed to generate the content-length during a POST method." + } else { + set length $env(CONTENT_LENGTH) + if {0!=[string compare $length "-1"]} { + set input [read stdin $env(CONTENT_LENGTH)] + } else { + set _cgi(client_error) 1 + error "Your browser generated a content-length of -1 during a POST method." + } + if {[info tclversion] >= 8.1} { + # guess query encoding from Content-Type header + if {[info exists env(CONTENT_TYPE)] \ + && [regexp -nocase -- {charset=([^[:space:]]+)} $env(CONTENT_TYPE) m cs]} { + if {[regexp -nocase -- {iso-?8859-([[:digit:]]+)} $cs m d]} { + set _cgi(queryencoding) "iso8859-$d" + } elseif {[regexp -nocase -- {windows-([[:digit:]]+)} $cs m d]} { + set _cgi(queryencoding) "cp$d" + } elseif {0==[string compare -nocase $cs "utf-8"]} { + set _cgi(queryencoding) "utf-8" + } elseif {0==[string compare -nocase $cs "utf-16"]} { + set _cgi(queryencoding) "unicode" + } + } else { + set _cgi(queryencoding) [encoding system] + } + } + } + # save input for possible diagnostics later + set _cgi(input) $input + + set pairs [split $input &] + foreach pair $pairs { + if {0 == [regexp "^(\[^=]*)=(.*)$" $pair dummy varname val]} { + # if no match, unquote and leave it at that + # this is typical of <isindex>-style queries + set varname anonymous + set val $pair + } + + set varname [cgi_unquote_input $varname] + set val [cgi_unquote_input $val] + _cgi_set_uservar $varname $val + } + } + + # O'Reilly's web server incorrectly uses COOKIE + catch {set env(HTTP_COOKIE) $env(COOKIE)} + if {![info exists env(HTTP_COOKIE)]} return + foreach pair [split $env(HTTP_COOKIE) ";"] { + # pairs are actually split by "; ", sigh + set pair [string trimleft $pair " "] + # spec is not clear but seems to allow = unencoded + # only sensible interpretation is to assume no = in var names + # appears MS IE can omit "=val" + set val "" + regexp (\[^=]*)=?(.*) $pair dummy varname val + + set varname [cgi_unquote_input $varname] + set val [cgi_unquote_input $val] + + if {[info exists _cgi_cookie($varname)]} { + lappend _cgi_cookie_shadowed($varname) $val + } else { + set _cgi_cookie($varname) $val + } + } +} + +proc _cgi_input_multipart {fin} { + global env _cgi _cgi_uservar _cgi_userfile + + cgi_debug -noprint { + # save file for debugging purposes + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + # explicitly flush all writes to fout, because sometimes the writer + # can hang and we won't get to the termination code + set dbg_fout [open $dbg_filename w $_cgi(tmpperms)] + set _cgi(input) $dbg_filename + catch {fconfigure $dbg_fout -translation binary} + } + + # figure out boundary + if {0==[regexp boundary=(.*) $env(CONTENT_TYPE) dummy boundary]} { + set _cgi(client_error) 1 + error "Your browser failed to generate a \"boundary=\" line in a multipart response (CONTENT_TYPE: $env(CONTENT_TYPE)). Please upgrade (or fix) your browser." + } + + # make boundary into a legal regsub pattern by protecting # + # legal boundary characters include ()+.? (among others) + regsub -all "\\(" $boundary "\\(" boundary + regsub -all "\\)" $boundary "\\)" boundary + regsub -all "\\+" $boundary "\\+" boundary + regsub -all "\\." $boundary "\\." boundary + regsub -all "\\?" $boundary "\\?" boundary + + set boundary --$boundary + + # don't corrupt or modify uploads yet allow Tcl 7.4 to work + catch {fconfigure $fin -translation binary} + + # get first boundary line + gets $fin buf + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} + + set _cgi(file,filecount) 0 + + while {1} { + # process Content-Disposition: + if {-1 == [gets $fin buf]} break + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} + catch {unset filename} + regexp {name="([^"]*)"} $buf dummy varname + if {0==[info exists varname]} { + # lynx violates spec and doesn't use quotes, so try again but + # assume space is delimiter + regexp {name=([^ ]*)} $buf dummy varname + if {0==[info exists varname]} { + set _cgi(client_error) 1 + error "In response to a request for a multipart form, your browser generated a part header without a name field. Please upgrade (or fix) your browser." + } + } + # Lame-o encoding (on Netscape at least) doesn't escape field + # delimiters (like quotes)!! Since all we've ever seen is filename= + # at end of line, assuming nothing follows. Sigh. + regexp {filename="(.*)"} $buf dummy filename + + # Skip remaining headers until blank line. + # Content-Type: can appear here. + set conttype "" + while {1} { + if {-1 == [gets $fin buf]} break + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} + if {0==[string compare $buf "\r"]} break + regexp -nocase "^Content-Type:\[ \t]+(.*)\r" $buf x conttype + } + + if {[info exists filename]} { + if {$_cgi(file,filecount) > $_cgi(file,filelimit)} { + error "Too many files submitted. Max files allowed: $_cgi(file,filelimit)" + } + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] + set fout [open $foutname w $_cgi(tmpperms)] + # "catch" permits this to work with Tcl 7.4 + catch {fconfigure $fout -translation binary} + _cgi_set_uservar $varname [list $foutname $filename $conttype] + set _cgi_userfile($varname) [list $foutname $filename $conttype] + + # + # Look for a boundary line preceded by \r\n. + # + # To do this, we buffer line terminators that might + # be the start of the special \r\n$boundary sequence. + # The buffer is called "leftover" and is just inserted + # into the front of the next output (assuming it's + # not a boundary line). + + set leftover "" + while {1} { + if {-1 == [gets $fin buf]} break + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} + + if {0 == [string compare "\r\n" $leftover]} { + if {[regexp ^[set boundary](--)?\r?$ $buf dummy dashdash]} { + if {$dashdash == "--"} {set eof 1} + break + } + } + if {[regexp (.*)\r$ $buf x data]} { + puts -nonewline $fout $leftover$data + set leftover "\r\n" + } else { + puts -nonewline $fout $leftover$buf + set leftover "\n" + } + if {[file size $foutname] > $_cgi(file,charlimit)} { + error "File size exceeded. Max file size allowed: $_cgi(file,charlimit)" + } + } + + close $fout + unset fout + } else { + # read the part into a variable + set val "" + set blanks 0 + while {1} { + if {-1 == [gets $fin buf]} break + if {[info exists dbg_fout]} {puts $dbg_fout $buf; flush $dbg_fout} + if {[regexp ^[set boundary](--)?\r?$ $buf dummy dashdash]} { + if {$dashdash == "--"} {set eof 1} + break + } + if {0!=[string compare $val ""]} { + append val \n + } + regexp (.*)\r$ $buf dummy buf + if {[info exists blanks]} { + if {0!=[string compare $buf ""]} { + if {$blanks} { + append val [string repeat \n [incr blanks]] + } + unset blanks + } else { + incr blanks + } + } + append val $buf + } + _cgi_set_uservar $varname $val + } + if {[info exists eof]} break + } + if {[info exists dbg_fout]} {close $dbg_fout} +} + +proc _cgi_input_multipart_binary {fin} { + global env _cgi _cgi_uservar _cgi_userfile + + log_user 0 + set timeout -1 + + cgi_debug -noprint { + # save file for debugging purposes + set dbg_filename [file join $_cgi(tmpdir) CGIdbg.[pid]] + set _cgi(input) $dbg_filename + spawn -open [open $dbg_filename w $_cgi(tmpperms)] + set dbg_sid $spawn_id + } + spawn -open $fin + set fin_sid $spawn_id + remove_nulls 0 + + if {0} { + # dump input to screen + cgi_debug { + puts "<xmp>" + expect { + -i $fin_sid + -re ^\r {puts -nonewline "CR"; exp_continue} + -re ^\n {puts "NL"; exp_continue} + -re . {puts -nonewline $expect_out(buffer); exp_continue} + } + puts "</xmp>" + exit + } + } + + # figure out boundary + if {0==[regexp boundary=(.*) $env(CONTENT_TYPE) dummy boundary]} { + set _cgi(client_error) 1 + error "Your browser failed to generate a \"boundary=\" definition in a multipart response (CONTENT_TYPE: $env(CONTENT_TYPE)). Please upgrade (or fix) your browser." + } + + # make boundary into a legal regsub pattern by protecting # + # legal boundary characters include ()+.? (among others) + regsub -all "\\(" $boundary "\\(" boundary + regsub -all "\\)" $boundary "\\)" boundary + regsub -all "\\+" $boundary "\\+" boundary + regsub -all "\\." $boundary "\\." boundary + regsub -all "\\?" $boundary "\\?" boundary + + set boundary --$boundary + set linepat "(\[^\r]*)\r\n" + + # get first boundary line + expect { + -i $fin_sid + -re $linepat { + set buf $expect_out(1,string) + if {[info exists dbg_sid]} {send -i $dbg_sid -- $buf\n} + } + eof { + set _cgi(client_error) 1 + error "Your browser failed to provide an initial boundary ($boundary) in a multipart response. Please upgrade (or fix) your browser." + } + } + + set _cgi(file,filecount) 0 + + while {1} { + # process Content-Disposition: + expect { + -i $fin_sid + -re $linepat { + set buf $expect_out(1,string) + if {[info exists dbg_sid]} {send -i $dbg_sid -- $buf\n} + } + eof break + } + catch {unset filename} + regexp {name="([^"]*)"} $buf dummy varname + if {0==[info exists varname]} { + set _cgi(client_error) 1 + error "In response to a request for a multipart form, your browser generated a part header without a name field. Please upgrade (or fix) your browser." + } + + # Lame-o encoding (on Netscape at least) doesn't escape field + # delimiters (like quotes)!! Since all we've ever seen is filename= + # at end of line, assuming nothing follows. Sigh. + regexp {filename="(.*)"} $buf dummy filename + + # Skip remaining headers until blank line. + # Content-Type: can appear here. + set conttype "" + expect { + -i $fin_sid + -re $linepat { + set buf $expect_out(1,string) + if {[info exists dbg_sid]} {send -i $dbg_sid -- $buf\n} + if {0!=[string compare $buf ""]} exp_continue + regexp -nocase "^Content-Type:\[ \t]+(.*)\r" $buf x conttype + } + eof break + } + + if {[info exists filename]} { + if {$_cgi(file,filecount) > $_cgi(file,filelimit)} { + error "Too many files submitted. Max files allowed: $_cgi(file,filelimit)" + } + + # read the part into a file + set foutname [file join $_cgi(tmpdir) CGI[pid].[incr _cgi(file,filecount)]] + spawn -open [open $foutname w $_cgi(tmpperms)] + set fout_sid $spawn_id + + _cgi_set_uservar $varname [list $foutname $filename $conttype] + set _cgi_userfile($varname) [list $foutname $filename $conttype] + + # This is tricky stuff - be very careful changing anything here! + # In theory, all we have to is record everything up to + # \r\n$boundary\r\n. Unfortunately, we can't simply wait on + # such a pattern because the input can overflow any possible + # buffer we might choose. We can't simply catch buffer_full + # because the boundary might straddle a buffer. I doubt that + # doing my own buffering would be any faster than taking the + # approach I've done here. + # + # The code below basically implements a simple scanner that + # keeps track of whether it's seen crlfs or pieces of them. + # The idea is that we look for crlf pairs, separated by + # things that aren't crlfs (or pieces of them). As we encounter + # things that aren't crlfs (or pieces of them), or when we decide + # they can't be, we mark them for output and resume scanning for + # new pairs. + # + # The scanner runs tolerably fast because the [...]+ pattern picks + # up most things. The \r and \n are ^-anchored so the pattern + # match is pretty fast and these don't happen that often so the + # huge \n action is executed rarely (once per line on text files). + # The null pattern is, of course, only used when everything + # else fails. + + # crlf == "\r\n" if we've seen one, else == "" + # cr == "\r" if we JUST saw one, else == "" + # Yes, strange, but so much more efficient + # that I'm willing to sacrifice readability, sigh. + # buf accumulated data between crlf pairs + + set buf "" + set cr "" + set crlf "" + + expect { + -i $fin_sid + -re "^\r" { + if {$cr == "\r"} { + append buf "\r" + } + set cr \r + exp_continue + } -re "^\n" { + if {$cr == "\r"} { + if {$crlf == "\r\n"} { + # do boundary test + if {[regexp ^[set boundary](--)?$ $buf dummy dashdash]} { + if {$dashdash == "--"} { + set eof 1 + } + } else { + # boundary test failed + if {[info exists dbg_sid]} {send -i $dbg_sid -- \r\n$buf} + send -i $fout_sid \r\n$buf ; set buf "" + set cr "" + exp_continue + } + } else { + set crlf "\r\n" + set cr "" + if {[info exists dbg_sid]} {send -i $dbg_sid -- $buf} + send -i $fout_sid -- $buf ; set buf "" + exp_continue + } + } else { + if {[info exists dbg_sid]} {send -i $dbg_sid -- $crlf$buf\n} + send -i $fout_sid -- $crlf$buf\n ; set buf "" + set crlf "" + exp_continue + } + } -re "\[^\r\n]+" { + if {$cr == "\r"} { + set buf $crlf$buf\r$expect_out(buffer) + set crlf "" + set cr "" + } else { + append buf $expect_out(buffer) + } + exp_continue + } null { + if {[info exists dbg_sid]} { + send -i $dbg_sid -- $crlf$buf$cr + send -i $dbg_sid -null + } + send -i $fout_sid -- $crlf$buf$cr ; set buf "" + send -i $fout_sid -null + set cr "" + set crlf "" + exp_continue + } eof { + set _cgi(client_error) 1 + error "Your browser failed to provide an ending boundary ($boundary) in a multipart response. Please upgrade (or fix) your browser." + } + } + exp_close -i $fout_sid ;# implicitly closes fout + exp_wait -i $fout_sid + unset fout_sid + } else { + # read the part into a variable + set val "" + expect { + -i $fin_sid + -re $linepat { + set buf $expect_out(1,string) + if {[info exists dbg_sid]} {send -i $dbg_sid -- $buf\n} + if {[regexp ^[set boundary](--)?$ $buf dummy dashdash]} { + if {$dashdash == "--"} {set eof 1} + } else { + regexp (.*)\r$ $buf dummy buf + if {0!=[string compare $val ""]} { + append val \n + } + append val $buf + exp_continue + } + } + } + _cgi_set_uservar $varname $val + } + if {[info exists eof]} break + } + if {[info exists fout]} { + exp_close -i $dbg_sid + exp_wait -i $dbg_sid + } + + # no need to close fin, fin_sid, or dbg_sid +} + +# internal routine for defining user variables +proc _cgi_set_uservar {varname val} { + global _cgi _cgi_uservar + + set exists [info exists _cgi_uservar($varname)] + set isList $exists + # anything we've seen before and is being set yet again necessarily + # has to be (or become a list) + + if {!$exists} { + lappend _cgi(uservars) $varname + } + + if {[regexp List$ $varname]} { + set isList 1 + } elseif {$exists} { + # vars that we've seen before but aren't marked as lists + # need to be "listified" so we can do appends later + if {-1 == [lsearch $_cgi(uservars,autolist) $varname]} { + # remember that we've listified it + lappend _cgi(uservars,autolist) $varname + set _cgi_uservar($varname) [list $_cgi_uservar($varname)] + } + } + if {$isList} { + lappend _cgi_uservar($varname) $val + } else { + set _cgi_uservar($varname) $val + } +} + +# export named variable +proc cgi_export {nameval} { + regexp "(\[^=]*)(=?)(.*)" $nameval dummy name q value + + if {$q != "="} { + set value [uplevel 1 set [list $name]] + } + + cgi_put "<input type=hidden name=\"$name\" value=[cgi_dquote_html $value]/>" +} + +proc cgi_export_cookie {name args} { + upvar 1 $name x + eval cgi_cookie_set [list $name=$x] $args +} + +# return list of variables available for import +# Explicit list is used to keep items in order originally found in form. +proc cgi_import_list {} { + global _cgi + + return $_cgi(uservars) +} + +# import named variable +proc cgi_import {name} { + global _cgi_uservar + upvar 1 $name var + + set var $_cgi_uservar($name) +} + +proc cgi_import_as {name tclvar} { + global _cgi_uservar + upvar 1 $tclvar var + + set var $_cgi_uservar($name) +} + +# like cgi_import but if not available, try cookie +proc cgi_import_cookie {name} { + global _cgi_uservar + upvar 1 $name var + + if {0==[catch {set var $_cgi_uservar($name)}]} return + set var [cgi_cookie_get $name] +} + +# like cgi_import but if not available, try cookie +proc cgi_import_cookie_as {name tclvar} { + global _cgi_uservar + upvar 1 $tclvar var + + if {0==[catch {set var $_cgi_uservar($name)}]} return + set var [cgi_cookie_get $name] +} + +proc cgi_import_file {type name} { + global _cgi_userfile + upvar 1 $name var + + set var $_cgi_userfile($name) + switch -- $type { + "-server" { + lindex $var 0 + } "-client" { + lindex $var 1 + } "-type" { + lindex $var 2 + } + } +} + +# deprecated, use cgi_import_file +proc cgi_import_filename {type name} { + global _cgi_userfile + upvar 1 $name var + + set var $_cgi_userfile($name) + if {$type == "-server" || $type == "-local"} { + # -local is deprecated + lindex $var 0 + } else { + lindex $var 1 + } +} + +# set the urlencoding +proc cgi_urlencoding {{encoding ""}} { + global _cgi + + set result [expr {[info exists _cgi(queryencoding)] + ? $_cgi(queryencoding) + : ""}] + + # check if the encoding is available + if {[info tclversion] >= 8.1 + && [lsearch -exact [encoding names] $encoding] != -1 } { + set _cgi(queryencoding) $encoding + } + + return $result +} + +################################################## +# button support +################################################## + +# not sure about arg handling, do we need to support "name="? +proc cgi_button {value args} { + cgi_put "<input type=button value=[cgi_dquote_html $value]" + foreach a $args { + if {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +# Derive a button from a link predefined by cgi_link +proc cgi_button_link {args} { + global _cgi_link + + set tag [lindex $args 0] + if {[llength $args] == 2} { + set label [lindex $args end] + } else { + set label $_cgi_link($tag,label) + } + + cgi_button $label onClick=$_cgi_link($tag,url) +} + +proc cgi_submit_button {{nameval {=Submit Query}} args} { + regexp "(\[^=]*)=(.*)" $nameval dummy name value + cgi_put "<input type=submit" + if {0!=[string compare "" $name]} { + cgi_put " name=\"$name\"" + } + cgi_put " value=[cgi_dquote_html $value]" + foreach a $args { + if {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + + +proc cgi_reset_button {{value Reset} args} { + cgi_put "<input type=reset value=[cgi_dquote_html $value]" + + foreach a $args { + if {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +proc cgi_radio_button {nameval args} { + regexp "(\[^=]*)=(.*)" $nameval dummy name value + + cgi_put "<input type=radio name=\"$name\" value=[cgi_dquote_html $value]" + + foreach a $args { + if {[regexp "^checked_if_equal=(.*)" $a dummy default]} { + if {0==[string compare $default $value]} { + cgi_put " checked" + } + } elseif {[regexp "^checked=(.*)" $a dummy checked]} { + # test explicitly to avoid forcing user eval + if {$checked} { + cgi_put " checked" + } + } elseif {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +proc cgi_image_button {nameval args} { + regexp "(\[^=]*)=(.*)" $nameval dummy name value + cgi_put "<input type=image" + if {0!=[string compare "" $name]} { + cgi_put " name=\"$name\"" + } + cgi_put " src=\"$value\"" + foreach a $args { + if {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +# map/area implement client-side image maps +proc cgi_map {name cmd} { + cgi_put "<map name=\"$name\">" + _cgi_close_proc_push "cgi_put </map>" + + uplevel 1 $cmd + _cgi_close_proc +} + +proc cgi_area {args} { + cgi_put "<area" + foreach a $args { + if {[regexp "^(coords|shape|href|target|onMouseOut|alt)=(.*)" $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +################################################## +# checkbox support +################################################## + +proc cgi_checkbox {nameval args} { + regexp "(\[^=]*)(=?)(.*)" $nameval dummy name q value + cgi_put "<input type=checkbox name=\"$name\"" + + if {0!=[string compare "" $value]} { + cgi_put " value=[cgi_dquote_html $value]" + } + + foreach a $args { + if {[regexp "^checked_if_equal=(.*)" $a dummy default]} { + if {0==[string compare $default $value]} { + cgi_put " checked" + } + } elseif {[regexp "^checked=(.*)" $a dummy checked]} { + # test explicitly to avoid forcing user eval + if {$checked} { + cgi_put " checked" + } + } elseif {[regexp "^onClick=(.*)" $a dummy str]} { + cgi_put " onClick=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +################################################## +# textentry support +################################################## + +proc cgi_text {nameval args} { + regexp "(\[^=]*)(=?)(.*)" $nameval dummy name q value + + cgi_put "<input name=\"$name\"" + + if {$q != "="} { + set value [uplevel 1 set [list $name]] + } + cgi_put " value=[cgi_dquote_html $value]" + + foreach a $args { + if {[regexp "^on(Select|Focus|Blur|Change)=(.*)" $a dummy event str]} { + cgi_put " on$event=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put "/>" +} + +################################################## +# textarea support +################################################## + +proc cgi_textarea {nameval args} { + regexp "(\[^=]*)(=?)(.*)" $nameval dummy name q value + + cgi_put "<textarea name=\"$name\"" + foreach a $args { + if {[regexp "^on(Select|Focus|Blur|Change)=(.*)" $a dummy event str]} { + cgi_put " on$event=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_put ">" + + if {$q != "="} { + set value [uplevel 1 set [list $name]] + } + cgi_put "[cgi_quote_html $value]</textarea>" +} + +################################################## +# file upload support +################################################## + +# for this to work, pass enctype=multipart/form-data to cgi_form +proc cgi_file_button {name args} { + global _cgi + if {[info exists _cgi(formtype)] && ("multipart/form-data" != $_cgi(form,enctype))} { + error "cgi_file_button requires that cgi_form have the argument enctype=multipart/form-data" + } + cgi_put "<input type=file name=\"$name\"[_cgi_list_to_string $args]/>" +} + +# establish a per-file limit for uploads + +proc cgi_file_limit {files chars} { + global _cgi + + set _cgi(file,filelimit) $files + set _cgi(file,charlimit) $chars +} + +################################################## +# select support +################################################## + +proc cgi_select {name args} { + cgi_put "<select name=\"$name\"" + _cgi_close_proc_push "cgi_put </select>" + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp "^on(Focus|Blur|Change)=(.*)" $a dummy event str]} { + cgi_put " on$event=\"$str\"" + } else { + if {0==[string compare multiple $a]} { + ;# sanity check + if {![regexp "List$" $name]} { + cgi_puts ">" ;# prevent error from being absorbed + error "When selecting multiple options, select variable \ + must end in \"List\" to allow the value to be \ + recognized as a list when it is processed later." + } + } + cgi_put " $a" + } + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_option {o args} { + cgi_put "<option" + set value $o + set selected 0 + foreach a $args { + if {[regexp "^selected_if_equal=(.*)" $a dummy selected_if_equal]} { + } elseif {[regexp "^value=(.*)" $a dummy value]} { + cgi_put " value=[cgi_dquote_html $value]" + } else { + cgi_put " $a" + } + } + if {[info exists selected_if_equal]} { + if {0 == [string compare $selected_if_equal $value]} { + cgi_put " selected" + } + } + cgi_puts ">[cgi_quote_html $o]</option>" +} + +################################################## +# plug-in support +################################################## + +proc cgi_embed {src wh args} { + regexp (.*)x(.*) $wh dummy width height + cgi_put "<embed src=[cgi_dquote_html $src] width=\"$width\" height=\"$height\"" + foreach a $args { + if {[regexp "^palette=(.*)" $a dummy str]} { + cgi_put " palette=\"$str\"" + } elseif {[regexp -- "-quote" $a]} { + set quote 1 + } else { + if {[info exists quote]} { + regexp "(\[^=]*)=(.*)" $a dummy var val + cgi_put " var=[cgi_dquote_html $var]" + } else { + cgi_put " $a" + } + } + } + cgi_put "/>" +} + +################################################## +# mail support +################################################## + +# mail to/from the service itself +proc cgi_mail_addr {args} { + global _cgi + + if {[llength $args]} { + set _cgi(email) [lindex $args 0] + } + return $_cgi(email) +} + +proc cgi_mail_start {to} { + global _cgi + + set _cgi(mailfile) [file join $_cgi(tmpdir) cgimail.[pid]] + set _cgi(mailfid) [open $_cgi(mailfile) w+] + set _cgi(mailto) $to + + # mail is actually sent by "nobody". To force bounce messages + # back to us, override the default return-path. + cgi_mail_add "Return-Path: <$_cgi(email)>" + cgi_mail_add "From: [cgi_name] <$_cgi(email)>" + cgi_mail_add "To: $to" +} + +# add another line to outgoing mail +# if no arg, add a blank line +proc cgi_mail_add {{arg {}}} { + global _cgi + + puts $_cgi(mailfid) $arg +} + +# end the outgoing mail and send it +proc cgi_mail_end {} { + global _cgi + + flush $_cgi(mailfid) + + foreach sendmail in $_cgi(sendmail) { + if {[file executable $sendmail]} { + exec $sendmail -t -odb < $_cgi(mailfile) + # Explanation: + # -t means: pick up recipient from body + # -odb means: deliver in background + # note: bogus local address cause sendmail to fail immediately + set sent 1 + } + } + + if {0==[info exists sent]} { + # fallback for sites without sendmail + + if {0==[info exists _cgi(mail_relay)]} { + regexp "@(.*)" $_cgi(mailto) dummy _cgi(mail_relay) + } + + set s [socket $_cgi(mail_relay) 25] + gets $s answer + if {[lindex $answer 0] != 220} {error $answer} + + puts $s "HELO [info host]";flush $s + gets $s answer + if {[lindex $answer 0] != 250} {error $answer} + + puts $s "MAIL FROM:<$_cgi(email)>";flush $s + gets $s answer + if {[lindex $answer 0] != 250} {error $answer} + + puts $s "RCPT TO:<$_cgi(mailto)>";flush $s + gets $s answer + if {[lindex $answer 0] != 250} {error $answer} + + puts $s DATA;flush $s + gets $s answer + if {[lindex $answer 0] != 354} {error $answer} + + seek $_cgi(mailfid) 0 start + puts $s [read $_cgi(mailfid)];flush $s + puts $s .;flush $s + gets $s answer + if {[lindex $answer 0] != 250} {error $answer} + + close $s + } + close $_cgi(mailfid) + file delete -force $_cgi(mailfile) +} + +proc cgi_mail_relay {host} { + global _cgi + + set _cgi(mail_relay) $host +} + +proc cgi_sendmail {path} { + global _cgi + + set _cgi(sendmail) $path +} + +################################################## +# cookie support +################################################## + +# calls to cookie_set look like this: +# cgi_cookie_set user=don domain=nist.gov expires=never +# cgi_cookie_set user=don domain=nist.gov expires=now +# cgi_cookie_set user=don domain=nist.gov expires=...actual date... + +proc cgi_cookie_set {nameval args} { + global _cgi + + if {![info exists _cgi(http_head_in_progress)]} { + error "Cookies must be set from within cgi_http_head." + } + cgi_puts -nonewline "Set-Cookie: [cgi_cookie_encode $nameval];" + + foreach a $args { + if {[regexp "^expires=(.*)" $a dummy expiration]} { + if {0==[string compare $expiration "never"]} { + set expiration "Friday, 11-Jan-2038 23:59:59 GMT" + } elseif {0==[string compare $expiration "now"]} { + set expiration "Friday, 31-Dec-1990 23:59:59 GMT" + } + cgi_puts -nonewline " expires=$expiration;" + } elseif {[regexp "^(domain|path)=(.*)" $a dummy attr str]} { + cgi_puts -nonewline " $attr=[cgi_cookie_encode $str];" + } elseif {[regexp "^secure$" $a]} { + cgi_puts -nonewline " secure;" + } + } + cgi_puts "" +} + +# return list of cookies available for import +proc cgi_cookie_list {} { + global _cgi_cookie + + array names _cgi_cookie +} + +proc cgi_cookie_get {args} { + global _cgi_cookie + + set all 0 + + set flag [lindex $args 0] + if {$flag == "-all"} { + set args [lrange $args 1 end] + set all 1 + } + set name [lindex $args 0] + + if {$all} { + global _cgi_cookie_shadowed + + if {[info exists _cgi_cookie_shadowed($name)]} { + return [concat $_cgi_cookie($name) $_cgi_cookie_shadowed($name)] + } else { + return [concat $_cgi_cookie($name)] + } + } + return $_cgi_cookie($name) +} + +proc cgi_cookie_encode {in} { + regsub -all " " $in "+" in + regsub -all "%" $in "%25" in ;# must preceed other subs that produce % + regsub -all ";" $in "%3B" in + regsub -all "," $in "%2C" in + regsub -all "\n" $in "%0D%0A" in + return $in +} + +################################################## +# table support +################################################## + +proc cgi_table {args} { + cgi_put "<table" + _cgi_close_proc_push "cgi_put </table>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_caption {args} { + cgi_put "<caption" + _cgi_close_proc_push "cgi_put </caption>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_table_row {args} { + cgi_put "<tr" + _cgi_close_proc_push "cgi_put </tr>" + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +# like table_row but without eval +proc cgi_tr {args} { + cgi_put <tr + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + foreach i [lindex $args end] { + cgi_td $i + } + cgi_put </tr> +} + +proc cgi_table_head {args} { + cgi_put "<th" + _cgi_close_proc_push "cgi_put </th>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +# like table_head but without eval +proc cgi_th {args} { + cgi_put "<th" + + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">[lindex $args end]</th>" +} + +proc cgi_table_data {args} { + cgi_put "<td" + _cgi_close_proc_push "cgi_put </td>" + + if {[llength $args]} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +# like table_data but without eval +proc cgi_td {args} { + cgi_put "<td" + + if {[llength $args] > 1} { + cgi_put "[_cgi_lrange $args 0 [expr [llength $args]-2]]" + } + cgi_put ">[lindex $args end]</td>" +} + +################################################## +# stylesheets - not yet documented +################################################## + +proc cgi_stylesheet {href} { + cgi_puts "<link rel=stylesheet href=\"$href\" type=\"text/css\"/>" +} + +proc cgi_span {args} { + set buf "<span" + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp "style=(.*)" $a dummy str]} { + append buf " style=\"$str\"" + } elseif {[regexp "class=(.*)" $a dummy str]} { + append buf " class=\"$str\"" + } else { + append buf " $a" + } + } + return "$buf>[lindex $args end]</span>" +} + +################################################## +# frames +################################################## + +proc cgi_frameset {args} { + cgi_head ;# force it out, just in case none + + cgi_put "<frameset" + _cgi_close_proc_push "cgi_puts </frameset>" + + foreach a [lrange $args 0 [expr [llength $args]-2]] { + if {[regexp "^(rows|cols|onUnload|onLoad|onBlur)=(.*)" $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_puts ">" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +proc cgi_frame {namesrc args} { + cgi_put "<frame" + + regexp "(\[^=]*)(=?)(.*)" $namesrc dummy name q src + + if {$name != ""} { + cgi_put " name=\"$name\"" + } + + if {$src != ""} { + cgi_put " src=\"$src\"" + } + + foreach a $args { + if {[regexp "^(marginwidth|marginheight|scrolling|onFocus)=(.*)" $a dummy attr str]} { + cgi_put " $attr=\"$str\"" + } else { + cgi_put " $a" + } + } + cgi_puts "/>" +} + +proc cgi_noframes {args} { + cgi_puts "<noframes>" + _cgi_close_proc_push "cgi_puts </noframes>" + uplevel 1 [lindex $args end] + _cgi_close_proc +} + +################################################## +# admin support +################################################## + +# mail address of the administrator +proc cgi_admin_mail_addr {args} { + global _cgi + + if {[llength $args]} { + set _cgi(admin_email) [lindex $args 0] + } + return $_cgi(admin_email) +} + +################################################## +# if possible, make each cmd available without cgi_ prefix +################################################## + +if {[info tclversion] >= 7.5} { + foreach _cgi(old) [info procs cgi_*] { + regexp "^cgi_(.*)" $_cgi(old) _cgi(dummy) _cgi(new) + if {[llength [info commands $_cgi(new)]]} continue + interp alias {} $_cgi(new) {} $_cgi(old) + } +} else { + foreach _cgi(old) [info procs cgi_*] { + regexp "^cgi_(.*)" $_cgi(old) _cgi(dummy) _cgi(new) + if {[llength [info commands $_cgi(new)]]} continue + proc $_cgi(new) {args} "uplevel 1 $_cgi(old) \$args" + } +} + +################################################## +# internal utilities +################################################## + +# undo Tcl's quoting due to list protection +# This leaves a space at the beginning if the string is non-null +# but this is always desirable in the HTML context in which it is called +# and the resulting HTML looks more readable. +# (It makes the Tcl callers a little less readable - however, there aren't +# more than a handful and they're all right here, so we'll live with it.) +proc _cgi_list_to_string {list} { + set string "" + foreach l $list { + append string " $l" + } + # remove first space if possible + # regexp "^ ?(.*)" $string dummy string + return $string +} + +# do lrange but return as string +# needed for stuff like: cgi_puts "[_cgi_lrange $args ...] +# Like _cgi_list_to_string, also returns string with initial blank if non-null +proc _cgi_lrange {list i1 i2} { + _cgi_list_to_string [lrange $list $i1 $i2] +} + +################################################## +# temporary file procedures +################################################## + +# set appropriate temporary file modes +proc cgi_tmpfile_permissions {{mode ""}} { + global _cgi + + if {[string length $mode]} { + set _cgi(tmpperms) $mode + } + + return $_cgi(tmpperms) +} + +################################################## +# user-defined procedures +################################################## + +# User-defined procedure called immediately after <body> +# Good mechanism for controlling things such as if all of your pages +# start with the same graphic or other boilerplate. +proc app_body_start {} {} + +# User-defined procedure called just before </body> +# Good place to generate signature lines, last-updated-by, etc. +proc app_body_end {} {} + +proc cgi_puts {args} { + eval puts $args +} + +# User-defined procedure to generate DOCTYPE declaration +proc cgi_doctype {} {} + +################################################## +# do some initialization +################################################## + +# cgi_init initializes to a known state. + +proc cgi_init {} { + global _cgi + unset _cgi + + # set explicitly for speed + set _cgi(debug) -off + set _cgi(buffer_nl) "\n" + + cgi_name "" + cgi_root "" + cgi_body_args "" + cgi_file_limit 10 100000000 + + if {[info tclversion] >= 8.1} { + # set initial urlencoding + if { [lsearch -exact [encoding names] "utf-8"] != -1} { + cgi_urlencoding "utf-8" + } else { + cgi_urlencoding [encoding system] + } + } + + # email addr of person responsible for this service + cgi_admin_mail_addr "root" ;# you should override this! + + # most services won't have an actual email addr + cgi_mail_addr "CGI script - do not reply" +} +cgi_init + +# deduce tmp directory +switch $tcl_platform(platform) { + unix { + set _cgi(tmpdir) /tmp + set _cgi(tmpperms) 0644 + set _cgi(sendmail) [list /usr/lib/sendmail /usr/sbin/sendmail] + } macintosh { + set _cgi(tmpdir) [pwd] + set _cgi(tmpperms) {} + set _cgi(sendmail) {} + } default { + set _cgi(tmpdir) [pwd] + catch {set _cgi(tmpdir) $env(TMP)} + catch {set _cgi(tmpdir) $env(TEMP)} + set _cgi(tmpperms) {} + set _cgi(sendmail) {} + } +} + +# regexp for matching attr=val +set _cgi(attr,regexp) "^(\[^=]*)=(\[^\"].*)" + +package provide cgi @CGI_VERSION_FULL@ diff --git a/web/src/cgi.tcl-1.10/cgi.tcl.man b/web/src/cgi.tcl-1.10/cgi.tcl.man new file mode 100644 index 00000000..c121800b --- /dev/null +++ b/web/src/cgi.tcl-1.10/cgi.tcl.man @@ -0,0 +1,36 @@ +.TH CGI.TCL 3 "12 December 1995" +.SH NAME +cgi.tcl \- procedures for CGI scripting in Tcl +.SH DESCRIPTION + +These routines implement the code described in the paper "Writing CGI +scripts in Tcl" which appeared in the Tcl '96 conference. + +This man page is really just a placeholder. See the README for more +info. + +.SH SYNOPSIS +.nf + +source cgi.tcl + +more to come... + +.fi +No attempt is made to explain all aspects of the code. The paper is +the right way to get started. After that, read the code \- the code +really is quite straightforward. Feel free to make changes to it. +Experiment. No claims of completeness are made. (In fact, I can +assure you that there are missing pieces - there are things in CGI +that I find utterly useless so I didn't bother to support them.) + +More to come... + +.SH SEE ALSO +.SH AUTHOR +Don Libes, libes@nist.gov, National Institute of Standards and Technology +.SH ACKNOWLEDGEMENTS +Design and implementation of the this software was paid for by the +U.S. government and is therefore in the public domain. However the +author and NIST would like credit if this program and documentation or +portions of them are used. diff --git a/web/src/cgi.tcl-1.10/configure b/web/src/cgi.tcl-1.10/configure new file mode 100755 index 00000000..1c167432 --- /dev/null +++ b/web/src/cgi.tcl-1.10/configure @@ -0,0 +1,2291 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="Makefile.in" +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CGI_MAJOR_VERSION CGI_MINOR_VERSION CGI_MICRO_VERSION CGI_VERSION_FULL CGI_VERSION CGI_LIB_FILE CGI_LIB_FILES CGI_TCL_EXECUTABLE LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + +CGI_MAJOR_VERSION=1 +CGI_MINOR_VERSION=10 +CGI_MICRO_VERSION=0 +CGI_VERSION=$CGI_MAJOR_VERSION.$CGI_MINOR_VERSION +CGI_VERSION_FULL=$CGI_VERSION.$CGI_MICRO_VERSION + +# If `configure' is invoked (in)directly via `make', ensure that it +# encounters no `make' conflicts. +# +unset MFLAGS MAKEFLAGS + +# this'll use a BSD compatible install or our included install-sh +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Find a usable Tcl executable so that we can run Tcl utilities +# For simplicity, assume Tcl is completely installed. +echo "$as_me:$LINENO: checking for usable Tcl executable" >&5 +echo $ECHO_N "checking for usable Tcl executable... $ECHO_C" >&6 +for i in \ + ${exec_prefix}/bin/tclsh \ + `ls -r ${exec_prefix}/bin/tclsh[8-9]* 2>/dev/null` \ + ${prefix}/bin/tclsh \ + `ls -r ${prefix}/bin/tclsh[8-9]* 2>/dev/null` \ + ${srcdir}/../tcl/unix/tclsh \ + `ls -dr ${srcdir}/../tcl[8-9]*/unix/tclsh 2>/dev/null` \ + /usr/local/bin/tclsh \ + /usr/bin/tclsh ; do + if test -x "$i" ; then + CGI_TCL_EXECUTABLE=$i + break + fi +done +if test "x$CGI_TCL_EXECUTABLE" = "x" ; then + { { echo "$as_me:$LINENO: error: no tcl executable found, cannot install" >&5 +echo "$as_me: error: no tcl executable found, cannot install" >&2;} + { (exit 1); exit 1; }; } +else + echo "$as_me:$LINENO: result: $CGI_TCL_EXECUTABLE" >&5 +echo "${ECHO_T}$CGI_TCL_EXECUTABLE" >&6 +fi + +# +# Set up makefile substitutions +# + + + + + + + + + ac_config_files="$ac_config_files Makefile cgi.tcl version" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "cgi.tcl" ) CONFIG_FILES="$CONFIG_FILES cgi.tcl" ;; + "version" ) CONFIG_FILES="$CONFIG_FILES version" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CGI_MAJOR_VERSION@,$CGI_MAJOR_VERSION,;t t +s,@CGI_MINOR_VERSION@,$CGI_MINOR_VERSION,;t t +s,@CGI_MICRO_VERSION@,$CGI_MICRO_VERSION,;t t +s,@CGI_VERSION_FULL@,$CGI_VERSION_FULL,;t t +s,@CGI_VERSION@,$CGI_VERSION,;t t +s,@CGI_LIB_FILE@,$CGI_LIB_FILE,;t t +s,@CGI_LIB_FILES@,$CGI_LIB_FILES,;t t +s,@CGI_TCL_EXECUTABLE@,$CGI_TCL_EXECUTABLE,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/web/src/cgi.tcl-1.10/configure.in b/web/src/cgi.tcl-1.10/configure.in new file mode 100644 index 00000000..7b7f6880 --- /dev/null +++ b/web/src/cgi.tcl-1.10/configure.in @@ -0,0 +1,52 @@ +# Process this file with autoconf to produce a configure script. + +AC_INIT(Makefile.in) +CGI_MAJOR_VERSION=1 +CGI_MINOR_VERSION=10 +CGI_MICRO_VERSION=0 +CGI_VERSION=$CGI_MAJOR_VERSION.$CGI_MINOR_VERSION +CGI_VERSION_FULL=$CGI_VERSION.$CGI_MICRO_VERSION + +# If `configure' is invoked (in)directly via `make', ensure that it +# encounters no `make' conflicts. +# +unset MFLAGS MAKEFLAGS + +# this'll use a BSD compatible install or our included install-sh +AC_PROG_INSTALL + +# Find a usable Tcl executable so that we can run Tcl utilities +# For simplicity, assume Tcl is completely installed. +AC_MSG_CHECKING([for usable Tcl executable]) +for i in \ + ${exec_prefix}/bin/tclsh \ + `ls -r ${exec_prefix}/bin/tclsh[[8-9]]* 2>/dev/null` \ + ${prefix}/bin/tclsh \ + `ls -r ${prefix}/bin/tclsh[[8-9]]* 2>/dev/null` \ + ${srcdir}/../tcl/unix/tclsh \ + `ls -dr ${srcdir}/../tcl[[8-9]]*/unix/tclsh 2>/dev/null` \ + /usr/local/bin/tclsh \ + /usr/bin/tclsh ; do + if test -x "$i" ; then + CGI_TCL_EXECUTABLE=$i + break + fi +done +if test "x$CGI_TCL_EXECUTABLE" = "x" ; then + AC_MSG_ERROR([no tcl executable found, cannot install]) +else + AC_MSG_RESULT($CGI_TCL_EXECUTABLE) +fi + +# +# Set up makefile substitutions +# +AC_SUBST(CGI_MAJOR_VERSION) +AC_SUBST(CGI_MINOR_VERSION) +AC_SUBST(CGI_MICRO_VERSION) +AC_SUBST(CGI_VERSION_FULL) +AC_SUBST(CGI_VERSION) +AC_SUBST(CGI_LIB_FILE) +AC_SUBST(CGI_LIB_FILES) +AC_SUBST(CGI_TCL_EXECUTABLE) +AC_OUTPUT(Makefile cgi.tcl version) diff --git a/web/src/cgi.tcl-1.10/doc/ref.txt b/web/src/cgi.tcl-1.10/doc/ref.txt new file mode 100644 index 00000000..79ddd721 --- /dev/null +++ b/web/src/cgi.tcl-1.10/doc/ref.txt @@ -0,0 +1,1651 @@ +cgi.tcl - A Reference Manual (Draft) +by Don Libes + +This document contains technical notes on using cgi.tcl. This +document is a draft and has not been officially reviewed. + +This document assumes that you have read the Tcl '96 paper "CGI +Scripting in Tcl". That document will give you the feel for what this +code is all about. In contrast, this document provides the details. + +This document assumes you know HTML. I'm not going to explain what +particular tags do or how to use them effectively, except as necessary +to understand the document. + +Some of the commands may not work with all browsers. For example, the +cgi_center command is generally understood only by some Netscape +browsers because it produces <center></center> tags which are not +commonly supported. You'll have to use your judgement. Remember: +Just because a command exists to produce the HTML doesn't mean your +browser will do anything meaningful with it. In that sense, using +this code is no different than handcoding HTML. + +************************************************** +A NOTE ABOUT PROCEDURE NAMES +************************************************** + +All procedures are named cgi_XXX. You can also call them without the +cgi_ prefix. Using the cgi_XXX form is no big deal for rarely used +procedures, but the aliases are particularly convenient for things +like hr and br. Aliases are suppressed if procedures exist by those +names already. (Thus, cgi_eval cannot be invoked as "eval"!) +Similarly, you can overwrite the aliases with impunity. Internally, +references are only made to the cgi_ names. + +I'm still thinking about this. If you have strong feelings about it, +let me know. + +************************************************** +SECURITY +************************************************** + +I frequently see statements saying that Tcl (and other interpretive +languages, for that matter) are insecure and should not be used for +writing CGI. + +I disagree. It is possible to use Tcl securely and it really isn't +very hard. The key, of course, is to not blindly evaluate user input. +There really isn't much reason to. For instance, this library itself +is pretty big and does lots of things, but nothing in it evaluates +user input. (It does do a lot of evaluation of *programmer* input, +but that's quite acceptable.) + +The two classes of commands you should pay close attention to are +commands that do eval operations and commands that invoke external +programs. + +************************************************** +GENERAL NOTES ABOUT PARAMETERS +************************************************** + +** There are several basic styles of parameter passing. + +-- Container commands (e.g., <body></body>, <div></div>, etc.) + +The last argument is typically a block of code. Other arguments +become attributes. For example: + + cgi_body bgcolor=red background=white { + h4 "hello" + } + +produces: + + <body bgcolor="red" background="white"> + <h4>hello</h4> + </body> + +-- Commands with required arguments + +Some commands have required arguments. Required arguments which are +relatively long, are passed *after* all others. For example: + + cgi_h4 align=left "Foo's Bar & Grill" + +Another example: + + cgi_body bgcolor=red background=white { + cgi_h4 "Foo's Bar & Grill" + } + +Commands with relatively short arguments have the short arguments +passed *before* all others. This avoids many redundant keywords. In +the following example, the "img=" is omitted because it is already +implied by the command. The "alt=" is not optional (although the +entire argument is). + + cgi_img foo.gif "alt=Foo's Bar & Grill" + +Note the quotes around the alt argument. This is only necessary if +the argument has whitespace in it - a consequence of Tcl's normal +scanning rules. The resulting HTML automatically includes quotes +around the value attribute. (See Case-sensitivity.) + +** Case-sensitivity and Quotes and Whitespace + +Attribute names are case sensitive. Use lowercase names for "normal" +handling. For example, values for attributes such as "url" and +"value" are quoted and encoded. Use uppercase names to suppress the +usual processing. (For example, you might want to test how a browser +responds to incorrect HTML.) + +Consider: + + cgi_body bgcolor=#123456 { + p [cgi_img foo.gif "alt=Foo's Bar & Grill"] + } + +This is translated to + + <body bgcolor="#123456"> + <p><img src="foo.gif" alt="Foo's Bar & Grill"></p> + </body> + +Notice how the ampersand in the alt value has been encoded. Also +notice how quotes have been added to the values of bgcolor, url, and +alt. Thus you no longer have to add quotes all over the place (or +remember when you need to). + +Embedded whitespace is protected by quoting in the usual Tcl fashion +rather than typical HTML fashion. + +So instead of: + img foo.gif alt="foo bar" +do this: + img foo.gif "alt=foo bar" +which will return HTML that is properly quoted: + <img src="foo.gif" alt="foo bar"> + +-- Name-value commands + +Many commands produce tags that use "name" and "value" attributes. +Because these attributes are almost always used in such commands, the +first argument is always of the form name=value so the literal "name" +and "value" can be omitted. For example: + + cgi_text color=Red size=5 + +produces: + + <input name="color" value="Red" size=5> + +Reasonable defaults exist. For example, if you don't need the value +of a submit button (but the user still needs to see it appear as the +label), omit the name: + + cgi_submit_button =Execute + +If no "=" is present, the string is assumed to be the "name" +attribute. For example: + + cgi_checkbox Vegies + +produces a checkbox associated with the variable named "Vegies". +(With no specified value, it will be set to "on" if checked.) + +Most of the commands have reasonable defaults. For example, to +quickly script a submit button, the following suffices: + + cgi_submit_button + +Certain constructions make no sense and are therefore disallowed. For +example, a submit button with a name but no value makes no sense, so +cgi_submit_button doesn't allow it. (In other words, if you provide +an argument, it has to have "=" in it.) + +************************************************** +JAVASCRIPT ARGUMENTS +************************************************** + +JavaScript event attributes such as onClick are handled just like any +other attributes in terms of quoting and case sensitivity. Because +there are so many attributes on so many tags, they are not documented +explicitly in this manual. However, they are all supported. Here is +an example: + + cgi_text age=18 onChange=MinimumAge(this.form.age) + +************************************************** +PROCEDURES TO ASSIST IN DEBUGGING +************************************************** + +** User-id differences + +You can interactively run and debug CGI scripts by simply running them +from the shell, or a Tcl or C debugger. (For convenience, I use +Expect instead of tclsh just so that I get the debugger.) In fact, +I've never had to resort to the C debugger. However, simply watching +the raw output from a shell is very handy. This catches the really +basic errors such as incorrect protections, incorrect #! line, etc. +Once your script is actually executing, you can rely on cgi_eval (see +below). + +cgi_uid_check user + +Typically, a CGI script is intended to run from a particular uid, such +as "nobody". If you run such scripts interactively, you can end up +with conflicts. For example, if the script creates files, files can +accidentally end up being owned by you. + +cgi_uid_check is a convenient mechanism to warn against this problem. +Simply call cgi_uid_check in your script. The argument is the uid +under which the script should be running. If the given uid does +not match the actual uid, cgi_uid_check will generate an error. + +** Trapping error messages + +cgi_eval + +cgi_eval is the primary error catching/reporting mechanism. Execute +commands from cgi_eval so that errors can be caught and reported in a +nice way. By default, errors are emailed back to the administrator. +"cgi_debug -on" makes errors be immediately viewable in the browser. + +If an error is caught when debugging is enabled, the diagnostic is +anchored with #cgierror. This is useful in scripts that produce +voluminous output. + +cgi_error_occurred + +cgi_error_occurred returns 1 if an error occurred and was caught by +cgi_eval. This separate function simplifies exit handling - for +example, rather than always checking the return value of cgi_eval, an +app can just test this from a redefined exit. + +cgi_admin_mail_addr addr + +cgi_admin_mail_addr sets the administrator's email address. +Diagnostics are sent via email if a problem is encountered with the +script and debugging is not enabled. + +cgi_name name + +cgi_name defines a name for the service. If called with no arguments, +the name is returned. The name is currently used in the following +places: + + If email is sent, it comes from [cgi_name]. + If errors are emailed, the subject is "[cgi_name]: CGI problem" + +** Generating debugging output and other commands + +cgi_debug args + +cgi_debug provides rudimentary support for generating debugging +messages. Here are some example calls: + +cgi_debug cmd + If debugging is on, the command is evaluated. For example: + + cgi_debug { + h2 "completed initialization" + } + or + cgi_debug {h2 "completed initialization"} + + Note this is more than simply calling h2. Context is rewound + or forwarded to get to a place where this is safe. (And + conversely, this call can suppress things such as header + elements that haven't been processed yet.) The flag + "-noprint" suppresses this manipulation - this is useful for + early code that causes no printing. + + The -- flag causes the next argument to treated as a command + even if it looks like another flag. +cgi_debug -on + Enables debugging messages. This includes debugging messages + generated by explicit calls to cgi_debug as well as implicit + diagnostics, for example, that report on form input. +cgi_debug -temp text + Enable debugging for this one line. +cgi_debug -off + Disable debugging. + +cgi_debug always returns the old setting ("-on" or "-off"). The +initial value is -off. + + +** Printing arrays + +cgi_parray arrayname + +cgi_parray prints out the elements of a Tcl array. cgi_parray is just +like Tcl's parray except that its output is appropriately formatted +for a browser. + +************************************************** +BASIC STRUCTURE OF A CGI SCRIPT +************************************************** + +Typically, the basic structure of most CGI scripts is: + + package require cgi + + cgi_eval { + cgi_http_head {cmds} + cgi_html { + cgi_head {cmds} + cgi_body {cmds} + } + } + +Much of this can be omitted, however. In fact, a typical script looks +more like this: + + package require cgi + + cgi_eval { + cgi_title "title" + cgi_body { + cmds + } + } + +(If you're not using the Tcl package support, replace the 'package +require' command with a 'source' command of the specific file +containing the cgi.tcl source.) + +(The "...." in the examples above should be replaced by the true path +to the cgi.tcl file.) + +I'll now go through each of these in more detail as well as some other +possibilities for the overall structure. + +************************************************** +HTTP HEADERS +************************************************** + +cgi_http_head cmds + +CGI scripts must produce various headers to explain how the remainder +of the output is to be interpreted. No other output may preceed this! + +With no argument, an HTML content type is produced if the script is +running in the CGI environment. This means that most people need not +bother calling cgi_http_head. However, if you want to see the HTTP +headers and you are not running in the CGI environment, you should +call cgi_http_head explicitly. (Alternatively, you can make it appear +that you are in the CGI environment by defining the environment +variable REQUEST_METHOD.) + +The remaining commands in this section may be used in cgi_http_head. +Most should be intuitively obvious and thus need no explanation. + +cgi_content_type type + Generates a "Content-type:" header. + +With no argument, cgi_content_type generates a declaration for HTML. +If specified, the 'type' argument should be the full MIME-style +type/subtype declaration. Any MIME-style parameters should be +included in the type argument. + +cgi_redirect location + Generates a redirect header (Status:/Location:/URI:) +cgi_target + Generates a "Window-target:" header. +cgi_refresh seconds url + Generates a "Refresh:" header. The url argument is optional. +cgi_pragma pragma + Generates a "Pragma:" header. +cgi_status number string + Generates a "Status:" header. + +** Cookies + +cgi_cookie_set name=val args + Define a cookie with given name, value, and other arguments. + Cookie values are automatically encoded to protect odd characters. + A couple expirations are predefined (with intuitive meaning): + expires=never + expires=now + expires=...actual date... + + Here are some examples: + cgi_cookie_set user=don domain=nist.gov expires=never + cgi_cookie_set user=don expires=now secure + +cgi_export_cookie name args + Export the named Tcl variable as a cookie. Other arguments are + processed as with cgi_cookie_set. + +Cookies may be read only after calling cgi_input. The following +routines read cookie names or specific cookies. + +cgi_cookie_list + Returns the list of all cookies supplied by the server. + +cgi_cookie_get name + Returns the value of the named cookie. If multiple values exists + the most specific path mapping is used. + + If the "-all" flag is used (before the cookie name), a list is + returned containing all cookie values for the given name. The + list is ordered most-specific (path mapping) to least. I.e., + the first value on the list is the same one returned by + calling cgi_cookie get without a flag. + +cgi_import_cookie name + Define a Tcl variable with the value of the cookie of the same + name. For example, the following command retrieves the cookie + named "Password" and stores it in the Tcl variable "Password". + + cgi_import_cookie Password + + +************************************************** +GENERATING HTML +************************************************** + +cgi_html + +<html></html> tags can be generated using cgi_html. An argument to +cgi_html is evaluated to produce the actual HTML code. + +In practice, it is not necessary to use cgi_html. CGI.tcl will +automatically generate the tags when appropriate. (Oddly, modern HTML +specs don't require it and most if not all browsers never cared +anyway.) + +cgi_doctype + +cgi_doctype is a user-defined procedure that produces a SGML DOCTYPE +declaration. If it exists, cgi_doctype is automatically invoked at +the beginning of cgi_html. (This library does not automatically create +DOCTYPE declarations since the library is not restricted to generating +SGML for any single DTD. Realistically, DOCTYPEs are pointless for +HTML generation since web browsers don't require DOCTYPE declarations. +However, if you are creating pages for some other purpose that +requires such a declaration, use cgi_doctype.) + +cgi_head + +<head></head> tags can be generated using cgi_head. An argument to +cgi_head is evaluated to produce the actual headers. + +In practice, it is not necessary to use cgi_head. CGI.tcl will +automatically generate the tags when appropriate. (Oddly, modern HTML +specs don't require it and most if not all browsers never cared +anyway. So for example: + + cgi_head { + cgi_title "my page" + } + +is equivalent to: + + cgi_title "my page" + +Note that cgi_title will be called automatically if you omit +cgi_title, cgi_head, or call cgi_head with no arguments. + +cgi_title title + +cgi_title defines the title of a page. It is called from within a +<head></head> pair. If not called from within cgi_head, it implicitly +forces it to occur. + +cgi_title always returns the title. With no argument, cgi_title +returns the old title without changing it. + +cgi_http_equiv + +cgi_http_equiv is equivalent to cgi_http_head but from within +cgi_head. This procedure is defined for completeness - there is no +reason to use it. In fact, it doesn't allow all cgi_http_head +declarations, so it should be avoided. + +cgi_meta + +cgi_meta generates a <meta> tag. You can do whatever you want with +these. (Read some an HTML document for more info.) For example: + + meta name=author {content="Don Libes"} + +cgi_script cmd + +cgi_script evaluates its arguments inside of <script></script> tags. +This is appropriate for putting in client-side scripting. Optional +arguments are passed as attributes to the <script> tag. + +Note that the cmd argument is a Tcl command, not a command in the +other scripting language. So if all you want to do is print out some +script, use cgi_puts: + + cgi_script { + cgi_puts { + some scripting stuff + in whatever weird funky + language you want + } +} + +cgi_javascript cmd + +cgi_javascript is a version of cgi_script specialized for javascript. +At present, all it does is add the comment hacks so that the +javascript can't be seen by old browsers. + +cgi_noscript cmd + +cgi_noscript evaluates its argument to generate code for browsers that +do not understand cgi_script or its variants. + +cgi_body + +<body></body> tags are generated using cgi_body. An argument to +cgi_body is evaluated to produce the actual body. + +Executing "return" from within cgi_body causes cgi_body to return. +This is useful if more code follows the cgi_body within the cgi_eval. +Compare to cgi_exit (see elsewhere). + +cgi_body_args + +Arguments to cgi_body_args are made available to cgi_body as if they +had been specified in the call to cgi_body. This provides a +convenient way for using the same colors, backgrounds, etc, in a set +of pages. + +cgi_exit + +cgi_exit provides a fast way of cleanly exiting a CGI script without +having to manually unwind procedures. In particular, cgi_exit forces +closure of all open tags. It then calls exit. This is useful if you +want to exit from a CGI script at any point and still have the HTML be +correct. + +** Frames + +cgi_frameset cmd + +Instead of cgi_body, you can call cgi_frameset to create framed +documents. This produces <frameset></frameset> tags with the content +filled by evaluation of cmd. Optional arguments are passed on as +attributes. + +cgi_frame name=url + +cgi_frame defines a frame with the given name and url. The argument +handling is the same as for other name-value commands (even though the +value here is a url). The url is automatically double-quoted. Other +optional arguments are passed on as attributes. + +cgi_noframes cmd + +cgi_noframes produces <noframes></noframes> tags with the content +filled evaluation of cmd. Optional arguments are passed on as +attributes. + +************************************************** +CONTAINER SUPPORT +************************************************** + +cgi_division + +cgi_division evaluates its last argument, grouping it together. This +is useful for acting on a group of paragraphs, such as for alignment +purposes. + +cgi_center + +cgi_center is similar to "cgi_division align=center". + +************************************************** +SINGLE PARAGRAPH SUPPORT +************************************************** + +Everything in this section generates a single paragraph or line break. +Most of these take a string as the last argument which is +appropriately formatted. Any other arguments are used as tag +attributes. + +cgi_p +cgi_address +cgi_blockquote +cgi_h1 through h7 + +Most of these procedures should be intuitive. They all take a string +and display it in the appropriate way. For example, a level 2 +heading: + + h2 "Paragraph Support" + +Here's a paragraph with some formatting (see next section for more +info): + + p "I [bold love] Tcl but hate [blink "blinking text"]" + +Note that some of these generate tags that are not supported by all +browsers. See the format-tour.cgi script to see these in use. + +cgi_br + +cgi_br causes a paragraph break to be printed. Additional arguments +are passed on as attributes. + +To embed a paragraph break (rather than printing it), use cgi_nl. In +the following example, it is much more convenient to call cgi_br than +cgi_nl: + + radio_button "version=1" + br + radio_button "version=2" + +See cgi_nl for more info. + +************************************************** +TEXT SUPPORT +************************************************** + +The following procedures take a string and return an appropriately +formatted version. The string is always the last argument. Any other +arguments are used as tag attributes. + +cgi_bold +cgi_italic +cgi_underline +cgi_strikeout +cgi_subscript +cgi_superscript +cgi_typewriter +cgi_blink +cgi_emphasis +cgi_strong +cgi_cite +cgi_sample +cgi_keyboard +cgi_variable +cgi_definition +cgi_big +cgi_small +cgi_font + + p "I [bold love] Tcl but hate [blink "blinking text"]" + +Note that some of these generate tags that are not supported by all +browsers. See the format-tour.cgi script to see these in use. + +cgi_basefont + +cgi_basefont defines the base font. + +************************************************** +SPECIAL CHARACTERS OR CHARACTER SEQUENCES +************************************************** + +The following procedures produce characters such that when interpreted +by a browser returns the indicated character. + + Returns +cgi_lt < +cgi_gt > +cgi_amp & +cgi_quote " +cgi_enspace en space +cgi_emspace em space +cgi_nbspace nonbreaking space +cgi_tm registered trademark +cgi_copyright copyright +cgi_isochar n ISO character #n + +cgi_nl + +cgi_nl returns a paragraph break string suitable for embedding in a +string just as you would embed a newline in a Tcl string via \n. + +To print a paragraph break rather than returning it, use cgi_br. In +the following example, it is much more convenient to call cgi_nl than +than cgi_br: + + h2 "This appears[nl]on two lines." + +See cgi_br for more info. + +cgi_breakable + +cgi_breakable indicates a place in a word at which the browser can +break a string across two lines. + +cgi_unbreakable cmd + +cgi_unbreakable evaluates a cmd in such a way that the output will not +be broken across lines by the browser just because the screen width is +exceeded. Instead a horizontal scrollbar will appear so that the +browser can be manually scrolled to see the long line. +n +cgi_unbreakable_string string + +cgi_unbreakable_string returns its arguments so that it will not be +broken across lines by the browser just because the screen width is +exceeded. Instead a horizontal scrollbar will appear so that the +browser can be manually scrolled to see the long line. + +Notes: + +- It is my assumption that cgi_unbreakable will be much more commonly +used than the _string version, hence the choice of names. Feel free +to let me know what I'm wrong. + +- I have seen browsers handle unbreakables incorrectly, particularly +in interaction with other features. If you can't get your +unbreakables to behave correctly, consider alternative layouts or +alternative HTML. For example, unbreakable table data should be done +using "table_data nowrap". I have no idea why but it works whereas +unbreakable causes the table rows to overlap. Clearly, this is a +browser bug. + +************************************************** +FORMS +************************************************** + +cgi_form action args cmd + +cgi_form defines a form. The form is populated by executing the +command (last argument of cgi_form). action defines the url to +process the form. Any other arguments are passed as attributes. +A typical call looks like this: + + cgi_form response { + .... + } + +Here "response" names the URL to process the form. If the URL does +not begin with a protocol name (such as "http:"), a common root is +prepended and ".cgi" is appended. This can be changed by redefining +the procedure cgi_cgi. + +cgi_root + +cgi_root defines the common root used by cgi_form (see above). +For example: + + cgi_root "http://www.nist.gov/cgi-bin/cgi.tcl-examples" + +With one argument, cgi_root returns the new root. With no arguments, +cgi_root returns the old root. + +cgi_suffix + +cgi_suffix defines the common suffix used by cgi_cgi and anything that +uses it such as cgi_form. The default suffix is ".cgi". + +cgi_cgi +cgi_cgi_set + +cgi_cgi controls exactly how cgi_form creates URLs from its action +argument. By default, cgi_cgi takes an argument, prepends [cgi_root] +and appends [cgi_suffix]. The suffix can be overridden by using the +-suffix flag and an argument to be used instead of [cgi_suffix]. + +Any additional arguments are joined together in the style required for +a GET style request. These arguments should be preformatted using +cgi_cgi_set to guarantee proper encoding. For example: + + cgi_cgi myscript \ + [cgi_cgi_set owner "Don"] \ + [cgi_cgi_set color "black & white"] + +generates: ....?owner=Don&color=black+%26+white + +cgi_isindex + +cgi_isindex generates an <isindex> tag. Optional arguments are passed +on as attributes. In the processing CGI script, the value of the +isindex query is found in the "anonymous" variable. + +cgi_relationship rel url + +cgi_relationship expresses a relationship between this document and +another. For example, the following says that the url named by +homepage is the home document of the current document. + + cgi_relationship home $homepage + +Optional arguments are passed on as additional attributes. Here's an +example that references an external style sheet that is a CSS type +(cascading style sheet). + + cgi_relationship stylesheet basic.css type=text/css + + +************************************************** +INPUT +************************************************** + +cgi_input + +CGI input means "cookies, files, and get/post data". cgi_input reads +in all input, decodes it, and makes it available to a variety of other +routines. + +For debugging, cgi_input can be given arguments to fake input. This +allows you to run your cgi_script interactively or under a debugger +(either Tcl or C debugger). Provide GET/POST data as the first +argument. Provide cookie data as the second argument. The arguments +should be encoded (see cgi_cgi_set). For example: + + cgi_input "name=libes&old=foo&new1=bar&new2=hello" + +This is convenient because when you run into a misbehaving CGI script, +the first thing it does is tell you the input in exactly this format. +Simply cut and paste it into your program and you can then +interactively debug it without using the real form or the CGI server. + +If cgi_input is invoked from the CGI environment, the fake inputs are +ignored. (If you want to force fake inputs in the CGI environment, +unset env(REQUEST_METHOD). + +Forms encoded as multipart/form-data are usually used to handle file +input. Since file data usually implies a large amount of data, the +data is saved to /tmp/CGIdbg.[pid] if debugging is enabled. This file +can be fed back to cgi_input by providing the filename as the first +argument of cgi_input. In addition, env(CONTENT_TYPE) must be set to +the appropriate content type. This can found in env(CONTENT_TYPE). +Removal of the debugging file is the responsibility of the script or +the script programmer. (Typically, I examine the file after my CGI +script is over and then delete them by hand.) + +Execs before cgi_input reads POST data should have standard input +redirected ("< /dev/null" for instance) so that the exec'd process +doesn't inherit the CGI script's standard input. + +** Form elements that generate lists + +Variable names should only end with "List" if they correspond to form +elements which generate multiple values (some but not all uses of +select, checkbox, etc). List variables will be given Tcl-style list +values. + +If cgi_input encounters multiple values for variables that do not end +with List, it will provide the values in a Tcl-style list. However, +this leaves an ambiguity in the case of a single value that "looks" +like a list, such as "a b". Although a form author can usually "know" +whether a string is a list or not, it is simpler to stick to the +convention stated earlier. + +Here are examples: + + # pull-down menu + cgi_select Foo { + cgi_option "a" + cgi_option "a b" + } + + # scrolled list, allow multiple selections + cgi_select FooList multiple { + cgi_option "a" + cgi_option "a b" + } + +** Getting at the input + +Input is made available in two ways: variables, files, and cookies. + +-- Variables and Cookies + +cgi_import_list + +cgi_import_list returns a list of variable names supplied as input to +the script. + +cgi_cookie_list + +cgi_cookie_list returns a list of cookie names supplied to the script. + +cgi_import name + +cgi_import retrieves the value of the named variable and places it in +a Tcl variable of the same name. The value is also returned as the +return value. + +cgi_import_as name tclvar + +cgi_import_as is similar to cgi_import but the value is assigned to +the Tcl variable named by the second argument. + +cgi_import_cookie name + +cgi_import is similar to cgi_import, however if the cgi variable does +not exist, the value is fetched from the cookie by that name. (This +allows the user to override a cookie if the form allows it.) + +cgi_import_cookie_as name tclvar + +cgi_import_cookie_as is similar to cgi_import_cookie but the value is +assigned to the Tcl variable named by the second argument. + +cgi_cookie_get name + +cgi_cookie_get returns the value of the named cookie. + +-- Files + +cgi_import_file -server name +cgi_import_file -client name +cgi_import_file -type name + +cgi_import_file returns information about an uploaded file. "name" is +the string from the original form. The Content-type is returned via +-type. (This may be empty or even undefined in which case +cgi_import_file should be caught.) + +Uploaded files are saved on the CGI server. To avoid collisions with +other file upload instances, files are not stored in their original +names. The name of the file as it is stored on the CGI server is +retrieved using the "-server" flag. The original name of the file as +it was stored on the user's host is retrieved using the "-client" +flag. + +Uploaded files are the responsibility of the CGI programmer. In +particular, if you do not delete them, they will remain until /tmp is +cleaned up in some other way. + +If the user does not enter a filename, an empty file will be delivered +with a null remote filename. + +cgi_file_limit files chars + +cgi_file_limit establishes limits on the number of files and their +size. This is provided to prevent denial of service attacks. If the +limit is exceeded, an error is raised from within cgi_input. + +Note that when the limit is exceeded, cgi_input fails immediately. So +if you just want to check file sizes that are not security related - +for example, you just want to accept gifs under 10K - it's better to +accept the gifs and then check the size manually (i.e., [file size +...]. That way, cgi_input will completely read all the variables and +you can give more appropriate diagnostics. + +The default limit is 10 100MB files. If you were to set this +yourself, it would look this way: + +cgi_file_limit 10 100000000 + + +-- File example + +The following code echos the contents of a file that was +uploaded using the variable "file": + + cgi_input + cgi_body { + set server [cgi_import_filename -server $v] + set client [cgi_import_filename -client $v] + if [string length $client] { + h4 "Uploaded: $client, contents:" + cgi_preformatted {puts [exec cat $server]} + } + file delete $server + } + +The present implementation supports binary upload if you are using Tcl +8.1 (or later) or if you are using the Expect extension. If you are +using a version of Tcl earlier than 8.1 with Expect but want to +suppress binary loading, create the global variable +_cgi(no_binary_upload). (The reason you might want to suppress binary +loading is that it is noticably slower.) + +************************************************** +EXPORT +************************************************** + +Form elements automatically export their values. See FORM ELEMENTS +for more information. + +cgi_export name=value + +cgi_export makes the named variable available with the given value. +The "=value" is optional. If not present, the value of the Tcl +variable by the same name is used. + +cgi_export is implemented with variables of type=hidden. + +cgi_export is implemented as an all-or-nothing operation. In +particular, no HTML is emitted if the variable does not exist. That +means it is not necessary to test for existence in situations where +you would like to export a variable IF it exists. Rather, it is +sufficient to embed cgi_export within a catch. For example, the +following generates nothing if xyz doesn't exist and it generates the +appropriate HTML if xyz does exist. + + catch {cgi_export xyz} + +** Cookies + +cgi_export_cookie name + +cgi_export_cookie is similar to cgi_export except that the value is +made available as a cookie. Additional arguments are handled as with +cgi_cookie_set (see below). + +cgi_cookie_set name=val + +cgi_cookie_set sets the named cookie. All optional arguments are +handled specially. All arguments are encoded appropriately. The +expires keyword is handled specially to simplify common cases. In +particular, the values "now" and "never" produce appropriate GMT +values. + +Here are some example of cgi_cookie_set: + + cgi_cookie_set user=don domain=nist.gov expires=never + cgi_cookie_set user=don domain=nist.gov expires=now + cgi_cookie_set user=don domain=nist.gov expires=...actual date... + +Note that cookie setting must be done during http head generation. + +************************************************** +URL/IMG DICTIONARY SUPPORT +************************************************** + +cgi_link tag +cgi_link tag display url + +cgi_link provides a convenient mechanism for maintaining and +referencing from a set of URLs. + +cgi_link returns the string <A>...</A> corresponding to the given tag. +A tag is defined by calling cgi_link with the tag, the clickable text +that the use should see, and the url. + +For example, suppose you want to produce the following (where _xyz_ +indicates xyz is a hyperlink): + + I am married to _Don Libes_ who works in the _Manufacturing + Collaboration Technologies Group_ at _NIST_. + +Using cgi_link with appropriate link definitions, the scripting to +produce this is: + + p "I am married to [link Libes] who works in the [link MCTG] + at [link NIST]." + +This expands to: + + I am married to <A HREF="http://elib.cme.nist.gov/msid/staff + /libes/ libes.don.html">Don Libes</A> who works in the <A + HREF="http:// elib.cme.nist.gov/msid/groups/mctg.htm"> + Manufacturing Collaboration Technologies Group</A> at <A + HREF="http:// www.nist.gov">NIST</A>. + +The links themselves are defined thusly: + + link Libes "Don Libes" http://www.cme.nist.gov/msid/staff/libes + link MCTG "$MCT Group" http://www.cme.nist.gov/msid/mctg + link NIST "NIST" http://www.nist.gov + +Now if my home page ever changes, rather than updating every +occurrence, I just have to edit the one definition. + +Tcl variables can further simplify updates. For instance, URLs for +Libes and MCTG are in a common directory. It makes sense to store +that in a single variable. Rewritten this appears: + +set MSID http://www.cme.nist.gov/msid + + link Libes "Don Libes" $MSID/staff/libes + link MCTG "$MCT Group" $MSID/mctg + link NIST "NIST" http://www.nist.gov + +Then if the MSID directory ever moves, only one line need be updated. +This may seem like no big deal here, but if you have many links and +many uses of them, this pays off handsomely. + +Optional attributes can be provided as additional arguments (see IMG +example below). + +An existing link can be given a different "display" temporarily by +calling cgi_link with the different display and omitting the url. + +cgi_imglink + +imglink works similar to cgi_link (see that documentation for more +info) except that no display argument is used and the second argument +is assumed to be the image source. Example: + + imglink taj tajmahal.gif + +Other attributes can be provided as additional arguments. + + imglink taj tajmahal.gif "alt=The Taj Mahal" + +cgi_url display href args + +By using cgi_url, URLs can be generated immediately (without using +cgi_link first). This is convenient when you need a URL that will +only appear once - so that there is no point in storing it in a +dictionary. For example: + + cgi_li "[cgi_url "Plume" http://pastime.anu.edu.au/Plume] + is a Tcl-based WWW browser written by Steve Ball, + Australian National University. Among its interesting + features is the ability to execute Tcl applets and the + ability to dynamically extend the browser at runtime." + +cgi_img href args + +cgi_img returns a formatted <img> tag. It is useful for one-time tags. +Tags that are used multiple times should use cgi_imglink. Example: + + cgi_img foo.gif "alt=Foo's Bar & Grill" + +cgi_anchor_name name + +cgi_anchor_name returns an anchor that can be used in an HTML body +that it can be linked to using the #name syntax. For example, to make +a heading that you want to be able to link to: + + h2 "[cgi_anchor_name future]Future Improvements" + +Then to reference the "future" tag: + + p "Look for [cgi_url "improvements" #future] in the future." + +cgi_base args + +cgi_base defines a base or window target for urls. + +************************************************** +QUOTING +************************************************** + +cgi_unquote_input string + +cgi_unquote_input undoes "url-encoding" and returns the result. This +is normally applied automatically to input sources including URLs and +cookies. So you shouldn't have to call this manually. + +cgi_quote_html string + +cgi_quote_html returns the string but with any html-special characters +escaped. For example, "<" is replaced by "\<". This is useful for +displaying a literal "<" in the browser. + +cgi_dquote_html string + +cgi_dquote_html does the same thing as cgi_quote_html but also adds on +double quotes. cgi_quote_html is called automatically for implicit +value attributes. + +cgi_quote_url string + +cgi_quote_url quotes strings appropriately to appear in a url, cookie, +etc. This is useful if you want to publish a url by hand (and must do +the conversion manually that the client normally does for you). + +If you are generating cgi-style URLs for forms, use cgi_cgi_set. + +cgi_preformatted cmd + +cgi_preformatted evaluates its last argument to produce fixed-width +preformatted output. Optional arguments are passed as attributes to +the tags. + +cgi_preformatted allows a subset of tags to be interpreted by the +browser. For example, the <a> tag is interpreted but font change tags +are not. To prevent all interpretation, use cgi_quote_html. For +example, the following prints a file that might contain HTML but +without any risk to throwing off formatting. + + cgi_preformatted { + puts [cgi_quote_html [read $fid]] + } + +************************************************** +LIST SUPPORT +************************************************** + +** List elements + +cgi_li string + +cgi_li prints its string as a list element. Optional arguments are +passed through as attributes. cgi_li does not have to appear in a +list container, but it can. + +cgi_term text +cgi_term_definition text + +cgi_term and cgi_term_definition are usually paired up (although they +need not be) to creates terms and defintions. They do not have to +appear in a list container, but usually appear in a cgi_definition_list. + +** List containers + +cgi_number_list cmd +cgi_bullet_list cmd + +cgi_number_list and cgi_bullet_list take their cmd argument and +evaluate it in a list container context. (I don't know about you but +I could never remember <ol>, <ul>, and all the other ones. This names +seem much easier to remember.) + +cgi_li is a typical command to call inside of a list container, but +you can use regular paragraphs (or anything else) as well. + +cgi_definition_list + +cgi_definition_list is the usual list container for cgi_term and +cgi_term_definition. It may contain other things as well. + +cgi_menu_list +cgi_directory_list + +cgi_menu_list and cgi_directory are more list containers with the +obvious semantics. Previous remarks about other list containers +apply. + +************************************************** +TABLE +************************************************** + +cgi_table cmd + +cgi_table produces <table></table> tags with the content filled by +evaluation of cmd. Optional arguments are passed on as attributes. + +cgi_caption cmd + +cgi_caption produces <caption></caption> tags with the content filled +by evaluation of cmd. Optional arguments are passed on as attributes. + +cgi_table_row cmd +cgi_table_head cmd +cgi_table_data cmd + +These functions all produce the appropriate tags with the content +filled by evaluation of cmd. Optional arguments are passed on as +attributes. + +cgi_tr table_data +cgi_td table_data +cgi_th table_data + +cgi_tr, cgi_td, and cgi_th are shortcuts for relatively simple rows. + +cgi_td outputs a table element. Unlike cgi_table_data, the argument +is not evalled. This allows more terse specification of simple rows. +The following example produces a table with three elements, the last +of which is prevented from wrapping: + + table_row {td Don;td Steve;td nowrap "Really Long Name"} + +As the example suggests, optional arguments are passed on as +data-specific attributes. + +cgi_th is identical to cgi_td except that it produces table heading +elements. + +cgi_tr outputs a row of elements without having to call cgi_td or +cgi_table_data. As with td, eval is not called. Data-specific +attributes cannot be provided. All the elements are passed as a +single argument. For example: + + tr {Don Steve {Really Long Name}} +or + tr [list Don Steve $reallylongname] + +Optional arguments are passed on as row-specific attributes. + +************************************************** +BUTTON +************************************************** + +cgi_submit_button name=value +cgi_radio_button name=value +cgi_image_button name=value + +These procedure create buttons. The first argument indicates the +variable name and value. (See notes on "Name-value" commands earlier +to understand behavior of omitted names/values.) Unless otherwise +mentioned below, additional arguments are passed on as attributes. + + cgi_submit_button "=Submit Form" + cgi_submit_button "Action=Pay Raise" + + cgi_radio_button "version=1" + cgi_radio_button "version=2" checked=1 + + cgi_image_button "=http://www.cme.nist.gov/images/title.gif" + cgi_image_button "Map=http://www.cme.nist.gov/images/msid3.gif" + +Groups of radio buttons must share the same variable name. To address +the obvious question: No, there is no single command to produce a +group of radio buttons because you might very well want to do +arbitrarily-complex calculations in between them. And with a +long-enough line of buttons, the obvious behavior (laying them all out +in a line like CGI.pm does) makes it hard to tell at a glance if the +buttons associate with the label to the left or the right of them. +Anyway, you'll almost certainly want to write another procedure to +call cgi_radio_button and that can control the variable name. + +The radio button argument "checked_if_equal=xxx" indicates that the +button should be shown selected if its associated value is xxx. This +is handy if you are creating radio buttons by iterating over a list. + +The radio button "checked=value" indicates that the button should be +shown selected if the value is a boolean of value true. + +All other arguments are passed on as attributes. + +cgi_file_button name + +cgi_file_button provides a filename entry box. When the form is +submitted, the file is "uploaded" (sent from the client to the +server). The argument enctype=multipart/form-data must be given to +the cgi_form command when using cgi_file_button. + +After uploading, the file is the responsibility of the CGI programmer. +In particular, if you do not delete it, it will remain until /tmp is +cleaned up in some other way. + +For example, to upload a single file, the form might look like this: + + cgi_form upload height=3 enctype=multipart/form-data { + cgi_file_button file + cgi_submit_button =Upload + } + +Uploaded files are automatically made available to the CGI script +using cgi_import_filename. (See elsewhere for more information.) + +cgi_reset_button value + +cgi_reset_button creates a a reset button. An argument overrides the +default label. For example: + + cgi_reset_button + cgi_reset_button "Not the Default Reset Button" + +cgi_map name cmd +cgi_area args + +These procedures are used to specify client-side image maps. The +first argument of cgi_map is the map name. The last argument is +evaluated to fill the contents of <map></map> tags. cgi_area's +arguments are embedded as arguments in an <area> tag. + +Warning: These two commands will likely be redefined as I get more +familiar with how they are typically used. + +************************************************** +CHECKBOX +************************************************** + +cgi_checkbox name=value + +cgi_checkbox is similar to cgi_radio_button (see above) except that +multiple values can be checked at the same time. As explained +earlier, the variable name must end with "List" in order for it to +group all the values as a list in the resulting CGI script. + +The argument "checked_if_equal=xxx" which indicates that the current +name should be shown selected if its associated value is xxx. This is +handy if you are creating checkboxes by iterating over a list. + +The argument "checked=value" indicates that the checkbox should be +shown selected if the value is a boolean of value true. + +Other arguments are passed on as attributes. + + +************************************************** +TEXTENTRY AND TEXTAREA +************************************************** + +cgi_text name=value + +cgi_text provides a one-line text entry box. It works similarly to +other form elements. (Read "Name-value commands" elsewhere.) +Additional arguments are passed on as attributes. Examples: + + cgi_text Foo + cgi_text Foo= + cgi_text Foo=value2 + cgi_text Foo=value2 size=5 + cgi_text Foo=value2 size=5 maxlength=10 + cgi_text Foo=value2 size=10 maxlength=5 + cgi_text Foo=value2 maxlength=5 + +cgi_textarea name=value + +cgi_textarea provides a multiline text entry box. It works similarly +to other form elements. (Read "Name-value commands" elsewhere.) +Additional arguments are passed on as attributes. + + set value "A really long line so that we can compare the\ + effect of wrap options." + + cgi_textarea Foo + cgi_textarea Foo= + cgi_textarea Foo=$value + cgi_textarea Foo=$value rows=3 + cgi_textarea Foo=$value rows=3 cols=7 + cgi_textarea Foo=$value rows=3 cols=7 wrap=virtual + +************************************************** +SELECT +************************************************** + +cgi_select name cmd + +cgi_select can be used to produce pull-down menus and scrolled lists. +(And depending upon the future of HTML, I may provide better-named +commands to indicate this.) Its behavior is controlled by additional +arguments which are simply the appropriate attributes. + +cgi_select evaluates cmd which typically contains multiple calls to +cgi_option. + +cgi_option string + +cgi_option adds options to cgi_select. By default, the string is +displayed and sent back as the value of the cgi_select variable. The +value can be overridden by an explicit "value=" argument. Additional +options are passed on as attributes, except for "selected_if_equal". + +"selected_if_equal=xxx" indicates that the current option should be +shown selected if the value is equal to xxx. This is useful if you +are generating cgi_options in a loop rather than manually. + +Here are examples: + + # pull-down menu + cgi_select Foo { + cgi_option one selected + cgi_option two + cgi_option many value=hello + } + + # scrolled list, allow multiple selections, show all elements + cgi_select FooList multiple { + cgi_option one selected + cgi_option two selected + cgi_option many + } + + # scrolled list, allow multiple selections, show 2 elements max + cgi_select FooList multiple size=2 { + cgi_option one selected + cgi_option two selected + cgi_option many + } + + # choose "selected" dynamically + # example: list all Tcl command and select "exit" automatically + cgi_select FooList multiple size=5 { + foreach o [info comm] { + cgi_option $o selected_if_equal=exit + } + } + +Note: If both value= and selected_if_equal= appear, the test for +selection is made against the last value string (implicit or explicit) +that appears before the selected_if_equal argument. In other words, +if you want selected_if_equal= to be tested against the explicit +value= argument, put the selected_if_equal= *after* the value=. + +************************************************** +APPLET +************************************************** + +cgi_applet parameters cmd + +cgi_applet produces <applet></applet> tags such as for Java. + +cgi_param name=value + +cgi_param produces <param> tags for passing parameters to applets. + +For example: + + cgi_applet "codebase=../" "code=some.class" width=640 height=480 { + cgi_param parm=value + } + +************************************************** +PLUG-IN +************************************************** + +cgi_embed src widthxheight + +cgi_embed creates an <embed> tag. The first argument is the source. +The second argument is the width and height in the style "WxH". +Optional arguments are passed on to the tag. For example: + + cgi_embed myavi.avi 320x200 autostart=true + +produces: + + <embed src="myavi.avi" width="320" height="200" autostart=true> + +Notice the autostart value is unquoted because autostart is not +specifically defined by the spec. The argument "-quote" causes all +remaining attributes to be url encoded and quoted. For example: + + cgi_embed myavi.avi 320x200 a=b -quote c=d e=f + +produces: + + <embed src="myavi.avi" width="320" height="200" a=b c="d" e="f"> + +************************************************** +MISC +************************************************** + +cgi_hr + +cgi_hr produces horizontal rules. Optional arguments are passed on as +attributes. + +************************************************** +COMMENTS +************************************************** + +cgi_comment stuff + +cgi_comment can comment out anything including blocks of code. + +cgi_html_comment stuff + +cgi_html_comment comments out things in such a way that the comment +appears in the final html itself. + +************************************************** +OUTPUT +************************************************** + +cgi_put string + +cgi_put prints the string with no new terminating newline. This is +simply a shorthand for puts -nonewline. + +cgi_puts + +Many routines in this library send output to the standard output by +default. This is convenient for CGI scripts. However, if you want to +generate multiple files, it is useful to be able to redirect output +dynamically. Output can be redirected by redefining cgi_puts. The +default definition of cgi_puts is: + + proc cgi_puts {args} { + eval puts $args + } + +cgi_puts must allow for an optional -nonewline argument. For example, +here is a definition that writes to a file identified by the global +"fd". + + proc cgi_puts {args} { + global fd + + puts -nonewline $fd [lindex $args end] + if {[llength $args] > 1} { + puts $fd "" + } + } + +cgi_buffer cmd + +cgi_buffer evaluates its argument in such a way that output (through +explicit or implicit calls to cgi_puts) is not produced. Instead, the +output is returned. + +For example, the following cmd generates a link with the hyperlinked +portion being a header and two paragraphs. + + link tag [cgi_buffer { + h3 "Level 3 header" + p "New paragraph" + p "Another paragraph" + }] $URL + +cgi_buffer can be called recursively. + +cgi_buffer_nl string + +By default, cgi_buffer generates newlines at the end of every line in +the style of puts. It is occasionally useful to be able to disable +this - for example, when calling it inside cgi_preformatted. The +newline definition can be changed via cgi_buffer_nl. (There is no +point to redefining cgi_puts since cgi_buffer doesn't use it.) A null +argument suppresses any newline. For example: + + cgi_buffer_nl "" + +cgi_buffer_nl returns the previous definition. + +************************************************** +MAIL +************************************************** + +Rudimentary email support is provided, in part, because it is useful +for trapping errors - if debugging is disabled (i.e., during actual +use) and an error is encountered, errors are emailed to the service +admin. + +The current implementation only permits one email transaction at a +time. + +cgi_mail_addr addr + +cgi_mail_addr defines the email address that mail comes from. Your +email system must allow this, of course. (If your system doesn't +allow it, the request is usually ignored.) + +cgi_mail_start addr + +cgi_mail_start creates a mail message to be delivered the given addr. +cgi_mail_add should be used to provide a subject and body. + +cgi_mail_add string + +cgi_mail_add adds strings to the current mail message. No argument +causes a blank line to be added. + +cgi_mail_end + +cgi_mail_end queues the the current mail message for delivery. + + cgi_mail_start libes@nist.gov + cgi_mail_add "Subject: [cgi_name] request succeeded + cgi_mail_add + cgi_mail_add "Your request has been processed." + cgi_mail_add "Thanks for using [cgi_name]. + cgi_mail_end + +cgi_mail_relay host + +cgi_mail_relay identifies a host to be used for mail relay services. +(This is currently only used when sendmail support is not available.) +If a relay is not defined, email is sent directly to the recipient. + +************************************************** +INITIALIZATION +************************************************** + +cgi_init + +The package initializes itself upon initial loading, however it can be +explicitly initialized by calling cgi_init. This is useful in +environments such as tclhttpd. diff --git a/web/src/cgi.tcl-1.10/example/README b/web/src/cgi.tcl-1.10/example/README new file mode 100644 index 00000000..6bbbb80c --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/README @@ -0,0 +1,77 @@ +This file is cgi.tcl/README. It contains brief descriptions of the +examples in this directory. You are welcome to send me additional +scripts. + +-------------------- +Instructions on running scripts +-------------------- + +The "examples.cgi" script provides a page of clickable links to all +the other example scripts. "frame.cgi" is a framed version - it's not +particularly good looking but it does work and - anyway - I needed a +frame example! + +There are three ways of running these scripts: + +1) Point your browser at http://expect.nist.gov/cgi.tcl + +2) Run them by hand, such as by typing "tclsh scriptname" at the +command line. This is appropriate if you just want to study the raw +HTML output or see how fast they run. + +3) Install them in your own web and run them through your browser. +(If you're on a UNIX host, the "make examples" target in the Makefile +fixes up the #! line of each examples and installs them in a public +demo directory.) You'll want to edit the example.tcl file to redefine +cgi_root appropriately. + +If you run the examples locally (options 2 and 3): + + - In order to get the submit buttons to take you back to your + site (instead of on to my site!), check the cgi_root call in + example.tcl to point back to your site. + + - Some of these examples may do things that are not portable + and therefore may not run on all systems. For example, some + of them call "exec". The "unimail" script assumes the + existence of sendmail through cgi.tcl's built-in mail + support. See the ../install.win file for more info. + +-------------------- +Source files in this directory +-------------------- + + cookie.cgi - demonstrates cookies + + display.cgi - display a CGI script + + error.cgi - demonstrates error handing + + examples.cgi - Provides a page with clickable links to all + these examples. + + form-tour.cgi - demonstrates most form elements (Note that these + don't do anything - they're just for looks.) + + format-tour.cgi - demonstrates many formats, unrelated to forms + + frame.cgi - a friend's home page that demonstrates frames + + kill.cgi - kill runaway CGI processes + + parray.cgi - displays an array (or the environment by default) + + passwd-form.cgi - creates a form for changing a password + passwd.cgi - backend to passwd-form where password is actually changed + Note that this script is an Expect script. + passwd.tcl - common definitions for passwd*.cgi scripts + + upload.cgi - file upload + + vclock.pl - Lincoln Stein's virtual clock from CGI.pm paper + vclock.cgi - Lincoln Stein's virtual clock (but in Tcl) + + visitor.cgi - implements a visitor counter + visitor.cnt - file containing the count + + example.tcl - common definitions for most of the examples diff --git a/web/src/cgi.tcl-1.10/example/cookie.cgi b/web/src/cgi.tcl-1.10/example/cookie.cgi new file mode 100755 index 00000000..ea0709bc --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/cookie.cgi @@ -0,0 +1,45 @@ +#!/depot/path/tclsh + +# This CGI script shows how to create a cookie. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_http_head { + cgi_content_type text/html + if {0==[catch {cgi_import Name}]} { + cgi_export_cookie Name ;# expires=never + # For a persistent cookie, uncomment the "expires=never" + } else { + catch {cgi_import_cookie Name} + } + } + cgi_head { + cgi_title "Cookie Form Example" + } + cgi_body { + p "This form finds a value from a previous submission of \ + the form either directly or through a cookie." + set Name "" + + if {0==[catch {cgi_import Name}]} { + p "The value was found from the form submission and the cookie + has now been set. Bookmark this form, surf somewhere else + and then return to this page to get the value via the cookie." + } elseif {0==[catch {cgi_import_cookie Name}]} { + p "The value was found from the cookie." + } else { + p "No cookie is currently set. To set a cookie, enter a value + and press return." + } + + cgi_form cookie { + puts "Value: " + cgi_text Name + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/creditcard.cgi b/web/src/cgi.tcl-1.10/example/creditcard.cgi new file mode 100755 index 00000000..a205b452 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/creditcard.cgi @@ -0,0 +1,137 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + set cardtypes { + "American Express" + "Carte Blanche" + "Diners Card" + "Discover" + "Enroute" + "JCB" + "Mastercard" + "Novus" + "Visa" + } + + # My own version of the LUHN check + proc LUHNFormula {cardnumber} { + if {0==[regexp "(.*)(.)$" $cardnumber dummy cardnumber check]} { + user_error "No card number entered" + } + set evenodd [expr [string length $cardnumber] % 2] + + set sum 0 + foreach digit [split $cardnumber ""] { + incr sum $digit + if {$evenodd} { + incr sum [lindex {0 1 2 3 4 -4 -3 -2 -1 0} $digit] + } + set evenodd [expr !$evenodd] + } + set computed [expr {(10 - ($sum % 10)) % 10}] + if {$computed != $check} { + user_error "Invalid card number. (Failed LUHN test - try changing last digit to $computed.)" + } + } + + # generate digit patterns of length n + proc d {n} { + for {set i 0} {$i < $n} {incr i} { + append buf {[0-9]} + } + return $buf + } + + cgi_input + + cgi_title "Check Credit Card" + + cgi_body { + if {0 == [catch {cgi_import cardtype}]} { + if {[catch {cgi_import cardnumber}]} { + user_error "No card number entered" + } + # Save original version for clearer diagnostics + set originalcardnumber [cgi_quote_html $cardnumber] + + if {[catch {cgi_import expiration}]} { + user_error "You must enter an expiration." + } + if {-1 == [lsearch $cardtypes $cardtype]} { + user_error "Unknown card type: $cardtype" + } + + # Remove any spaces or dashes in card number + regsub -all "\[- ]" $cardnumber "" cardnumber + + # Make sure that only digits are left + if {[regexp "\[^0-9]" $cardnumber invalid]} { + user_error "Invalid character ([cgi_quote_html $invalid]) in credit card number: $originalcardnumber" + } + + if {$cardtype != "Enroute"} { + LUHNFormula $cardnumber + } + + # Verify correct length and prefix for each card type + switch $cardtype { + Visa { + regexp "^4[d 12]([d 3])?$" $cardnumber match + } Mastercard { + regexp "^5\[1-5][d 14]$" $cardnumber match + } "American Express" { + regexp "^3\[47][d 13]$" $cardnumber match + } "Diners Club" { + regexp "^3(0\[0-5]|\[68][d 1])[d 11]$" $cardnumber match + } "Carte Blanche" { + regexp "^3(0\[0-5]|\[68][d 1])[d 11]$" $cardnumber match + } Discover { + regexp "^6011[d 12]$" $cardnumber match + } Enroute { + regexp "^(2014|2149)[d 11]$" $cardnumber match + } JCB { + regexp "^(2131|1800)[d 11]$" $cardnumber match + regexp "^3(088|096|112|158|337|528)[d 12]$" $cardnumber match + } Novus { + if {[string length $cardnumber] == 16} { + set match 1 + } + } + } + + if 0==[info exists match] { + user_error "Invalid card number: $originalcardnumber" + } + h3 "Your card appears to be valid. Thanks!" + return + } + + cgi_form creditcard { + h3 "Select a card type, enter the card number and expiration." + puts "Card type: " + cgi_select cardtype { + foreach t $cardtypes { + cgi_option $t + } + } + puts "[nl]Card number: " + cgi_text cardnumber= + puts "(blanks and dashes are ignored)" + + puts "[nl]Expiration: " + cgi_text expiration= + + br + submit_button "=Confirm purchase" + reset_button + h5 "This script will perform all of the known syntactic + checks for each card type but will not actually contact + a credit bureau. The expiration field is not presently + checked at all." + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/display-in-frame.cgi b/web/src/cgi.tcl-1.10/example/display-in-frame.cgi new file mode 100755 index 00000000..6366957e --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/display-in-frame.cgi @@ -0,0 +1,31 @@ +#!/depot/path/tclsh + +# This is a CGI script that displays the results of other CGI scripts +# in a separate frame. It is only used for a few rare examples such +# as image.cgi + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_head { + set scriptname image.cgi + catch {cgi_import scriptname} + set scriptname [file tail $scriptname] + cgi_title $scriptname + } + cgi_frameset rows=50%,50% { + cgi_frame =$scriptname?header=1 + cgi_frame =$scriptname + } + cgi_noframes { + cgi_h1 "uh oh" + + p "This document is designed to be viewed by a Frames-capable + browser. If you see this message your browser is not + Frames-capable." + } +} diff --git a/web/src/cgi.tcl-1.10/example/display.cgi b/web/src/cgi.tcl-1.10/example/display.cgi new file mode 100755 index 00000000..efadbe05 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/display.cgi @@ -0,0 +1,44 @@ +#!/depot/path/tclsh + +# This is a CGI script that displays another CGI script +# and massages "source" commands into hyperlinks + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_head { + set scriptname [info script]; # display self by default! + catch {cgi_import scriptname} + + # strip tildes to gracefully handle experimenters + set scriptname [string trimleft $scriptname ~] + + set scriptname [file tail $scriptname] + cgi_title "Source for $scriptname" + } + cgi_body { + # gracefully handle hackers trying to opening directories + switch -- $scriptname . - .. - "" { + h3 "No such file: $scriptname" + return + } + if {[catch {set fid [open $scriptname]}]} { + h3 "No such file: $scriptname" + return + } + cgi_preformatted { + while {-1 != [gets $fid buf]} { + if {[regexp "^(\[ \t]*)source (.*)" $buf ignore space filename]} { + puts "[set space]source [cgi_url $filename [cgi_cgi display scriptname=$filename]]" + } else { + puts [cgi_quote_html $buf] + } + } + } + } +} + diff --git a/web/src/cgi.tcl-1.10/example/download.cgi b/web/src/cgi.tcl-1.10/example/download.cgi new file mode 100755 index 00000000..c82cb3f5 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/download.cgi @@ -0,0 +1,36 @@ +#!/depot/path/tclsh + +package require cgi + +set msg "Very funny, Scotty. Now beam down my clothes." +set filename "scotty.msg" + +cgi_eval { + source example.tcl + + cgi_input + + if {[catch {cgi_import style}]} { + cgi_title "download example" + body { + cgi_suffix "" + form download.cgi/$filename { + puts "This example demonstrates how to force files to be + downloaded into a separate file via the popup file browser." + br + puts "Download data" + submit_button "style=in window" + submit_button "style=in file using popup file browser" + } + } + } else { + if {[regexp "in window" $style]} { + title "Display data in browser window" + } else { + cgi_http_head { + content_type application/x-download + } + } + puts $msg + } +} diff --git a/web/src/cgi.tcl-1.10/example/error.cgi b/web/src/cgi.tcl-1.10/example/error.cgi new file mode 100755 index 00000000..0b97c99a --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/error.cgi @@ -0,0 +1,31 @@ +#!/depot/path/tclsh + +# This is a CGI script that demonstrates error processing. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_title "This CGI script contains an intentional error." + + cgi_body { + p "The page that you are now reading is being generated by a + CGI script that contains an intentional error." + + cgi_debug -on + + p "Debugging is enabled, so the error message will be shown in +the browser window (below). Disable this by commenting out the +cgi_debug command and reloading this script." + + cgi_number_list { + cgi_li "List item 1" + cgi_li "List item 2" + cgi_lix "List item 3 - intentionally misspelled" + cgi_li "List item 4" + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/evaljs.cgi b/web/src/cgi.tcl-1.10/example/evaljs.cgi new file mode 100755 index 00000000..ea732e9d --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/evaljs.cgi @@ -0,0 +1,36 @@ +#!/depot/path/tclsh + +# This CGI script uses JavaScript to evaluate an expression. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_head { + title "Using JavaScript to evaluate an expression" + + javascript { + puts { + function compute(f) { + f.result.value = eval(f.expr.value) + } + } + } + noscript { + puts "Sorry - your browser doesn't understand JavaScript." + } + } + + cgi_body { + cgi_form dummy { + cgi_unbreakable { + cgi_button "Evaluate" onClick=compute(this.form) + cgi_text expr=Math.sqrt(2)*10000 + puts "=" + cgi_text result= + } + p "Feel free to enter and evaluate your own JavaScript expression." + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/example.tcl b/web/src/cgi.tcl-1.10/example/example.tcl new file mode 100644 index 00000000..c1246621 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/example.tcl @@ -0,0 +1,82 @@ +# common definitions for all examples + +# cgi_debug -on + +set NIST_HOST http://www.nist.gov +set MSID_HOST http://www.nist.gov +set EXPECT_HOST http://expect.nist.gov +set EXPECT_ART $EXPECT_HOST/art +set MSID_STAFF $MSID_HOST/msidstaff +set CGITCL $EXPECT_HOST/cgi.tcl +set DATADIR data + +set domainname "unknown" +catch {set domainname [exec domainname]} + +# prevent everyone in the world from sending specious mail to Don! +if {($domainname == "cme.nist.gov") || ([info hostname] == "ats.nist.gov")} { + cgi_admin_mail_addr libes@nist.gov +} + +set TOP target=_top +cgi_link NIST "NIST" $NIST_HOST $TOP +cgi_link Don "Don Libes" $MSID_STAFF/libes $TOP +cgi_link admin "your system administrator" mailto:[cgi_admin_mail_addr] +cgi_link CGITCL "cgi.tcl homepage" $CGITCL $TOP +cgi_link examples "list of examples" [cgi_cgi examples] $TOP +cgi_link realapps "real applications" $CGITCL/realapps.html $TOP +cgi_link Expect "Expect" $EXPECT_HOST $TOP +cgi_link Oratcl "Oratcl" http://www.nyx.net/~tpoindex/tcl.html#Oratcl $TOP + +cgi_imglink logo $EXPECT_ART/cgitcl-powered-feather.gif align=right "alt=powered-by-cgi.tcl logo" +cgi_link logolink [cgi_imglink logo] $CGITCL $TOP + +# Allow for both my development and production environment. And people +# who copy this to their own server and fail to change cgi_root will get +# my production environment! +if {$domainname == "cme.nist.gov"} { + cgi_root "http://www-i.cme.nist.gov/cgi-bin/cgi-tcl-examples" +} else { + cgi_root "http://ats.nist.gov/cgi-bin/cgi.tcl" +} + +proc scriptlink {} { + if {0==[catch {cgi_import framed}]} { + set target "target=script" + } else { + set target "" + } + + cgi_url "the Tcl script" [cgi_cgi display scriptname=[info script]] $target +} + +proc app_body_start {} { + h2 [cgi_title] + puts "See [scriptlink] that created this page." + hr +} + +proc app_body_end {} { + hr; puts "[cgi_link logolink]" + puts "Report problems with this script to [link admin]." + br; puts "CGI script author: [link Don], [link NIST]" + br; puts "Go back to [link CGITCL] or [link examples]." +} + +cgi_body_args bgcolor=#00b0b0 text=#ffffff + +proc user_error {msg} { + h3 "Error: $msg" + cgi_exit +} + +# support for rare examples that must be explicitly framed +proc describe_in_frame {title msg} { + if {0 == [catch {cgi_import header}]} { + cgi_title $title + cgi_body { + p $msg + } + exit + } +} diff --git a/web/src/cgi.tcl-1.10/example/examples.cgi b/web/src/cgi.tcl-1.10/example/examples.cgi new file mode 100755 index 00000000..75afb1e9 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/examples.cgi @@ -0,0 +1,81 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + input + + title "cgi.tcl examples" + + # use targets if we are framed + if {0==[catch {import framed}]} { + set target "target=script" + } else { + set target "" + } + + # create a hyperlink to run a script + proc run {name} { + url $name.cgi [cgi $name] [uplevel {set target}] + } + + # create hyperlink to show script source + proc display {name} { + url $name.cgi [cgi display scriptname=$name.cgi] [uplevel {set target}] + } + + body bgcolor=#d0a0a0 text=#000000 { + p "These are examples of cgi.tcl, a CGI support library for Tcl + programmers. If you would like to show off what you've + written with cgi.tcl, give me an html-formatted blurb and I'll + add it to a page of [link realapps]. For more information, + visit the [link CGITCL]." + + bullet_list { + li "[run cookie] - Cookie example. Also see [run passwd-form] to see cookies in the context of a real application." + li "[run creditcard] - Check a credit card." + li "[run download] - Demonstrate file downloading. Also see [run upload]." + li "[run echo] - Echo everything - good for debugging forms." + li "[run error] - Error handling example." + li "[run evaljs] - Evaluate an expression using JavaScript." + li "[run examples] - Generate the page you are now reading." + li "[run form-tour] and [display form-tour-result] - Show + many different form elements and the backend to process them." + li "[run format-tour] - Demonstrate many formats." + li "[run frame] - Framed example (of this page)." + li "[url "image.cgi" [cgi display-in-frame [cgi_cgi_set scriptname \ + image.cgi]] $target] - Produce a raw image." + li "[run img] - Examples of images embedded in a page." + li "[run kill] - Allow anyone to kill runaway CGI processes." + li "[display oratcl] - Use [link Oratcl] to query an Oracle database." + li "[run nistguest] - Specialized guestbook" + li "[run parray] - Demonstrate parray (print array elements)." + li "[run passwd-form] and [display passwd] - Form for + changing a password and its backend. Note that this CGI script + is [bold not] setuid because it is written using [link Expect]. + The script also demonstrates a nice use of cookies." + li "[run push] - Demonstrate server-push." + li "[run rm] - Allow anyone to remove old CGI files from /tmp." + li "[run stopwatch] - A stopwatch written as a Tcl applet." + li "[display unimail] - A universal mail backend that mails the + values of any form back to the form owner." + li "[run upload] - Demonstrate file uploading. Also see [run download]." + li "[run utf] - Demonstrate UTF output." + li "[run validate] - Validate input fields using JavaScript." + li "[run vclock] - Lincoln Stein's virtual clock. + This was the big example in his CGI.pm paper. Examine the + source to [eval url [list "his Perl version"] \ + [cgi display scriptname=vclock.pl] $target] or compare them + [url "side by side" [cgi vclock-src-frame] target=script2]." + li "[run visitor] - Example of a visitor counter." + li "[run version] - Show version information." + li "[run vote] - Vote for a quote." + li "[run display] - Display a CGI script with clickable + source commands. Not a particularly interesting application - + just a utility to help demo these other CGI scripts! But it is + written using cgi.tcl so it might as well be listed here." + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/form-tour-result.cgi b/web/src/cgi.tcl-1.10/example/form-tour-result.cgi new file mode 100755 index 00000000..d1278ecf --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/form-tour-result.cgi @@ -0,0 +1,69 @@ +#!/depot/path/tclsh + +# This is a CGI script that shows the result of the form tour. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + cgi_title "Form Element Tour Results" + + cgi_body { + h4 "This is a report of variables set by the form tour." + + if {0!=[catch {cgi_import Foo0}]} { + h5 "Error: It appears that you have invoked this script + without going through [cgi_url "the intended form" [cgi_cgi form-tour]]." + cgi_exit + } + + catch { + cgi_import Map.x + cgi_import Map.y + puts "image button coordinates = ${Map.x},${Map.y}[nl]" + } + + catch { + cgi_import Action + puts "submit button Action=$Action[nl]" + br + } + + foreach x {version A B C D} { + catch { + cgi_import $x + puts "radio button \"$x\": [set $x][nl]" + } + } + catch { + cgi_import VegieList + puts "checkbox Vegielist = $VegieList[nl]" + } + for {set i 0} {$i<=6} {incr i} { + set var Foo$i + cgi_import $var + puts "text $var:" + cgi_preformatted { + puts [set $var] + } + } + for {set i 0} {$i<=9} {incr i} { + set var Foo1$i + cgi_import $var + puts "textvar $var:" + cgi_preformatted { + puts [set $var] + } + } + catch { + cgi_import Foo + puts "select pull-down Foo: $Foo[nl]" + } + catch { + cgi_import FooList + puts "select scrolled list FooList: $FooList[nl]" + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/form-tour.cgi b/web/src/cgi.tcl-1.10/example/form-tour.cgi new file mode 100755 index 00000000..7e5e49d5 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/form-tour.cgi @@ -0,0 +1,123 @@ +#!/depot/path/tclsh + +# This is a CGI script that shows a selection of form elements +# This script doesn't actually DO anything. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "A Tour of Form Elements" + + cgi_body { + form form-tour-result { + h4 "Samples of image button" + cgi_put "image as button" + cgi_image_button "=http://www.nist.gov/msidimages/title.gif" + br + cgi_put "image as button (and will return coords)" + cgi_image_button "Map=http://www.nist.gov/public_affairs/gallery/fireseat.jpg" + + h4 "Samples of submit button" + cgi_submit_button + cgi_submit_button ="Submit" + cgi_submit_button "=Submit Form" + cgi_submit_button "Action=Pay Raise" + + h4 "Samples of reset button" + cgi_reset_button + cgi_put "Default Reset Button" + br + cgi_reset_button "Not the Default Reset Button" + cgi_put "Not the Default Reset Button" + + h4 "Samples of radio button" + cgi_radio_button "version=1" + cgi_put "Version 1" + br + cgi_radio_button "version=2" + cgi_put "Version 2" + br + cgi_radio_button "version=3" checked + cgi_put "Version 3" + + br + foreach x {A B C D} { + cgi_radio_button "$x=" checked_if_equal=B + cgi_put "$x" + br + } + + h4 "Samples of checkbox" + cgi_checkbox VegieList=carrot + cgi_put "Carrot" + br + cgi_checkbox VegieList=rutabaga checked + cgi_put "Rutabaga" + br + cgi_checkbox VegieList= + cgi_put "Vegie" + + h4 "Samples of textentry" + set Foo0 "value1" + set Foo1 "value1" + cgi_text Foo0 + br;cgi_text Foo1= + br;cgi_text Foo2=value2 + br;cgi_text Foo3=value2 size=5 + br;cgi_text Foo4=value2 size=5 maxlength=10 + br;cgi_text Foo5=value2 size=10 maxlength=5 + br;cgi_text Foo6=value2 maxlength=5 + + h4 "Samples of textarea" + + set value "A really long line so that we can compare the\ + effect of wrap options." + + set Foo10 "value1" + set Foo11 "value1" + cgi_textarea Foo10 + br;cgi_textarea Foo11= + br;cgi_textarea Foo12=$value + br;cgi_textarea Foo13=$value rows=3 + br;cgi_textarea "Foo14=default wrap" rows=3 cols=7 + br;cgi_textarea Foo15=wrap=off rows=3 cols=7 wrap=off + br;cgi_textarea Foo16=wrap=soft rows=3 cols=7 wrap=soft + br;cgi_textarea Foo17=wrap=hard rows=3 cols=7 wrap=hard + br;cgi_textarea Foo18=wrap=physical rows=3 cols=7 wrap=physical + br;cgi_textarea Foo19=wrap=virtual rows=3 cols=7 wrap=virtual + + h4 "Samples of select as pull-down menu" + cgi_select Foo { + cgi_option one selected + cgi_option two + cgi_option many value=hello + } + + h4 "Samples of select as scrolled list" + cgi_select FooList multiple { + cgi_option one selected + cgi_option two selected + cgi_option many + } + br + cgi_select FooList multiple size=2 { + cgi_option two selected + cgi_option three selected + cgi_option manymore + } + br + # choose "selected" dynamically + cgi_select FooList multiple size=5 { + foreach o [info comm] { + cgi_option $o selected_if_equal=exit + } + } + h4 "Samples of isindex" + } + cgi_isindex + cgi_isindex "prompt=Enter some delicious keywords: " + } +} + diff --git a/web/src/cgi.tcl-1.10/example/format-tour.cgi b/web/src/cgi.tcl-1.10/example/format-tour.cgi new file mode 100755 index 00000000..b399279f --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/format-tour.cgi @@ -0,0 +1,101 @@ +#!/depot/path/tclsh + +# This is a CGI script that shows a selection of format elements + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "A Tour of HTML Elements" + cgi_body { + + definition_list { + term "term" + term_definition "definition of term" + } + + h4 "menu list" + menu_list { + li item1 + li item2 + } + + h4 "directory list" + directory_list { + li item1 + li item2 + } + + h4 "a list item by itself" + li "item" + + h4 "number list (roman, starting from 4)" + number_list type=i value=4 { + li "first element" + li "second" + li value=9 "third, start numbering from 9" + li type=A "fourth, switch to upper-arabic" + } + + h4 "bullet list" + bullet_list { + p "plain text" + li "plain item" + h4 "nested list (disc, starting from 4)" + bullet_list type=disc value=4 { + li "first element" + li "second" + li type=circle "third, type=circle" + li type=square "fourth, type=square" + li "fifth, should remain square" + } + } + + h4 "Character formatting samples" + cgi_put "[bold bold]\ + [italic italic]\ + [underline underline]\ + [strikeout strikeout]\ + [subscript subscript]\ + [superscript superscript]\ + [typewriter typewriter]\ + [blink blink] + [emphasis emphasis]\ + [strong strong]\ + [cite cite]\ + [sample sample]\ + [keyboard keyboard]\ + [variable variable]\ + [definition definition]\ + [big big]\ + [small small]\ + [font color=#4499cc "color=#4499cc"]\ + " + for {set i 1} {$i<8} {incr i} { + puts [cgi_font size=$i "size=$i"] + } + + h4 "Paragraph formatting samples" + + cgi_h1 h1 + cgi_h2 h2 + cgi_h3 h3 + cgi_h4 h4 + cgi_h5 h5 + cgi_h6 h6 + cgi_h7 "h7 (beyond the spec, what the heck)" + cgi_h6 align=right "right-aligned h6" + cgi_p align=right "right-aligned paragraph" + cgi_put put + cgi_blockquote "blockquote" + cgi_address address + cgi_division { + puts "division" + } + cgi_preformatted { + puts "preformatted" + } + } +} + diff --git a/web/src/cgi.tcl-1.10/example/frame.cgi b/web/src/cgi.tcl-1.10/example/frame.cgi new file mode 100755 index 00000000..f8338b47 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/frame.cgi @@ -0,0 +1,32 @@ +#!/depot/path/tclsh + +# This is a CGI script that creates some frames. + +package require cgi + +cgi_eval { + source example.tcl + cgi_input + + cgi_title "Frame example" + + # allow URL's of the form ;# frame.cgi?example=.... + # so as to override default + set example examples ;# default is the examples page itself!! + catch {cgi_import example} + + cgi_frameset rows=100,* { + cgi_frame =$CGITCL + cgi_frameset cols=200,* { + cgi_frame =examples.cgi?framed=yes + cgi_frame script=$example.cgi + } + } + cgi_noframes { + cgi_h1 "uh oh" + + p "This document is designed to be viewed by a Frames-capable + browser. If you see this message your browser is not + Frames-capable." + } +} diff --git a/web/src/cgi.tcl-1.10/example/image.cgi b/web/src/cgi.tcl-1.10/example/image.cgi new file mode 100755 index 00000000..e1321523 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/image.cgi @@ -0,0 +1,29 @@ +#!/depot/path/tclsh +# See description below. + +package require cgi + +cgi_eval { + source example.tcl + cgi_input + + describe_in_frame "raw image" "This CGI script generates a raw + image. The script could be much more complicated - the point is + merely to show the framework. (The picture is of the US National + Prototype Kilogram. It is made of 90% platinum, 10% iridium. It + was assigned to the US in 1889 and is periodically recertified and + traceable to [italic "The Kilogram"] held at + [url "Bureau International des Poids et Mesures" http://www.bipm.fr" $TOP] + in France.)" + + # ignore the junk above this line - the crucial stuff is below + + cgi_content_type "image/jpeg" + + set fh [open $DATADIR/kg.jpg r] + fconfigure stdout -translation binary + fconfigure $fh -translation binary + fcopy $fh stdout + close $fh +} + diff --git a/web/src/cgi.tcl-1.10/example/img.cgi b/web/src/cgi.tcl-1.10/example/img.cgi new file mode 100755 index 00000000..4c84787d --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/img.cgi @@ -0,0 +1,39 @@ +#!/depot/path/tclsh + +# This is a CGI script that shows how to do simple images. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "Images" + + set NIST_IMAGES http://www.nist.gov/images + + cgi_imglink ball $NIST_IMAGES/ball.gif alt=ball + cgi_imglink birdies $NIST_IMAGES/brd-ln.gif alt=birdies + cgi_imglink daemon $NIST_IMAGES/bsd_daemon.gif "alt=Kirk McKusick's BSD deamon" + + # use white background because some of these images require it + cgi_body bgcolor=#ffffff text=#00b0b0 { + + p "Here are some birdies:[cgi_imglink birdies]" + p "and here is your basic ball [cgi_imglink ball] and here is + the BSD daemon [cgi_imglink daemon]." + + p "I like using the same picture" + p "[cgi_imglink ball] over" + p "[cgi_imglink ball] and over" + p "[cgi_imglink ball] and over" + p "[cgi_imglink ball] so I use the cgi_imglink command to make it easy." + + proc ball {} {return [cgi_imglink ball]} + + p "[cgi_imglink birdies]" + + p "[ball]I can make it even easier [ball] by making a ball + procedure [ball] which I've just done. [ball] You could + tell, eh? [ball]" + } +} diff --git a/web/src/cgi.tcl-1.10/example/kill.cgi b/web/src/cgi.tcl-1.10/example/kill.cgi new file mode 100755 index 00000000..f3ffe6a3 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/kill.cgi @@ -0,0 +1,69 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_title "Kill runaway CGI processes" + + cgi_body { + if {0==[catch {cgi_import PidList}]} { + catch {cgi_import Refresh;set PidList {}} + cgi_import Sig + h4 "If this were not a demo, the following commands would be executed:" + foreach pid $PidList { + # to undemoize this and allow processes to be killed, + # change h5 to exec and remove the quotes + if {[catch {h5 "kill -$Sig $pid"} msg]} { + h4 "$msg" + } + } + } + + cgi_form kill { + set ps /bin/ps + if {[file exists /usr/ucb/ps]} { + set ps /usr/ucb/ps + } + + set f [open "|$ps -auxww" r] + table border=2 { + table_row { + table_data {puts kill} + table_data {cgi_preformatted {puts [gets $f]}} + } + while {-1 != [gets $f buf]} { + if {[regexp "$argv0" $buf]} continue + if {![regexp "^http" $buf]} continue + table_row { + table_data { + scan $buf "%*s %d" pid + cgi_checkbox PidList=$pid + } + table_data { + cgi_preformatted {puts $buf} + } + } + } + + } + + submit_button "=Send signal to selected processes" + submit_button "Refresh=Refresh listing" + reset_button + + br; radio_button "Sig=TERM" checked; puts "SIGTERM: terminate gracefully" + br; radio_button "Sig=KILL"; puts "SIGKILL: terminate ungracefully" + br; radio_button "Sig=STOP"; puts "SIGSTOP: suspend" + br; radio_button "Sig=CONT"; puts "SIGCONT: continue" + + p "SIGSTOP and SIGCONT are particularly useful if the + processes aren't yours and the owner isn't around to ask. + Suspend them and let the owner decide later whether to + continue or kill them." + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/nistguest b/web/src/cgi.tcl-1.10/example/nistguest new file mode 100644 index 00000000..651efc9a --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/nistguest @@ -0,0 +1,102 @@ +Alabama +{} {} x +Alaska +{} {} {} +Arizona +{} {} {} +Arkansas +{} {} x +California +{} {} {} +Colorado +{} {} x +Connecticut +{} {} x +Delaware +{} {} x +Florida +{} {} x +Georgia +{} {} {} +Hawaii +{} {} {} +Idaho +{} {} {} +Illinois +{} {} {} +Indiana +{} {} x +Iowa +{} {} x +Kansas +{} {} {} +Kentucky +{} {} {} +Louisiana +{} {} {} +Maine +{} {} x +Maryland +{} {} x +Massachusetts +{} {} {} +Michigan +{} {} x +Minnesota +{} {} x +Mississippi +{} {} {} +Missouri +{} {} x +Montana +{} {} {} +Nebraska +{} {} x +Nevada +{} {} {} +New Hampshire +{} {} x +New Jersey +{} {} x +New Mexico +{} {} {} +New York +{} {} x +North Carolina +{} {} x +North Dakota +{} {} {} +Ohio +{} {} {} +Oklahoma +{} {} x +Oregon +{} {} {} +Pennsylvania +{} {} {} +Rhode Island +{} {} {} +South Carolina +{} {} x +South Dakota +{} {} x +Tennessee +{} {} x +Texas +{} {} x +Utah +{} {} x +Vermont +{} {} {} +Virginia +{} {} x +Washington +{} {} x +Washington DC +{} {} {} +West Virginia +{} {} {} +Wisconsin +{} {} x +Wyoming +{} {} {} diff --git a/web/src/cgi.tcl-1.10/example/nistguest.cgi b/web/src/cgi.tcl-1.10/example/nistguest.cgi new file mode 100755 index 00000000..b41d456b --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/nistguest.cgi @@ -0,0 +1,130 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + cgi_input + + cgi_title "NIST Guest Book" + + cgi_uid_check http + + set BarURL $EXPECT_ART/pink.gif + + set Q(filename) "$DATADIR/nistguest" + + set statesNeeded {} + + proc poll_read {} { + global Q + + set fid [open $Q(filename) r] + while {-1!=[gets $fid StateFullName]} { + regsub " " $StateFullName "" State + set Q($State) $StateFullName + gets $fid buf + foreach "Q($State,1) Q($State,2) Q($State,3)" $buf {} + lappend Q(statesAll) $State + if {0 == [string compare "" "$Q($State,3)"]} { + lappend Q(statesNeeded) $State + } + } + close $fid + } + + proc poll_write {} { + global Q + + # No file locking or real database handy so we can't guarantee that + # simultaneous votes aren't dropped, but we'll at least avoid + # corruption of the file by working on a private copy. + set tmpfile $Q(filename).[pid] + set fid [open $tmpfile w] + foreach state $Q(statesAll) { + set data [list $Q($state,1) $Q($state,2) $Q($state,3)] + puts $fid $Q($state)\n$data + } + close $fid + exec mv $tmpfile $Q(filename) + } + + cgi_body { + poll_read + + if {0 == [catch {cgi_import State}]} { + if {![info exists Q($State)]} { + user_error "There is no such state: $State" + } + + set Name "" + catch {import Name} + if {0==[string length $Name]} { + user_error "You didn't provide your name." + } + + set Email "" + catch {import Email} + + set Description "" + catch {import Description} + if {0==[string length $Description]} { + user_error "You didn't provide a description." + } + + set data "<Name $Name><Email $Email><Description $Description>" + # simplify poll_read by making each entry a single line + regsub -all \n $data " " data + + if {0 == [string compare "" $Q($State,1)]} { + set Q($State,1) $data + } elseif {0 == [string compare "" $Q($State,2)]} { + set Q($State,2) $data + } else { + set Q($State,3) $data + } + + poll_write + puts "Thanks for your submission!" + + return + } + + form nistguest { + puts "In the spirit of Scriptics' request for Tcl success +stories, our group at NIST is looking for some too. It's time for our +annual report to Congress. So if your state appears in the list below +and you can provide a brief description of how our work has helped +you, we would appreciate hearing from you." + hr + br;puts "If your state does not appear in this list, then we +already have enough entries for your state. Thanks anyway!" + br;puts "State:" + cgi_select State { + foreach state $Q(statesNeeded) { + option "$Q($state)" value=$state + } + } + + br;puts "Full name:" + cgi_text Name= + + br;puts "We probably won't need to contact you; But just in +case, please provide some means of doing so. Email info will remain +confidential - you will NOT be put on any mailing lists." + br;puts "Email:" + cgi_text Email= + puts "(optional)" + + p "Please describe a significant impact (e.g., goals +accomplished, hours/money saved, user expectations met or exceeded) +that NIST's Tcl-based work (Expect, cgi.tcl, APDE, APIB, EXPRESS +server, ...) has had on your organization. A brief paragraph is +fine." + + cgi_textarea Description= rows=10 cols=80 + br + submit_button "=Submit" + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/oratcl.cgi b/web/src/cgi.tcl-1.10/example/oratcl.cgi new file mode 100644 index 00000000..de4a7626 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/oratcl.cgi @@ -0,0 +1,33 @@ +#!/depot/path/tclsh + +# This is a CGI script that demonstrates how easy it is to use a web +# page to query an Oracle server - using cgi.tcl and Oratcl. +# This example fetches the date from Oracle. + +# I wish we had a public account on our Oracle server so that I could +# allow anyone to run this, but alas we don't. So you'll have to +# trust me that it works. - Don + +package require cgi +package require Oratcl + +cgi_eval { + source example.tcl + + cgi_title "Oracle Example" + cgi_input + + cgi_body { + set env(ORACLE_SID) fork + set env(ORACLE_HOME) /u01/oracle/product/7322 + + set logon [oralogon [import user] [import password]] + set cursor [oraopen $logon] + + orasql $cursor "select SysDate from Dual" + h4 "Oracle's date is [orafetch $cursor]" + + oraclose $cursor + oralogoff $logon + } +} diff --git a/web/src/cgi.tcl-1.10/example/parray.cgi b/web/src/cgi.tcl-1.10/example/parray.cgi new file mode 100755 index 00000000..a4c23316 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/parray.cgi @@ -0,0 +1,48 @@ +#!/depot/path/tclsh + +# This is a CGI script that displays the environment or another array. + +package require cgi + +cgi_eval { + source example.tcl + + proc arrays {} { + uplevel #0 { + set buf {} + foreach a [info globals] { + if {[array exists $a]} { + lappend buf $a + } + } + return $buf + } + } + + cgi_input + + cgi_title "Display environment or another array" + + cgi_body { + p "This script displays the environment or another array." + if {[catch {cgi_import Name}]} { + set Name env + } + + cgi_form parray { + cgi_select Name { + foreach a [arrays] { + cgi_option $a selected_if_equal=$Name + } + } + cgi_submit_button + } + + global $Name + if {[array exist $Name]} { + cgi_parray $Name + } else { + puts "$Name: no such array" + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/passwd-form.cgi b/web/src/cgi.tcl-1.10/example/passwd-form.cgi new file mode 100755 index 00000000..9d99b716 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/passwd-form.cgi @@ -0,0 +1,39 @@ +#!/depot/path/tclsh + +# This is a CGI script to present a form in which to change a password. + +# This form doesn't actually have to be written as a CGI script, +# however, it is done so here to demonstrate the procedures described +# in the Tcl '96 paper by Don Libes. You can find this same form +# written as static html in the example directory of the Expect +# package. + +package require cgi + +cgi_eval { + source example.tcl + source passwd.tcl + + cgi_input + + # Use a cookie so that if user has already entered name, don't make them + # do it again. If you dislike cookies, simply remove the next two + # lines - cookie use here is simply a convenience for users. + set login "" + catch {cgi_import_cookie login} + + cgi_title "Change your login password" + cgi_body { + cgi_form passwd { + put "Username: "; cgi_text login size=16 + password "Old" old + password "New" new1 + password "New" new2 + + p "(The new password must be entered twice to avoid typos.)" + + cgi_submit_button "=Change password" + cgi_reset_button + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/passwd.cgi b/web/src/cgi.tcl-1.10/example/passwd.cgi new file mode 100755 index 00000000..85c18174 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/passwd.cgi @@ -0,0 +1,119 @@ +#!/depot/path/expect -- + +# This is a CGI script to process requests created by the accompanying +# passwd.html form. This script is pretty basic, although it is +# reasonably robust. (Purposely intent users can make the script bomb +# by mocking up their own HTML form, however they can't expose or steal +# passwords or otherwise open any security holes.) This script doesn't +# need any special permissions or ownership. +# +# With a little more code, the script can do much more exotic things - +# for example, you could have the script: +# +# - telnet to another host first (useful if you run CGI scripts on a +# firewall), or +# +# - change passwords on multiple password server hosts, or +# +# - verify that passwords aren't in the dictionary, or +# +# - verify that passwords are at least 8 chars long and have at least 2 +# digits, 2 uppercase, 2 lowercase, or whatever restrictions you like, +# or +# +# - allow short passwords by responding appropriately to passwd +# +# and so on. Have fun! +# +# Don Libes, NIST + +package require cgi + +cgi_eval { + source example.tcl + source passwd.tcl + + cgi_input + + # Save username as cookie (see comment in passwd-form script) so that the + # next time users load the form, their username will already be filled in. + # If cookies bother you, simply remove this entire cgi_http_head command. + cgi_http_head { + cgi_content_type text/html + if {0==[catch {cgi_import login}]} { + cgi_export_cookie login expires=never + } + } + + cgi_title "Password Change Acknowledgment" + cgi_body { + if {(![info exists login]) + || [catch {cgi_import old}] + || [catch {cgi_import new1}] + || [catch {cgi_import new2}]} { + errormsg "This page has been called with input missing. Please \ + visit this form by filling out the password change \ + request form." + return + } + + # Prevent user from sneaking in commands (albeit under their own uid). + if {[regexp "\[^a-zA-Z0-9]" $login char]} { + errormsg "Illegal character ($char) in username." + return + } + + log_user 0 + + # Need to su first to get around passwd's requirement that + # passwd cannot be run by a totally unrelated user. Seems + # rather pointless since it's so easy to satisfy, eh? + + # Change following line appropriately for your site. + # (We use yppasswd, but you might use something else.) + spawn /bin/su $login -c "/bin/yppasswd $login" + # This fails on SunOS 4.1.3 (passwd says "you don't have a + # login name") so run on (or telnet first to) host running + # SunOS 4.1.4 or later. + + expect { + -re "Unknown (login|id):" { + errormsg "unknown user: $login" + return + } default { + errormsg "$expect_out(buffer)" + return + } "Password:" + } + send "$old\r" + expect { + "unknown user" { + errormsg "unknown user: $login" + return + } "Sorry" { + errormsg "Old password incorrect" + return + } default { + errormsg "$expect_out(buffer)" + return + } "Old password:" + } + send "$old\r" + expect "New password:" + send "$new1\r" + expect "New password:" + send "$new2\r" + expect -re (.+)\r\n { + set error $expect_out(1,string) + } + close + wait + + if {[info exists error]} { + errormsg "$error" + } else { + successmsg "Password changed successfully." + } + } +} + diff --git a/web/src/cgi.tcl-1.10/example/passwd.tcl b/web/src/cgi.tcl-1.10/example/passwd.tcl new file mode 100644 index 00000000..31de1e17 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/passwd.tcl @@ -0,0 +1,10 @@ +# common definitions for all password-related pages + +proc password {prompt varname} { + br + put "$prompt password: " + cgi_text $varname= type=password size=16 +} + +proc successmsg {s} {h3 "$s"} +proc errormsg {s} {h3 "Error: $s"} diff --git a/web/src/cgi.tcl-1.10/example/push.cgi b/web/src/cgi.tcl-1.10/example/push.cgi new file mode 100755 index 00000000..75aeb98c --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/push.cgi @@ -0,0 +1,37 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + set boundary "ThisRandomString" + + cgi_http_head { + cgi_content_type "multipart/x-mixed-replace;boundary=$boundary" + + puts \n--$boundary + cgi_content_type + } + + cgi_title "Multipart example - 1st page" + cgi_body { + h4 "This is an example of [italic server-push] as implemented + by the multipart MIME type. In contrast with client-pull, push + leaves the connection open and the CGI script remains in control + as to send more information. The additional information can + be anything - this example demonstrates an entire page being + replaced." + } + + puts \n--$boundary + after 5000 + + cgi_content_type + + cgi_title "Multipart example - 2nd page" + cgi_body { + h4 "This page replaced the previous page with no action on the + client side." + } +} diff --git a/web/src/cgi.tcl-1.10/example/rm.cgi b/web/src/cgi.tcl-1.10/example/rm.cgi new file mode 100644 index 00000000..bc9534af --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/rm.cgi @@ -0,0 +1,59 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_title "Remove old CGI files from /tmp" + + cgi_body { + if {0==[catch {cgi_import FileList}]} { + catch {cgi_import Refresh;set FileList {}} + h4 "If this were not a demo, the following commands would have been executed:" + foreach File $FileList { + # prevent deletion of this dir or anything outside it + set File [file tail $File] + switch $File . - .. - "" { + h3 "Illegal filename: $File" + continue + } + + # to undemoize this and allow files to be killed, + # remove h5 and quotes + if {[catch {h5 "file delete -force /tmp/$File"} msg]} { + h4 "$msg" + } + } + } + + cgi_form rm { + set f [open "|/bin/ls -Alt /tmp" r] + table border=2 { + table_row { + table_data {puts "rm -rf"} + table_data {cgi_preformatted {puts "permissions ln owner group size date filename"}} + } + while {-1 != [gets $f buf]} { + if {![regexp " http " $buf]} continue + table_row { + table_data { + regexp ".* (\[^ ]+)$" $buf dummy File + cgi_checkbox FileList=$File + } + table_data { + cgi_preformatted {puts $buf} + } + } + } + + } + + submit_button "=Removed selected files" + submit_button "Refresh=Refresh listing" + reset_button + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/stopwatch.cgi b/web/src/cgi.tcl-1.10/example/stopwatch.cgi new file mode 100755 index 00000000..4fb4f8c3 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/stopwatch.cgi @@ -0,0 +1,64 @@ +#!/depot/path/tclsh + +# This is a CGI script that demonstrates a simple Tcl applet + +package require cgi + +source example.tcl + +set srcdir http://www.nist.gov/mel/div826/src/stopwatch +set plugins http://www.sunlabs.com/research/tcl/plugin + +cgi_link source "source" $srcdir/stopwatch.tcl.html" +cgi_link gz "complete distribution" $srcdir/stopwatch.tar.gz +cgi_link moreplugins "More info on Tcl plugins" $plugins +cgi_link homepage "homepage" $EXPECT_HOST/stopwatch + +cgi_eval { + + cgi_input + + cgi_head { + cgi_title "Stopwatch implemented via Tcl applet" + } + cgi_body { + h3 "Description" + + p "This tclet provides a stopwatch. I wrote it to help me + time talks and individual slides within a talk. Stopwatch can + also be run as a Tk script outside the browser - which is the + way I normally use it. If you want to use it outside the browser, grab the distribution from the stopwatch [cgi_link homepage]." + + h3 "Directions" + + p {Press "start" to start the stopwatch and "stop" to stop it. + "zero" resets the time. You can also edit/cut/paste the time + by hand and set it to any valid time. A second timer is + provided as well. It works just like a normal lap timer.} + + cgi_embed http://www.nist.gov/mel/div826/src/stopwatch/stopwatch.tcl \ + 450x105 + + p "This is the first Tclet I've ever written. Actually, I + just took an existing Tk script I had already written and + wrapped it in an HTML page. It took about 30 minutes to write + the original Tk script (about 80 lines) and 1 minute to embed + it in an HTML page." + + p "Stopwatch is not intended for timing less than one second + or longer than 99 hours. It's easy to make make it show more + but the code doesn't do it as distributed and I have no + interest in adding more and more features until it reads mail. + It's just a nice, convenient stopwatch." + + h3 "For more info" + + cgi_bullet_list { + cgi_li "Stopwatch [cgi_link homepage]." + cgi_li "Stopwatch [cgi_link source] and [cgi_link gz]." + cgi_li "[cgi_link moreplugins]." + } + } +} + + diff --git a/web/src/cgi.tcl-1.10/example/unimail.cgi b/web/src/cgi.tcl-1.10/example/unimail.cgi new file mode 100755 index 00000000..9fca7cb0 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/unimail.cgi @@ -0,0 +1,58 @@ +#!/depot/path/tclsh + +# This script is a universal mail backend. It's handy for creating +# forms that simply email all their elements to someone else. You +# wouldn't use it in a fancy application, but non-programmers like it +# since they can use it to process forms with no CGI scripting at all. +# +# To use, make your form look something like this: +# +# <form action="http://ats.nist.gov/cgi-bin/cgi.tcl/unimail.cgi" method=post> +# <input type=hidden name=mailto value="YOUR EMAIL ADDRESS HERE"> +# ...rest of your form... +# </form> +# +# Note: You can use our action URL to try this out, but please switch +# to using your own local unimail script for production use. Thanks! +# +# Author: Don Libes, NIST + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "Universal mail backend" + + cgi_body { + if {[catch cgi_input errormsg]} { + h2 "Form Error" + p "An error was detected in the form. Please send the + following diagnostics to the form author." + cgi_preformatted {puts $errormsg} + return + } + if {[catch {cgi_import mailto}]} { + h2 "Error: No mailto variable in form." + return + } + if {![info exists env(HTTP_REFERER)]} { + set env(HTTP_REFERER) "unknown" + } + cgi_mail_start $mailto + cgi_mail_add "Subject: submission from web form: $env(HTTP_REFERER)" + cgi_mail_add + catch {cgi_mail_add "Remote addr: $env(REMOTE_ADDR)"} + catch {cgi_mail_add "Remote host: $env(REMOTE_HOST)"} + + foreach item [cgi_import_list] { + cgi_mail_add "$item: [cgi_import $item]" + } + cgi_mail_end + + if {[catch {cgi_import thanks}]} { + set thanks [cgi_buffer {h2 "Thanks for your submission."}] + } + cgi_put $thanks + } +} diff --git a/web/src/cgi.tcl-1.10/example/upload.cgi b/web/src/cgi.tcl-1.10/example/upload.cgi new file mode 100755 index 00000000..9841aa97 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/upload.cgi @@ -0,0 +1,59 @@ +#!/depot/path/tclsh + +# This is a CGI script that demonstrates file uploading. + +package require cgi + +cgi_eval { + source example.tcl + + proc showfile {v} { + catch { + set server [cgi_import_file -server $v] + set client [cgi_import_file -client $v] + set type [cgi_import_file -type $v] + if {[string length $client]} { + h4 "Uploaded: $client" + if {0 != [string compare $type ""]} { + h4 "Content-type: $type" + } + cgi_import showList + foreach show $showList { + switch $show { + "od -c" - "cat" { + h5 "Contents shown using $show" + cgi_preformatted {puts [eval exec $show [list $server]]} + } + } + } + } + exec /bin/rm -f $server + } + } + + cgi_input + + cgi_head { + cgi_title "File upload demo" + } + cgi_body { + if {[info tcl] < 8.1} { + h4 "Warning: This script can not perform binary uploads because the server is running a pre-8.1 Tcl ([info tcl])." + } + + showfile file1 + showfile file2 + + cgi_form upload enctype=multipart/form-data { + p "Select up to two files to upload" + cgi_file_button file1; br + cgi_file_button file2; br + checkbox "showList=cat" checked; + put "show contents using cat" ;br + checkbox "showList=od -c" + put "show contents using od -c" ;br + cgi_submit_button =Upload + } + } +} + diff --git a/web/src/cgi.tcl-1.10/example/utf.cgi b/web/src/cgi.tcl-1.10/example/utf.cgi new file mode 100644 index 00000000..1a5a1243 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/utf.cgi @@ -0,0 +1,17 @@ +#!/local/bin/tclsh + +# Test UTF encoding + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "Study utf encoding" + cgi_html { + cgi_body { + p "I'm going to be living on the Straüße." + } + } +} + diff --git a/web/src/cgi.tcl-1.10/example/validate.cgi b/web/src/cgi.tcl-1.10/example/validate.cgi new file mode 100755 index 00000000..c104b7b5 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/validate.cgi @@ -0,0 +1,76 @@ +#!/depot/path/tclsh + +# This CGI script uses JavaScript to validate a form before submission. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + cgi_head { + title "Using JavaScript to validate a form before submission" + + javascript { + puts { + function odd(num) { + if (num.value % 2 == 0) { + alert("Please enter an odd number!") + num.value = "" + return false + } + return true + } + } + } + noscript { + puts "Sorry - your browser doesn't understand JavaScript." + } + } + + set rownum 0 + proc row {msg {event {}}} { + global rownum + + incr rownum + table_row { + table_data nowrap { + put "Odd number: " + text num$rownum= size=4 $event + } + table_data { + puts $msg + } + } + } + + cgi_body { + set more "" + if {0 == [catch {import num3}]} { + set count [scan $num3 %d num] + if {($count != 1) || ($num % 2 == 0)} { + p "Hey, you didn't enter an odd number!" + } else { + p "Thanks for entering odd numbers!" + set more " more" + } + } + + puts "Please enter$more odd numbers - thanks!" + + cgi_form validate "onSubmit=return odd(this.num2)" { + table { + row "This number will be validated when it is entered." onChange=odd(this.form.num1) + row "This number will be validated when the form is submitted." + row "This number will be validated after the form is submitted." + } + submit_button =Submit + } + + h5 "Note: JavaScript validation should always be accompanied + by validation in the backend (CGI script) since browsers + cannot be relied upon to have JavaScript enabled (or supported + in the first place). Sigh." + } +} diff --git a/web/src/cgi.tcl-1.10/example/vclock-src-frame.cgi b/web/src/cgi.tcl-1.10/example/vclock-src-frame.cgi new file mode 100755 index 00000000..37cd6d4b --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/vclock-src-frame.cgi @@ -0,0 +1,23 @@ +#!/depot/path/tclsh + +# This CGI script displays the Tcl and Perl vclock source side by side. + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "Comparison of vclock source" + + cgi_frameset cols=50%,* { + cgi_frame =[cgi_cgi display scriptname=vclock.cgi] + cgi_frame =[cgi_cgi display scriptname=vclock.pl] + } + cgi_noframes { + cgi_h1 "uh oh" + + p "This document is designed to be viewed by a Frames-capable + browser. If you see this message your browser is not + Frames-capable." + } +} diff --git a/web/src/cgi.tcl-1.10/example/vclock.cgi b/web/src/cgi.tcl-1.10/example/vclock.cgi new file mode 100755 index 00000000..4b925b9f --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/vclock.cgi @@ -0,0 +1,73 @@ +#!/depot/path/tclsh + +# This script implements the "Virtual Clock" used as the example in the +# paper describing CGI.pm, a perl module for generating CGI. +# Stein, L., "CGI.pm: A Perl Module for Creating Dynamic HTML Documents +# with CGI Scripts", SANS 96, May '96. + +# Do you think it is more readable than the other version? +# (If you remove the comments and blank lines, it's exactly +# the same number of lines.) See other comments after script. - Don + +package require cgi + +cgi_eval { + source example.tcl + + cgi_input + + set format "" + if {[llength [cgi_import_list]]} { + if 0==[catch {cgi_import time}] { + append format [expr {[cgi_import type] == "12-hour"?"%r ":"%T "}] + } + catch {cgi_import day; append format "%A "} + catch {cgi_import month; append format "%B "} + catch {cgi_import day-of-month; append format "%d "} + catch {cgi_import year; append format "%Y "} + } else { + append format "%r %A %B %d %Y" + } + + set time [clock format [clock seconds] -format $format] + + cgi_title "Virtual Clock" + + cgi_body { + puts "At the tone, the time will be [strong $time]" + hr + h2 "Set Clock Format" + + cgi_form vclock { + puts "Show: " + foreach x {time day month day-of-month year} { + cgi_checkbox $x checked + put $x + } + br + puts "Time style: " + cgi_radio_button type=12-hour checked;put "12-hour" + cgi_radio_button type=24-hour ;put "24-hour" + br + cgi_reset_button + cgi_submit_button =Set + } + } +} + +# Notes: + +# Time/date generation is built-in to Tcl. Thus, no extra processes +# are necessary and the result is portable. In contrast, CGI.pm +# only runs on UNIX. + +# Displaying checkboxes side by side the way that CGI.pm does by +# default is awful. The problem is that with enough buttons, it's not +# immediately clear if the button goes with the label on the right or +# left. So cgi.tcl does not supply a proc to generate such a +# grouping. I've followed CGI.pm's style here only to show that it's +# trivial to get the same affect, but the formatting in any real form +# is more wisely left to the user. + +# Footer generation (<hr><address>... at end of CGI.pm) is replaced +# by "source example.tcl". Both take one line. diff --git a/web/src/cgi.tcl-1.10/example/vclock.pl b/web/src/cgi.tcl-1.10/example/vclock.pl new file mode 100644 index 00000000..0605f0c7 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/vclock.pl @@ -0,0 +1,59 @@ +#!/usr/local/bin/perl + +# This script is the "Virtual Clock" example in the seminal +# paper describing CGI.pm, a perl module for generating CGI. +# Stein, L., "CGI.pm: A Perl Module for Creating Dynamic HTML Documents +# with CGI Scripts", SANS 96, May '96. + +# Do you think it is more readable than the other version? +# (If you remove the comments and blank lines, it's exactly +# the same number of lines.) - Don + +use CGI; +$q = new CGI; + +if ($q->param) { + if ($q->param('time')) { + $format = ($q->param('type') eq '12-hour') ? '%r ' : '%T'; + } + + $format .= '%A ' if $q->param('day'); + $format .= '%B ' if $q->param('month'); + $format .= '%d ' if $q->param('day-of-month'); + $format .= '%Y ' if $q->param('year'); +} else { + $format = '%r %A %B %d %Y'; +} + +$time = `date '+$format'`; + +# print the HTTP header and the HTML document +print $q->header; +print $q->start_html('Virtual Clock'); +print <<END; +<H1>Virtual Clock</H1> +At the tone, the time will be <STRONG>$time</STRONG>. +END + +print <<END; +<HR> +<H2>Set Clock Format</H2> +END + +# Create the clock settings form +print $q->start_form; +print "Show: "; +print $q->checkbox(-name->'time',-checked=>1); +print $q->checkbox(-name->'day',-checked=>1); +print $q->checkbox(-name->'month',-checked=>1); +print $q->checkbox(-name->'day-of-month',-checked=>1); +print $q->checkbox(-name->'year',-checked=>1); +print "<P>Time style:"; +print $q->radio_group(-name=>'type', + -values=>['12-hour','24-hour']),"<P>"; +print $q->reset(-name=>'Reset'), + $q->submit(-name=>'Set'); +print $q->end_form; + +print '<HR><ADDRESS>webmaster@ferrets.com</ADDRESS>' +print $q->end_html; diff --git a/web/src/cgi.tcl-1.10/example/version.cgi b/web/src/cgi.tcl-1.10/example/version.cgi new file mode 100644 index 00000000..b266acfb --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/version.cgi @@ -0,0 +1,30 @@ +#!/depot/path/tclsh + +# This is a CGI script that displays some version information that I +# find useful for debugging. + +set v [package require cgi] + +proc row {var val} { + table_row { + td $var + td $val + } +} + +cgi_eval { + source example.tcl + + title "Version info" + + cgi_body { + table border=2 { + row "cgi.tcl" $v + row "Tcl" [info patchlevel] + row "uname -a" [exec uname -a] + catch {row "SERVER_SOFTWARE" $env(SERVER_SOFTWARE)} + catch {row "HTTP_USER_AGENT" $env(HTTP_USER_AGENT)} + catch {row "SERVER_PROTOCOL" $env(SERVER_PROTOCOL)} + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/visitor.cgi b/web/src/cgi.tcl-1.10/example/visitor.cgi new file mode 100755 index 00000000..ee73922e --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/visitor.cgi @@ -0,0 +1,30 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + + cgi_title "Visitor count example" + + cgi_body { + cgi_put "This page demonstrates how easy it is to do visitor counts." + + cgi_uid_check http + + cgi_form visitor { + set cfname "$DATADIR/visitor.cnt" + + if {[catch {set fid [open $cfname r+]} errormsg]} { + h4 "Couldn't open $cfname to maintain visitor count: $errormsg" + return + } + gets $fid count + seek $fid 0 start + puts $fid [incr count] + close $fid + h4 "You are visitor $count. Revisit soon!" + cgi_submit_button "=Revisit" + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/visitor.cnt b/web/src/cgi.tcl-1.10/example/visitor.cnt new file mode 100755 index 00000000..5595fa46 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/visitor.cnt @@ -0,0 +1 @@ +95 diff --git a/web/src/cgi.tcl-1.10/example/vote.cgi b/web/src/cgi.tcl-1.10/example/vote.cgi new file mode 100755 index 00000000..6d06b977 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/vote.cgi @@ -0,0 +1,190 @@ +#!/depot/path/tclsh + +package require cgi + +cgi_eval { + source example.tcl + cgi_input + + cgi_title "Vote for a t-shirt design!" + + cgi_uid_check http + + set BarURL $EXPECT_ART/pink.gif + + set Q(filename) "$DATADIR/vote.cnt" + + proc votes_read {} { + global Q + + set Q(Max) 0 + set Q(Votes) 0 + set Q(Indices) "" + + set fid [open $Q(filename) r] + while {-1!=[gets $fid i]} { + gets $fid buf + foreach "Q(Votes,$i) Q(Entry,$i) Q(Name,$i) Q(Email,$i)" $buf {} + lappend Q(Indices) $i + set Q(Unvotable,$i) [catch {incr Q(Votes) $Q(Votes,$i)}] + set Q(Max) $i + } + close $fid + } + + proc votes_write {} { + global Q + + # No file locking (or real database) handy so we can't guarantee that + # simultaneous votes aren't dropped, but we'll at least avoid + # corruption of the vote file by working on a private copy. + set tmpfile $Q(filename).[pid] + set fid [open $tmpfile w] + foreach i $Q(Indices) { + set data [list $Q(Votes,$i) $Q(Entry,$i) $Q(Name,$i) $Q(Email,$i)] + # simplify votes_read by making each entry a single line + regsub -all \n $data <br> data + puts $fid $i\n$data + } + close $fid + exec mv $tmpfile $Q(filename) + } + + proc vote_other_show {} { + global Q + + h3 "Other suggestions" + table border=2 { + table_row { + th width=300 "Entry" + th width=300 "Judge's Comments" + } + foreach i $Q(Indices) { + if {!$Q(Unvotable,$i)} continue + table_row { + td width=300 "$Q(Entry,$i)" + td width=300 "$Q(Votes,$i)" + } + } + } + } + + + cgi_body { + votes_read + + if {[regexp "Vote(\[0-9]+)" [cgi_import_list] dummy i]} { + if {[catch {incr Q(Votes,$i)}]} { + user_error "There is no such entry to vote for." + } + incr Q(Votes) + votes_write + + h3 "Thanks for voting! See you at the next Tcl conference!" + set ShowVotes 1 + } + catch {cgi_import ShowVotes} + if {[info exists ShowVotes]} { + table border=2 { + table_row { + th width=300 "Entry" + th "Votes" + th width=140 "Percent" ;# 100 + room for pct + } + foreach i $Q(Indices) { + if {!$Q(Unvotable,$i)} { + table_row { + td width=300 "$Q(Entry,$i)" + td align=right "$Q(Votes,$i)" + table_data width=140 { + table { + table_row { + set pct [expr 100*$Q(Votes,$i)/$Q(Votes)] + # avoid 0-width Netscape bug + set pct_bar [expr $pct==0?1:$pct] + td [img $BarURL align=left width=$pct_bar height=15] + td $pct + } + } + } + } + } + } + } + form vote { + submit_button "=Submit entry or vote" + submit_button "ShowVotes=Show votes" + } + vote_other_show + return + } + + if 0==[catch {import Entry}] { + if {[string length $Entry] == 0} { + user_error "No entry found." + } + if {[string length $Entry] > 500} { + user_error "Your entry is too long. Keep it under 500 characters!" + } + set Name "" + catch {import Name} + if 0==[string length $Name] { + user_error "You must supply your name. How are we going to know who you are if you win?" + } + set Email "" + catch {import Email} + if 0==[string length $Email] { + user_error "You must supply your email. How are we going to contact you if you win?" + } + + set i [incr Q(Max)] + set Q(Entry,$i) $Entry + set Q(Name,$i) $Name + set Q(Email,$i) $Email + set Q(Votes,$i) 1 + lappend Q(Indices) $i + + votes_write + + h3 "Thanks for your new entry!" + p "No need to go back and vote for it - a vote has already + been recorded for you." + form vote { + submit_button "=Submit another entry or vote" + submit_button "ShowVotes=Show votes" + } + return + } + + p "Vote for what will go on the next Tcl conference t-shirt! (Feel free to vote for several entries.)" + + cgi_form vote { + table border=2 { + foreach i $Q(Indices) { + if {$Q(Unvotable,$i)} continue + table_row { + table_data { + cgi_submit_button Vote$i=Vote + } + td "$Q(Entry,$i)" + } + } + } + br + cgi_submit_button "ShowVotes=Just show me the votes" + hr + p "The author of the winning entry gets fame and glory (and a free t-shirt)! Submit a new entry:" + cgi_text Entry= size=80 + p "Entries may use embedded HTML. Images or concepts are fine - for artwork, we have the same artist who did the [url "'96 conference shirt" $MSID_STAFF/libes/t.html]). The [url judges mailto:tclchairs@usenix.org] reserve the right to delete entries. (Do us a favor and use common sense and good taste!)" + puts "Name: " + cgi_text Name= + br + puts "Email: " + cgi_text Email= + br + cgi_submit_button "=Submit new entry" + + vote_other_show + } + } +} diff --git a/web/src/cgi.tcl-1.10/example/vote.cnt b/web/src/cgi.tcl-1.10/example/vote.cnt new file mode 100644 index 00000000..73bc9061 --- /dev/null +++ b/web/src/cgi.tcl-1.10/example/vote.cnt @@ -0,0 +1,30 @@ +1 +179 {Tcl/Tk: The best-kept secret in the software industry} {Michael McLennan} mmc +2 +{it's got potential, needs more work} {Tcl/Tk: Saving the world one proc at a time} {Michael McLennan} mmc +3 +24 {Tcl/Tk: Programmers by day, heros by the end of the quarter} {Michael McLennan} mmc +4 +39 {Tcl/Tk: The struggle between good and eval} {Michael McLennan} mmc +6 +{already dated} {I love Tcl...but <i>puleeez</i> don't call me Elmo!} {mark pernal} mpernal@sprintmail.com +7 +{surely we have more imagination?} spec-TCL-ular {Joerg Reiberg} reiberg@uni-muenster.de +8 +48 {Tcl/Tk: Less Code, More Results} {Bob Jackson} jackson@stsci.edu +9 +{committed alright} {True Committed Lover} {Stephan Uyttebroeck} stephan@frontierd.com +12 +{may we suggest you invest five minutes reading the manual...} {Tcl/Tk: Welcome to string quoting hell!} {Harry Bovik} bovik+junk@cs.cmu.edu +13 +{We'll make up a special one-of-a-kind t-shirt for you, ok?} {I'd rather be hacking Perl.} psu psu@jprc.com +15 +{has potential but needs more work} {Tcl/Tk: A Rabid Prototyping Language} {Ralph Melton} ralph@cs.cmu.edu +16 +{the important thing is, you were using it!} {Tcl/Tk: If at first you don't succeed, you must have been using it} {Dushyanth Narayanan} bumba=roc_tcltk@cs.cmu.edu +17 +{the Howard Stern / People Magazine version} {perl: the angry drunken scripting language} {John Prevost} visigoth+www@cs.cmu.edu +18 +{already taken by Perl, shucks} {Perl: a fast and powerful tool for creating completely inconsistent, incoherent, and unmaintainable code.} {Don} don@libes.com +19 +{ok, enough Perl bashing!} {Perl: an awesome collection of special cases, side-effects, neato punctuation, and enough ambiguity to make a Ouija board blush.} {Don} don@libes.com diff --git a/web/src/cgi.tcl-1.10/fixline1 b/web/src/cgi.tcl-1.10/fixline1 new file mode 100755 index 00000000..1cb57972 --- /dev/null +++ b/web/src/cgi.tcl-1.10/fixline1 @@ -0,0 +1,13 @@ +#!/depot/path/expect -- +# Synopsis: fixline1 newpath < input > output +# Author: Don Libes + +# Description: change first line of script to reflect new binary +# try to match any of the following first lines +#!expect ... +#!../expect ... +#!expectk ... +#!foo/bar/expectk ... +# +regsub "^#!(.*/)*(.*)" [gets stdin] "#!$argv/\\2" line1 +puts -nonewline "$line1\n[read stdin]" diff --git a/web/src/cgi.tcl-1.10/install-sh b/web/src/cgi.tcl-1.10/install-sh new file mode 100755 index 00000000..89fc9b09 --- /dev/null +++ b/web/src/cgi.tcl-1.10/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/web/src/cgi.tcl-1.10/install.mac b/web/src/cgi.tcl-1.10/install.mac new file mode 100644 index 00000000..a79c6b72 --- /dev/null +++ b/web/src/cgi.tcl-1.10/install.mac @@ -0,0 +1,70 @@ +This file is install.mac. It contains installation instructions for +cgi.tcl on MacOS. + +If you do not have Tcl, get it (the README explains how) and install +it. The rest of these instructions assume that you have Tcl +installed. + +-------------------- +Installation +-------------------- + +These instructions are based on contributions courtesy of Henk-Jan +Kooiman <hjk@cable.a2000.nl>. Send fixes to me (libes@nist.gov). + +If you just want to experiment with cgi.tcl, you can simply source it +into your Tcl files by saying "source cgi.tcl". + +Once you're done playing, go ahead and install it. To install it: + +1) Make a package index. (This will create pkgIndex.tcl which will +make it possible to use "package require cgi" in scripts.) Asari +Hirotsugu <asari@math.uiuc.edu> has supplied the following +elaboration of this step: + + 1a) Put the cgi.tcl folder in the "Tool Command Language" folder + inside the Extensions folder. (Don't make an alias for the Tool + Command Language folder since Tcl Shell doesn't resolve aliases as + of 8.2.1.) + + 1b) Launch the Tcl Shell (or Wish) and move to the Tool Command + Language folder by entering: + + cd "Macintosh HD:System Folder:Extensions:Tool Command Language" + + (You may have to modify this command depending upon the names + and structure of your file system.) + + Issue the pkg_mkIndex command: + + pkg_mkIndex cgi.tcl* + + 1c) Test if the package comand works by trying: + + package require cgi + +2) You may want to edit some things in cgi.tcl at this time. + + 2a) Upon errors in production code, cgi.tcl sends mail to an + administrator. This can be set on a per-script basis but it + defaults to "root". You'll probably want to change this for your + site. To do that, search cgi.tcl for cgi_admin_mail_addr "root" and + change the argument to whatever you prefer. + + 2b) The cgi_mail_end procedure attempts to do mail delivery using + SMTP (the de facto Internet mail protocol). However, this mechanism + is not robust. For example, if the mail gateway is down, the mail + will not be requeued for later delivery. If you have a robust + mailer program or some other interface, you should switch to using + it. The ability to send mail isn't required for basic use of + cgi.tcl, but this ability is especially useful for in-the-field + debugging so I encourage you to use it. + +You're done! Now you can use cgi.tcl. + +-------------------- +Examples +-------------------- + +The example directory has some examples. See the README in there. + diff --git a/web/src/cgi.tcl-1.10/install.win b/web/src/cgi.tcl-1.10/install.win new file mode 100644 index 00000000..424fc649 --- /dev/null +++ b/web/src/cgi.tcl-1.10/install.win @@ -0,0 +1,105 @@ +This file is install.win. It contains installation instructions for +cgi.tcl on Win95/NT. + +If you do not have Tcl, get it (the README explains how) and install +it. The rest of these instructions assume that you have Tcl +installed. + +-------------------- +Installation +-------------------- + +These instructions are based on contributions courtesy of Maan +M. Hamze <mmhamze@pleiades.net> and Martin Meuer +<martin.meuer@frz.de>. Send fixes to me (libes@nist.gov). + +If you just want to experiment with cgi.tcl, you can simply source it +into your Tcl files by saying "source cgi.tcl". + +Once you're done playing, go ahead and install it. To install it: + +1) Open wish8.0 and run the following: + + pkg_mkIndex c:\\tcl\\lib\\tcl8.0 cgi.tcl + +(assuming that you have Tcl libraries in the above directory). This +This will create pkgIndex.tcl which will make it possible to use +"package require cgi" in scripts. + +2) The only files actually necessary for production use are +pkgIndex.tcl and cgi.tcl. Make sure those files and their directory +have execute permission for the web server scripts. + +3) You may want to edit some things in cgi.tcl at this time. + +3a) The default extension of the files that work with cgi.tcl is .cgi. +In case that extension is already being used by another program for +your cgi programs, you may want to change that extension into +something else, say, .cgt. To do that, search cgi.tcl for the string +.cgi and replace with .cgt or whatever you prefer. + +3b) Upon errors in production code, cgi.tcl sends mail to an +administrator. This can be set on a per-script basis but it defaults +to "root". You'll probably want to change this for your site. To do +that, search cgi.tcl for cgi_admin_mail_addr "root" and change the +argument to whatever you prefer. + +3c) The cgi_mail_end procedure attempts to do mail delivery using SMTP +(the de facto Internet mail protocol). However, this mechanism is not +robust. For example, if the mail gateway is down, the mail will not +be requeued for later delivery. If you have a robust mailer program +or some other interface, you should switch to using it. The ability +to send mail isn't required for basic use of cgi.tcl, but this ability +is especially useful for in-the-field debugging so I encourage you to +use it. + +4) Tcl/Tk 8.0 should have automatically created a file type to run +files with the .tcl extension. Make sure by running: +Explorer...Options....File Types. .tcl files should be associated +with Wish8.0. + +5) The web server must now be told about Tcl. The exact details +depend on your particular server. Here are instructions that people +have sent to me for different servers. (Feel free to send more.) + +5a) If you are using Personal Web Server for Win 95 or MS IIS ver 3 +for Win NT: + + Instructions according to Maan M. Hamze <mmhamze@pleiades.net> + +Run the Registry Editor. +Go to: +HKEY_LOCAL_MACHINE + System + CurrentControlSet + Services + W3SVC + Parameters + Script Map +Create a new String Value through Edit: +First enter the name of the extension (.cgi or the extension you want to use as +in .cgt). Associate the extension with: +FullPathToTclExecutable\tclsh80.exe %s + +5b) If you are using Netscape Enterprise Server: + + Instructions according to Martin Meuer <martin.meuer@frz.de>. + +5b1) Create an association from NT-Explorer (View-Options-Filetypes) for +the extension .cgt to tell NT to open .cgt with "/fullpath/tclsh80.exe +%1" +5b2) From the Server Manager of the Enterprise Server create o new MIME +type for .cnt with type "magnus-internal/shellcgi" +(Alternatively one can create a special shellCGI-Directory instead, +but I rather like to place my scripts anywhere.) + +6) Kill and restart your web server. + +You're done! Now you can use cgi.tcl. + +-------------------- +Examples +-------------------- + +The example directory has some examples. See the README in there. + diff --git a/web/src/cgi.tcl-1.10/mkinstalldirs b/web/src/cgi.tcl-1.10/mkinstalldirs new file mode 100755 index 00000000..0801ec2c --- /dev/null +++ b/web/src/cgi.tcl-1.10/mkinstalldirs @@ -0,0 +1,32 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" || errstatus=$? + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/web/src/cgi.tcl-1.10/pkgcreate b/web/src/cgi.tcl-1.10/pkgcreate new file mode 100755 index 00000000..877b6cb3 --- /dev/null +++ b/web/src/cgi.tcl-1.10/pkgcreate @@ -0,0 +1,9 @@ +#!/depot/path/tclsh +# allow for earlier versions of Tcl that don't define pkg_mkIndex +if {[catch {pkg_mkIndex . cgi.tcl}]} { + set f [open pkgIndex.tcl w] + puts $f "error \"please rebuild cgi.tcl with a modern version of Tcl (for package support)\"" + close $f +} + + diff --git a/web/src/cgi.tcl-1.10/version.in b/web/src/cgi.tcl-1.10/version.in new file mode 100644 index 00000000..86adc5dc --- /dev/null +++ b/web/src/cgi.tcl-1.10/version.in @@ -0,0 +1,2 @@ +set versionFull @CGI_VERSION_FULL@ +set version @CGI_VERSION@ diff --git a/web/src/pubcookie/INSTALL b/web/src/pubcookie/INSTALL new file mode 100644 index 00000000..e4685c40 --- /dev/null +++ b/web/src/pubcookie/INSTALL @@ -0,0 +1,90 @@ +alpine.tar.z web/src/pubcookie/INSTALL +$id$ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +STEPS TO ADD PUBCOOKIE SUPPORT TO WEB ALPINE +-------------------------------------------- + +UW Pubcookie <http://www.pubcookie.org> provides single-sign-on +service for web-based applications. Web Alpine can be built to use UW +Pubcookie within a Kerberos authorization framework. + +Building Web Alpine to use pubcookie authentication should be +accomplished by simply adding: + + --with-pubcookie + +and: + + --with-web-bin=/usr/local/libexec/alpine/bin + +to the configure script's command line. Note, the value you supply in +the second configure option is the directory where ultimately the Web +Alpine's binary support tools will be installed. In addition, +Kerberos 5 must be available on the Alpine web server. + +Installation of the extra binary components for pubcookie support +should happen automatically. After the "make install" command typed +in web/src directory completes successfully, verify that: + + web/bin/wp_uidmapper + web/bin/wp_tclsh + web/bin/wp_gssapi_proxy + +all exist. Then simply follow the normal Web Alpine installation +steps described in the web/INSTALL document. + +Once Web Alpine is installed, there is some additional configuration +required. First, you'll need to change permissions on a couple of the +binary components as they do make use of the setuid() system call. It +should be simply a matter of: + + cd /usr/local/libexec/alpine/bin + sudo chmod 4755 wp_gssapi_proxy wp_tclsh + +Next, you'll need to: + + cd /usr/local/libexec/alpine/cgi/session + +In that directory you'll need to edit the ".htaccess" file, adding the +lines contained in the example htaccess file in the distribution's +"web/src/pubcookie/_htaccess_session". + +Then, + + cd /usr/local/libexec/alpine/cgi/session + +and edit the ".htaccess" file therein, adding the lines contained in +the example file "web/src/pubcookie/_htaccess_session_logout". + +Running Web Alpine with pubcookie requires some extra care and +feeding. First, the service provided by "wp_uidmapper" must be +started and maintained as long as the web server is providing Web +Alpine service. It must be run under the same uid as the web server. +The helper script "debug.cgi" can be used to conveniently +start/restart the wp_uidmapper service. Make sure the path defined +within that script is correct for your system. + +Finally, you'll need to create within the Kerberos 5 system the ID of +the "IMAP Superuser". This userid is used by the web server to log +into the UW IMAP server via SASL proxy authentication. That is, to +establish an IMAP session, the web server logs into the IMAP server +via Kerberos as the IMAP Superuser (which must be configured on the +IMAP server separately) and specifies in that SASL exchange that login +in being performed on behalf of the UW Pubcookie-provided userid. + +With the IMAP Superuser ID established and configured on the IMAP +server, you'll need to acquire a Kerbero ticket on the web server. +Typically, you'll want to install a crontab entry to periodically +refresh the ticket. See web/src/pubcookie/README. + diff --git a/web/src/pubcookie/Makefile.am b/web/src/pubcookie/Makefile.am new file mode 100644 index 00000000..e4da1c39 --- /dev/null +++ b/web/src/pubcookie/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in +## Use aclocal -I m4; automake + +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +WP_UIDMAPPER_SOCKET = "/tmp/wp_uidmapper" +WEBSERVER_UID = 65534 + +CFLAGS = '-DWP_UIDMAPPER_SOCKET=$(WP_UIDMAPPER_SOCKET)' \ + '-DWEBSERVER_UID=$(WEBSERVER_UID)' \ + '-DAUTH_GSS_PROXY_PATH="$(WEB_BINDIR)/wp_gssapi_proxy"' + +bin_PROGRAMS = wp_uidmapper wp_tclsh wp_gssapi_proxy wp_umc + +noinst_LIBRARIES = libauthgssproxy.a + +libauthgssproxy_a_SOURCES = auth_gss_proxy.c + +wp_uidmapper_SOURCES = wp_uidmapper.c id_table.c id_table.h + +wp_tclsh_SOURCES = wp_tclsh.c wp_uidmapper_lib.c + +wp_gssapi_proxy_SOURCES = wp_gssapi_proxy.c wp_uidmapper_lib.c + +wp_umc_SOURCES = wp_umc.c wp_uidmapper_lib.c + +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include diff --git a/web/src/pubcookie/Makefile.in b/web/src/pubcookie/Makefile.in new file mode 100644 index 00000000..c353b8ba --- /dev/null +++ b/web/src/pubcookie/Makefile.in @@ -0,0 +1,621 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# ======================================================================== +# Copyright 2006-2008 University of Washington +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# ======================================================================== + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = wp_uidmapper$(EXEEXT) wp_tclsh$(EXEEXT) \ + wp_gssapi_proxy$(EXEEXT) wp_umc$(EXEEXT) +subdir = web/src/pubcookie +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + INSTALL +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/VERSION \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libauthgssproxy_a_AR = $(AR) $(ARFLAGS) +libauthgssproxy_a_LIBADD = +am_libauthgssproxy_a_OBJECTS = auth_gss_proxy.$(OBJEXT) +libauthgssproxy_a_OBJECTS = $(am_libauthgssproxy_a_OBJECTS) +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_wp_gssapi_proxy_OBJECTS = wp_gssapi_proxy.$(OBJEXT) \ + wp_uidmapper_lib.$(OBJEXT) +wp_gssapi_proxy_OBJECTS = $(am_wp_gssapi_proxy_OBJECTS) +wp_gssapi_proxy_LDADD = $(LDADD) +am_wp_tclsh_OBJECTS = wp_tclsh.$(OBJEXT) wp_uidmapper_lib.$(OBJEXT) +wp_tclsh_OBJECTS = $(am_wp_tclsh_OBJECTS) +wp_tclsh_LDADD = $(LDADD) +am_wp_uidmapper_OBJECTS = wp_uidmapper.$(OBJEXT) id_table.$(OBJEXT) +wp_uidmapper_OBJECTS = $(am_wp_uidmapper_OBJECTS) +wp_uidmapper_LDADD = $(LDADD) +am_wp_umc_OBJECTS = wp_umc.$(OBJEXT) wp_uidmapper_lib.$(OBJEXT) +wp_umc_OBJECTS = $(am_wp_umc_OBJECTS) +wp_umc_LDADD = $(LDADD) +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libauthgssproxy_a_SOURCES) $(wp_gssapi_proxy_SOURCES) \ + $(wp_tclsh_SOURCES) $(wp_uidmapper_SOURCES) $(wp_umc_SOURCES) +DIST_SOURCES = $(libauthgssproxy_a_SOURCES) $(wp_gssapi_proxy_SOURCES) \ + $(wp_tclsh_SOURCES) $(wp_uidmapper_SOURCES) $(wp_umc_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = '-DWP_UIDMAPPER_SOCKET=$(WP_UIDMAPPER_SOCKET)' \ + '-DWEBSERVER_UID=$(WEBSERVER_UID)' \ + '-DAUTH_GSS_PROXY_PATH="$(WEB_BINDIR)/wp_gssapi_proxy"' + +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +C_CLIENT_CFLAGS = @C_CLIENT_CFLAGS@ +C_CLIENT_GCCOPTLEVEL = @C_CLIENT_GCCOPTLEVEL@ +C_CLIENT_LDFLAGS = @C_CLIENT_LDFLAGS@ +C_CLIENT_SPECIALS = @C_CLIENT_SPECIALS@ +C_CLIENT_TARGET = @C_CLIENT_TARGET@ +C_CLIENT_WITH_IPV6 = @C_CLIENT_WITH_IPV6@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISPELLPROG = @ISPELLPROG@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN = @LN@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKE = @MAKE@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NPA_PROG = @NPA_PROG@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PWPROG = @PWPROG@ +RANLIB = @RANLIB@ +REGEX_BUILD = @REGEX_BUILD@ +RM = @RM@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPELLPROG = @SPELLPROG@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEB_BINDIR = @WEB_BINDIR@ +WEB_BUILD = @WEB_BUILD@ +WEB_PUBCOOKIE_BUILD = @WEB_PUBCOOKIE_BUILD@ +WEB_PUBCOOKIE_LIB = @WEB_PUBCOOKIE_LIB@ +WEB_PUBCOOKIE_LINK = @WEB_PUBCOOKIE_LINK@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +acx_pthread_config = @acx_pthread_config@ +alpine_interactive_spellcheck = @alpine_interactive_spellcheck@ +alpine_simple_spellcheck = @alpine_simple_spellcheck@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +WP_UIDMAPPER_SOCKET = "/tmp/wp_uidmapper" +WEBSERVER_UID = 65534 +noinst_LIBRARIES = libauthgssproxy.a +libauthgssproxy_a_SOURCES = auth_gss_proxy.c +wp_uidmapper_SOURCES = wp_uidmapper.c id_table.c id_table.h +wp_tclsh_SOURCES = wp_tclsh.c wp_uidmapper_lib.c +wp_gssapi_proxy_SOURCES = wp_gssapi_proxy.c wp_uidmapper_lib.c +wp_umc_SOURCES = wp_umc.c wp_uidmapper_lib.c +AM_CPPFLAGS = -I@top_builddir@/include -I@top_srcdir@/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign web/src/pubcookie/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign web/src/pubcookie/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libauthgssproxy.a: $(libauthgssproxy_a_OBJECTS) $(libauthgssproxy_a_DEPENDENCIES) + -rm -f libauthgssproxy.a + $(libauthgssproxy_a_AR) libauthgssproxy.a $(libauthgssproxy_a_OBJECTS) $(libauthgssproxy_a_LIBADD) + $(RANLIB) libauthgssproxy.a +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +wp_gssapi_proxy$(EXEEXT): $(wp_gssapi_proxy_OBJECTS) $(wp_gssapi_proxy_DEPENDENCIES) + @rm -f wp_gssapi_proxy$(EXEEXT) + $(LINK) $(wp_gssapi_proxy_OBJECTS) $(wp_gssapi_proxy_LDADD) $(LIBS) +wp_tclsh$(EXEEXT): $(wp_tclsh_OBJECTS) $(wp_tclsh_DEPENDENCIES) + @rm -f wp_tclsh$(EXEEXT) + $(LINK) $(wp_tclsh_OBJECTS) $(wp_tclsh_LDADD) $(LIBS) +wp_uidmapper$(EXEEXT): $(wp_uidmapper_OBJECTS) $(wp_uidmapper_DEPENDENCIES) + @rm -f wp_uidmapper$(EXEEXT) + $(LINK) $(wp_uidmapper_OBJECTS) $(wp_uidmapper_LDADD) $(LIBS) +wp_umc$(EXEEXT): $(wp_umc_OBJECTS) $(wp_umc_DEPENDENCIES) + @rm -f wp_umc$(EXEEXT) + $(LINK) $(wp_umc_OBJECTS) $(wp_umc_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_gss_proxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_gssapi_proxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_tclsh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_uidmapper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_uidmapper_lib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wp_umc.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLIBRARIES ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/web/src/pubcookie/README b/web/src/pubcookie/README new file mode 100644 index 00000000..9ca8a493 --- /dev/null +++ b/web/src/pubcookie/README @@ -0,0 +1,137 @@ +alpine.tar.z web/src/pubcookie/README +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +WEB ALPINE WITH PUBCOOKIE SUPPORT +--------------------------------- + +UW Pubcookie <http://www.pubcookie.org> provides single-sign-on +service for web-based applications. + +For building and installation comments, see web/src/pubcookie/INSTALL. + + +WEB ALPINE PUBCOOKIE COMPONENTS +------------------------------- + +Below are the extra binary helper applications and their descriptions +necessary to implement UW Pubcookie authentication within Web Alpine. + +bin/wp_uidmapper: + wp_uidmapper runs in background. Keeps pubcookie + username <-> uid tables. Handles requests from + wp_tclsh and wp_gssapi_proxy through the named socket + /tmp/wp_uidmapper. This needs to be manually started, + should never stop running, and should run as the same + uid as the web server (nobody). + +bin/wp_tclsh: + + wp_tclsh is a modified version of tclsh (8.0.5) that + does a setuid before doing the tcl stuff. The tcl + scripts directly run by the web server should use this + as their #! interpreter. If REMOTE_USER is set + (pubcookie in use) and the calling uid is the web + server (nobody), it calls wp_uidmapper to obtain its + destination uid. Otherwise, it just changes back to + the calling uid. + + +bin/wp_gssapi_proxy: + + wp_gssapi_proxy is called by the c-client + auth_gss_proxy.c routine, and does the GSSAPI/SASL + dance with the imap server. Looks up the username + corresponding to the calling uid via wp_uidmapper, and + will fail if the calling program is requesting access + to a different username's mail on the imap + server. Compile time options for wp_gssapi_proxy: + + -DDDEBUG: outputs extra info to the syslog mail log. + -DNO_UIDMAPPER: calls getpwuid(getuid()) to look up + username of calling uid. + +bin/alpined + + auth_gss_proxy.c is the c-client authenticator that calls + wp_gssapi_proxy. Stick this in the imap/src/c-client directory + of the pinetcl source tree. Make sure the + AUTH_GSS_PROXY_PATH #define points to the location of + the installed wp_gssapi_proxy. The following lines + should be added to main() function in pine/pinetcl.c: + + /* put this auth_link at the beginning of the list */ + auth_link(&auth_gss_proxy); + /* try to get username from REMOTE_USER (pubcookie) */ + if(user = getenv("REMOTE_USER")) env_init(user,"/"); + +*.tcl: + + The scripts directly run by the web server must be + changed to point to wp_tclsh instead of the normal + tclsh. If for some reason you want to create a script + that should be run as the web server uid, use the + default tclsh interpreter. There is a script + bin/chscriptinterp, which you can run as follows to + change *.tcl to use /www/test/bin/wp_tclsh instead of + whatever they currently use. + +.htaccess: + + AuthType UWNetID + AuthName "Webpine" + PubcookieAppId "Webpine" + require valid-user + + NOTE: to properly scope the pubcookie cookie for the web server, + remove the PubcookieAppId directive + +logout/.htaccess: + + PubcookieEndSesion redirect + +etc/webpine.keytab: + + Should be owned by nobody.nobody with 600 permissions. A cron + entry for user nobody should run kinit often enough so that + the ticket never expires: + + [root@server /]# crontab -u nobody -l + # DO NOT EDIT THIS FILE - edit the master and reinstall. + # (/var/spool/cron.new/nobody installed on Tue Dec 5 16:26:14 2000) + # (Cron version -- $Id: README 910 2008-01-14 22:28:38Z hubert@u.washington.edu $) + MAILTO=root@your-server-name + 0 3,11,19 * * * /usr/local/bin/kinit -k -t /www/test/etc/webpine.keytab webpine + +debug.cgi: + + If you are having weird problems, run this via your web + browser, and it might help you figure things out. Runs as the web + server uid (nobody) and displays the following: + + - output of 'klist' + - output of 'ps auxww |grep wp_uidmapper' + - the environment + - also lists any processes running as uids with no + corresponding usernames, which should tell you if your + pinetcl process is crashing. + + It also will restart wp_uidmapper if /tmp/wp_uidmapper does not + exist, should that have crashed for some reason. + + Finally, visit debug.cgi?stop (via the web browser) and it + will stop a currently running wp_uidmapper, so that you can + restart it in case you do something like move the location of + the binary. + +-- +$Id: README 910 2008-01-14 22:28:38Z hubert@u.washington.edu $ diff --git a/web/src/pubcookie/_htaccess_session b/web/src/pubcookie/_htaccess_session new file mode 100644 index 00000000..24855aab --- /dev/null +++ b/web/src/pubcookie/_htaccess_session @@ -0,0 +1,4 @@ +AuthType UWNetID +AuthName "Webpine" +PubcookieAppId "Webpine" +require valid-user diff --git a/web/src/pubcookie/_htaccess_session_logout b/web/src/pubcookie/_htaccess_session_logout new file mode 100644 index 00000000..ecc269e1 --- /dev/null +++ b/web/src/pubcookie/_htaccess_session_logout @@ -0,0 +1,8 @@ +# +# mod_rewrite rules to coerce secure (https) access to underlying pages +# + +AddHandler cgi-script tcl + +PubcookieAppId "Webpine" +PubcookieEndSession redirect diff --git a/web/src/pubcookie/auth_gss_proxy.c b/web/src/pubcookie/auth_gss_proxy.c new file mode 100644 index 00000000..ea5daf69 --- /dev/null +++ b/web/src/pubcookie/auth_gss_proxy.c @@ -0,0 +1,380 @@ +/* ======================================================================== + * Copyright 2006-2008 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include "../../../c-client/mail.h" +#include "../../../c-client/misc.h" +#include "../../../c-client/osdep.h" + +#define PROTOTYPE(x) x +#include <gssapi/gssapi_generic.h> +#include <gssapi/gssapi_krb5.h> + +long auth_gssapi_proxy_valid (void); +long auth_gssapi_proxy_client (authchallenge_t challenger, + authrespond_t responder, + char *service, + NETMBX *mb,void *stream,unsigned long *trial, + char *user); +char *auth_gssapi_proxy_server (authresponse_t responder,int argc,char *argv[]); + +AUTHENTICATOR auth_gss_proxy = { + AU_SECURE | AU_AUTHUSER, /* secure authenticator */ + "GSSAPI", /* authenticator name */ + auth_gssapi_proxy_valid, /* check if valid */ + auth_gssapi_proxy_client, /* client method */ + auth_gssapi_proxy_server, /* server method */ + NIL /* next authenticator */ +}; + +#define AUTH_GSSAPI_P_NONE 1 +#define AUTH_GSSAPI_P_INTEGRITY 2 +#define AUTH_GSSAPI_P_PRIVACY 4 + +#define AUTH_GSSAPI_C_MAXSIZE 8192 + +#define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y) + +extern char *krb5_defkeyname; /* sneaky way to get this name */ + + +/* Placate const declarations */ + +static gss_OID auth_gss_proxy_mech; +static gss_OID_set auth_gss_proxy_mech_set; + +/* Check if GSSAPI valid on this system + * Returns: T if valid, NIL otherwise + */ + +long auth_gssapi_proxy_valid (void) +{ + char *s,tmp[MAILTMPLEN]; + OM_uint32 smn; + gss_buffer_desc buf; + gss_name_t name; + struct stat sbuf; + sprintf (tmp,"host@%s",mylocalhost ()); + buf.length = strlen (buf.value = tmp) + 1; + memcpy (&auth_gss_proxy_mech,&gss_mech_krb5,sizeof (gss_OID)); + memcpy (&auth_gss_proxy_mech_set,&gss_mech_set_krb5,sizeof (gss_OID_set)); + /* see if can build a name */ + if (gss_import_name (&smn,&buf,gss_nt_service_name,&name) != GSS_S_COMPLETE) + return NIL; /* failed */ + if ((s = strchr (krb5_defkeyname,':')) && stat (++s,&sbuf)) + auth_gss_proxy.server = NIL; /* can't do server if no keytab */ + gss_release_name (&smn,&name);/* finished with name */ + return LONGT; +} + +/* Proxy client authenticator (mihodge) + * Accepts: challenger function + * responder function + * parsed network mailbox structure + * stream argument for functions + * pointer to current trial count + * returned user name + * Returns: T if success, NIL otherwise, number of trials incremented if retry + */ + +#ifndef AUTH_GSS_PROXY_PATH +#define AUTH_GSS_PROXY_PATH "/usr/local/libexec/alpine/bin/wp_gssapi_proxy" +#endif +#define AUTH_GSS_PROXY_MESSAGE 1 +#define AUTH_GSS_PROXY_READ 2 +#define AUTH_GSS_PROXY_SUCCESS 3 +#define AUTH_GSS_PROXY_WRITE 4 +#define AUTH_GSS_PROXY_WRITE_NIL 5 +#define AUTH_GSS_PROXY_EXEC_FAILED 6 + +static unsigned long read_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = read(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } else if(s == 0) break; + } + return total; +} + +static unsigned long write_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = write(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } + } + return total; +} + +long auth_gssapi_proxy_client (authchallenge_t challenger, + authrespond_t responder, + char *service, + NETMBX *mb,void *stream,unsigned long *trial, + char *user) +{ + char err[MAILTMPLEN]; + int status, ipipe[2], opipe[2]; + unsigned long len,cmd[2],maxlogintrials; + char *buf; + pid_t pid; + long ret = NIL; + + imap_parameters(GET_MAXLOGINTRIALS, (void *) &maxlogintrials); + *trial = maxlogintrials + 1; + err[0] = 0; + strcpy (user,mb->user[0] ? mb->user : myusername ()); + + /* open pipe to gss proxy process */ + if(pipe(ipipe)) { + sprintf (err,"auth_gss_proxy: create pipe error: %s",strerror(errno)); + } else if(pipe(opipe)) { + sprintf (err,"auth_gss_proxy: create pipe error: %s",strerror(errno)); + close(ipipe[0]); + close(ipipe[1]); + } else if((pid = fork()) == -1) { + sprintf (err,"auth_gss_proxy: fork error: %s",strerror(errno)); + close(ipipe[0]); + close(ipipe[1]); + close(opipe[0]); + close(opipe[1]); + + } else if(pid == 0) { /* child process */ + close(ipipe[0]); + close(opipe[1]); + dup2(opipe[0],0); + dup2(ipipe[1],1); + close(opipe[0]); + close(ipipe[1]); + + /* a little overloading of the "err" field here */ + sprintf (err,"%s@%s",service,mb->host); + execlp(AUTH_GSS_PROXY_PATH,AUTH_GSS_PROXY_PATH,err,user,0); + + /* tell parent that exec failed and exit */ + cmd[0] = AUTH_GSS_PROXY_EXEC_FAILED; + cmd[1] = 0; + write_full(1,cmd,sizeof(cmd)); + exit(-1); + + } else { /* parent process */ + close(ipipe[1]); + close(opipe[0]); + + while(len = read_full(ipipe[0],cmd,sizeof(cmd))) { + if (len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if (len != sizeof(cmd)) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,sizeof(cmd)); + break; + + } else if(cmd[0] == AUTH_GSS_PROXY_EXEC_FAILED) { + sprintf (err,"auth_gss_proxy: could not spawn proxy process"); + break; + + } else if(cmd[0] == AUTH_GSS_PROXY_MESSAGE) { + if(cmd[1]) { + buf = fs_get(cmd[1]); + len = read_full(ipipe[0],buf,cmd[1]); + if(len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if(len != cmd[1]) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,cmd[1]); + break; + } else { + mm_log(buf,WARN); + } + fs_give ((void **) &buf); + } + + } else if(cmd[0] == AUTH_GSS_PROXY_READ) { + buf = (*challenger) (stream,&len); + if(!buf) len = 0; + if(write_full(opipe[1],&len,sizeof(len)) == -1) { + sprintf (err,"auth_gss_proxy: write error: %s",strerror(errno)); + break; + } else if (buf && (write_full(opipe[1],buf,len) == -1)) { + sprintf (err,"auth_gss_proxy: write error: %s",strerror(errno)); + break; + } + if(buf) fs_give ((void **) &buf); + + } else if(cmd[0] == AUTH_GSS_PROXY_SUCCESS) { + ret = T; + + } else if(cmd[0] == AUTH_GSS_PROXY_WRITE) { + if(cmd[1]) { + buf = fs_get(cmd[1]); + len = read_full(ipipe[0],buf,cmd[1]); + if(len == -1) { + sprintf (err,"auth_gss_proxy: read error: %s",strerror(errno)); + break; + } else if(len != cmd[1]) { + sprintf (err,"auth_gss_proxy: read error: %lu out of %lu", + len,cmd[1]); + break; + } else { + (*responder) (stream,buf,cmd[1]); + } + fs_give ((void **) &buf); + } else { + (*responder) (stream,"",0); + } + + } else if(cmd[0] == AUTH_GSS_PROXY_WRITE_NIL) { + (*responder) (stream,NIL,0); + + } else { + sprintf (err,"auth_gss_proxy: unknown command: %lu",cmd[0]); + break; + } + } + + /* close pipes and wait for process to die */ + close(ipipe[0]); + waitpid(pid,&status,0); + close(opipe[1]); + } + + if(err[0]) mm_log(err,WARN); + return ret; +} + +/* Server authenticator + * Accepts: responder function + * argument count + * argument vector + * Returns: authenticated user name or NIL + */ + +char *auth_gssapi_proxy_server (authresponse_t responder,int argc,char *argv[]) +{ + char *ret = NIL; + char *s,tmp[MAILTMPLEN]; + unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE); + int conf; + OM_uint32 smj,smn,dsmj,dsmn,flags; + OM_uint32 mctx = 0; + gss_name_t crname,name; + gss_OID mech; + gss_buffer_desc chal,resp,buf; + gss_cred_id_t crd; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + /* make service name */ + sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL), + tcp_serverhost ()); + buf.length = strlen (buf.value = tmp) + 1; + /* acquire credentials */ + if ((gss_import_name (&smn,&buf,gss_nt_service_name,&crname)) == + GSS_S_COMPLETE) { + if ((smj = gss_acquire_cred (&smn,crname,0,auth_gss_proxy_mech_set,GSS_C_ACCEPT, + &crd,NIL,NIL)) == GSS_S_COMPLETE) { + if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) { + do { /* negotiate authentication */ + smj = gss_accept_sec_context (&smn,&ctx,crd,&resp, + GSS_C_NO_CHANNEL_BINDINGS,&name,&mech, + &chal,&flags,NIL,NIL); + /* don't need response any more */ + fs_give ((void **) &resp.value); + switch (smj) { /* how did it go? */ + case GSS_S_COMPLETE: /* successful */ + /* paranoia */ + if (memcmp (mech->elements,auth_gss_proxy_mech->elements,mech->length)) + fatal ("GSSAPI is bogus"); + case GSS_S_CONTINUE_NEEDED: + if (chal.value) { /* send challenge, get next response */ + resp.value = (*responder) (chal.value,chal.length, + (unsigned long *) &resp.length); + gss_release_buffer (&smn,&chal); + } + break; + } + } + while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED)); + + /* successful exchange? */ + if ((smj == GSS_S_COMPLETE) && + (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) { + /* extract authentication ID from principal */ + if (s = strchr ((char *) buf.value,'@')) *s = '\0'; + /* send security and size */ + memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4); + tmp[0] = AUTH_GSSAPI_P_NONE; + if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){ + resp.value = (*responder) (chal.value,chal.length, + (unsigned long *) &resp.length); + gss_release_buffer (&smn,&chal); + if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) { + /* client request valid */ + if (chal.value && (chal.length > 4) && (chal.length < MAILTMPLEN) + && memcpy (tmp,chal.value,chal.length) && + (tmp[0] & AUTH_GSSAPI_P_NONE)) { + /* tie off authorization ID */ + tmp[chal.length] = '\0'; + if (authserver_login (tmp+4,buf.value,argc,argv) || + authserver_login (lcase (tmp+4),buf.value,argc,argv)) + ret = myusername (); + } + /* done with user name */ + gss_release_buffer (&smn,&chal); + } + /* finished with response */ + fs_give ((void **) &resp.value); + } + /* don't need name buffer any more */ + gss_release_buffer (&smn,&buf); + } + /* don't need client name any more */ + gss_release_name (&smn,&name); + /* don't need context any more */ + if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL); + } + /* finished with credentials */ + gss_release_cred (&smn,&crd); + } + + else { /* can't acquire credentials! */ + if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE) + SERVER_LOG ("Failed to acquire credentials for %s",buf.value); + if (smj != GSS_S_FAILURE) do + switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, + GSS_C_NO_OID,&mctx,&resp)) { + case GSS_S_COMPLETE: + mctx = 0; + case GSS_S_CONTINUE_NEEDED: + SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value); + gss_release_buffer (&dsmn,&resp); + } + while (dsmj == GSS_S_CONTINUE_NEEDED); + do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp)) { + case GSS_S_COMPLETE: + case GSS_S_CONTINUE_NEEDED: + SERVER_LOG ("GSSAPI mechanism status: %s",resp.value); + gss_release_buffer (&dsmn,&resp); + } + while (dsmj == GSS_S_CONTINUE_NEEDED); + } + /* finished with credentials name */ + gss_release_name (&smn,&crname); + } + return ret; /* return status */ +} diff --git a/web/src/pubcookie/debug.cgi b/web/src/pubcookie/debug.cgi new file mode 100755 index 00000000..dd998380 --- /dev/null +++ b/web/src/pubcookie/debug.cgi @@ -0,0 +1,58 @@ +#!/usr/bin/perl +$| = 1; +$wp_uidmapper_bin = "/usr/local/libexec/alpine/bin/wp_uidmapper"; +$wp_uidmapper_socket = "/tmp/wp_uidmapper"; + +print "Content-type: text/plain\n\n"; +print "klist:\n"; +system("/usr/local/bin/klist"); +print "\n"; + +#if($ENV{'QUERY_STRING'} eq 'stop') { +# foreach $line (ps("axww")) { +# ($line =~ m/^(\d+).*wp_uidmapper/) && kill(15,$1); +# } +# sleep(1); +# if(-e $wp_uidmapper_socket) { +# print "Could not kill wp_uidmapper\n"; +# exit(1); +# } +# print "wp_uidmapper stopped\n"; +# exit 0; +#} + +if (! -e $wp_uidmapper_socket) { + print "Yikes! need to spawn new wp_uidmapper process\n"; + if(!fork()) { + close(STDIN); + close(STDOUT); + close(STDERR); + setpgrp(0,0); + exec("$wp_uidmapper_bin 60000-64999"); + } + sleep 1; +} + +@ps = ps("auxww"); +print "wp_uidmapper:\n"; +foreach $line (@ps) { ($line =~ m/wp_uidmapper/) && print $line; } + +print "\nEnvironment:\n"; +foreach $key (sort { $a cmp $b } keys(%ENV)) { + print "$key: $ENV{$key}\n"; +} + +print "\nAlpine user processes:\n"; +foreach $line (@ps) { ($line =~ m/^\#/) && print $line; } +exit 0; + +sub ps { + my ($args) = @_; + my (@a); + open(PS,"ps $args|") || return; + @a = <PS>; + close(PS); + return @a; +} + + diff --git a/web/src/pubcookie/id_table.c b/web/src/pubcookie/id_table.c new file mode 100644 index 00000000..1076524e --- /dev/null +++ b/web/src/pubcookie/id_table.c @@ -0,0 +1,294 @@ +#include "id_table.h" +#include "wp_uidmapper_lib.h" + +#include <sys/types.h> /* opendir */ +#include <sys/stat.h> /* stat */ +#include <stdlib.h> /* mallloc,free,strtol */ +#include <string.h> /* memcpy */ +#include <errno.h> /* errno */ + +#include <dirent.h> /* opendir */ +#include <unistd.h> /* stat */ + +unsigned long hash_func(char *string,unsigned long num_buckets) { + unsigned long i; + char *p; + for(i = 0, p = string; *p; p++) i = (9 * i) + *p; + return i % num_buckets; +} + +struct id_table_entry { + struct id_table_entry **pself; + struct id_table_entry *next; + int id; + char tmp; + char name[1]; +}; + +struct key_hash_entry { + unsigned key[WP_KEY_LEN]; + id_table_entry *e; + struct key_hash_entry **pself; + struct key_hash_entry *next; +}; + +id_table_range *id_table_range_new(char *str) { + id_table_range *rhead,*rtail; + char *p,*pn; + long s,e; + + rhead = rtail = 0; + for(p = str; *p; p = *pn ? pn + 1 : pn) { + s = strtoul(p,&pn,0); + if(pn > p) { + if(*pn == '-') { + p = pn + 1; + e = strtoul(p,&pn,0); + if(pn == p) e = s; + } else { + e = s; + } + + if(rtail) { + rtail->next = (id_table_range*)malloc(sizeof(id_table_range)); + rtail = rtail->next; + } else { + rhead = rtail = (id_table_range*)malloc(sizeof(id_table_range)); + } + rtail->start = s; + rtail->end = e; + } + } + if(rtail) rtail->next = 0; + return rhead; +} + +void id_table_range_delete(id_table_range *range) { + id_table_range *r; + while(r = range) { + range = range->next; + free(r); + } +} + +int id_table_init(id_table *t,id_table_range *range) { + id_table_range *r; + unsigned long array_end,u; + + if(!range) return -1; + t->array_start = range->start; + array_end = range->end; + for(r = range->next; r; r = r->next) { + if(r->start < t->array_start) t->array_start = r->start; + if(r->end > array_end) array_end = r->end; + } + if(t->array_start >= array_end) return -1; + t->array_size = array_end + 1 - t->array_start; + t->hash_size = t->array_size * 2 + 1; + t->key_hash_size = t->array_size * 2 + 1; + + t->array = (id_table_entry**)malloc(sizeof(id_table_entry*) * t->array_size); + t->hash = (id_table_entry**)malloc(sizeof(id_table_entry*) * t->hash_size); + t->key_hash = (key_hash_entry**)malloc(sizeof(key_hash_entry *) * t->key_hash_size); + if(!t->hash || !t->array || !t->key_hash) { + if(t->hash) free(t->hash); + if(t->key_hash) free(t->key_hash); + if(t->array) free(t->array); + return -1; + } + for(u = 0; u < t->array_size; u++) t->array[u] = (id_table_entry*)-1; + t->max_fill = 0; + for(r = range; r; r = r->next) { + t->max_fill += r->end + 1 - r->start; + for(u = r->start; u <= r->end; u++) t->array[u - t->array_start] = 0; + } + bzero(t->hash,sizeof(id_table_entry*) * t->hash_size); + bzero(t->key_hash, sizeof(key_hash_entry*) * t->key_hash_size); + + t->array_ptr = 0; + t->fill = 0; + return 0; +} + +void id_table_destroy(id_table *t) { + unsigned long u; + for(u = 0; u < t->array_size; u++) + if(t->array[u] && (t->array[u] != (id_table_entry*)-1)) free(t->array[u]); + free(t->hash); + free(t->array); +} + +int id_table_create_id(id_table *t,char *name,unsigned *key) { + id_table_entry **pe,*e; + unsigned long size; + + if(name && strlen(name)){ + for(pe = t->hash + hash_func(name,t->hash_size); *pe; pe = &(*pe)->next) + if(!strcmp(name,(*pe)->name)){ + if(key[0]){ + if((e = key_hash_get_entry(t, key)) == NULL){ + if(key_hash_create_entry(t, *pe, key) == NULL){ + return -1; + } + } + else if(e->id != (*pe)->id){ + return -1; + } + } + + return (*pe)->id; + } + + /* no matching name found */ + } + else { + if(e = key_hash_get_entry(t,key)) + return e->id; + + /* MUST have seen name/key pair at least once */ + errno = EINVAL; + return -1; + } + + /* need to add new entry */ + if(t->fill == t->max_fill) { + id_table_remove_stale(t); + if(t->fill == t->max_fill) { + errno = ENOSPC; + return -1; + } + for(pe = t->hash + hash_func(name,t->hash_size); *pe; pe = &(*pe)->next); + } + size = strlen(name); + e = (id_table_entry*)malloc(sizeof(id_table_entry) + size); + if(!e) return -1; + + while(t->array[t->array_ptr]) + t->array_ptr = (t->array_ptr + 1) % t->array_size; + + e->pself = pe; + e->next = 0; + e->id = (int)(t->array_ptr + t->array_start); + memcpy(e->name,name,size + 1); + if(key[0] && key_hash_create_entry(t, e,key) == NULL) + return -1; + + *pe = e; + t->array[t->array_ptr] = e; + t->array_ptr = (t->array_ptr + 1) % t->array_size; + t->fill++; + return e->id; +} + +static id_table_entry *id_table_get_entry(id_table *t,unsigned long id) { + if(id >= t->array_start) { + id -= t->array_start; + if(id < t->array_size) + if(t->array[id] && (t->array[id] != (id_table_entry*)-1)) + return t->array[id]; + } + return 0; +} + +char *id_table_get_name(id_table *t,int id) { + id_table_entry *e = id_table_get_entry(t,(unsigned long)id); + return e ? e->name : 0; +} + +int id_table_remove_stale(id_table *t) { + id_table_entry *e; + unsigned long u; + DIR *d; + struct dirent *de; + struct stat st; + char path[NAME_MAX + 7]; + + /* + * flag all uids inactive + */ + + for(u = 0; u < t->array_size; u++) + if(t->array[u] && (t->array[u] != (id_table_entry*)-1)) + t->array[u]->tmp = 0; + + /* + * go through list of processes, finding active uids + */ + + memcpy(path,"/proc/",6); + if(d = opendir("/proc")) { + while(de = readdir(d)) { + strcpy(path + 6,de->d_name); + if(!stat(path,&st)) { + if(e = id_table_get_entry(t,(unsigned long)st.st_uid)) e->tmp = 1; + } + } + closedir(d); + } + + /* + * remove ones still marked inactive + */ + + for(u = 0; u < t->array_size; u++) { + e = t->array[u]; + if(e && (e != (id_table_entry*)-1)) { + if(!e->tmp) { + if(e->next) e->next->pself = e->pself; + *e->pself = e->next; + t->array[u] = 0; + t->array_ptr = u; + t->fill--; + key_hash_delete_keys(t, e); + free(e); + } + } + } + return 0; +} + +id_table_entry *key_hash_get_entry(id_table *t, unsigned *key) { + key_hash_entry **ke; + + for(ke = t->key_hash + (key[0] % t->key_hash_size); *ke; ke = &(*ke)->next) + if(key[0] && (*ke)->key[0] == key[0] && !memcmp(key,(*ke)->key,WP_KEY_LEN * sizeof(unsigned))) + return (*ke)->e; + + return NULL; +} + +key_hash_entry *key_hash_create_entry(id_table *t, id_table_entry *pe, unsigned *key) { + key_hash_entry **ke, *kep; + + for(ke = &t->key_hash[key[0] % t->key_hash_size]; *ke; ke = &(*ke)->next) + if(!memcmp(key,(*ke)->key,WP_KEY_LEN * sizeof(unsigned))) + return NULL; + + if(kep = malloc(sizeof(key_hash_entry))){ + memcpy(kep->key,key,(WP_KEY_LEN * sizeof(unsigned int))); + kep->e = pe; + kep->pself = ke; + kep->next = NULL; + *ke = kep; + } + + return kep; +} + +void key_hash_delete_keys(id_table *t, id_table_entry *e) { + key_hash_entry *kp, *kd; + int u; + + for(u = 0; u < t->key_hash_size; u++){ + for(kp = t->key_hash[u]; kp; ) + if (kp->e == e){ + kd = kp; + if(kp->next) kp->next->pself = kp->pself; + *kp->pself = kp->next; + kp = kp->next; + free(kd); + } + else + kp = kp->next; + } +} diff --git a/web/src/pubcookie/id_table.h b/web/src/pubcookie/id_table.h new file mode 100644 index 00000000..2ba3f2b4 --- /dev/null +++ b/web/src/pubcookie/id_table.h @@ -0,0 +1,58 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _ID_TABLE_H_ +#define _ID_TABLE_H_ + +struct id_table_entry; +typedef struct id_table_entry id_table_entry; + +struct key_hash_entry; +typedef struct key_hash_entry key_hash_entry; + +typedef struct id_table_range { + unsigned long start; + unsigned long end; + struct id_table_range *next; +} id_table_range; + +typedef struct id_table { + id_table_entry **array; + unsigned long array_start; + unsigned long array_size; + unsigned long array_ptr; + + id_table_entry **hash; + unsigned long hash_size; + + key_hash_entry **key_hash; + unsigned long key_hash_size; + + unsigned long max_fill; + unsigned long fill; +} id_table; + +id_table_range *id_table_range_new(char *str); +void id_table_range_delete(id_table_range *range); + +int id_table_init(id_table *t,id_table_range *range); +void id_table_destroy(id_table *t); + +int id_table_create_id(id_table *t,char *name,unsigned int *key); +char *id_table_get_name(id_table *t,int id); +int id_table_remove_stale(id_table *t); + +id_table_entry *key_hash_get_entry(id_table *, unsigned *key); +key_hash_entry *key_hash_create_entry(id_table *, id_table_entry *pe, unsigned *key); +void key_hash_delete_keys(id_table *t, id_table_entry *e); + +#endif diff --git a/web/src/pubcookie/wp_gssapi_proxy.c b/web/src/pubcookie/wp_gssapi_proxy.c new file mode 100644 index 00000000..f23d6098 --- /dev/null +++ b/web/src/pubcookie/wp_gssapi_proxy.c @@ -0,0 +1,412 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + + +/* #define PROTOTYPE(x) x */ + +#include <system.h> +#include <general.h> + +#include "wp_uidmapper_lib.h" + +#include <gssapi/gssapi_generic.h> +#include <gssapi/gssapi_krb5.h> + +#define AUTH_GSS_PROXY_MESSAGE 1 +#define AUTH_GSS_PROXY_READ 2 +#define AUTH_GSS_PROXY_SUCCESS 3 +#define AUTH_GSS_PROXY_WRITE 4 +#define AUTH_GSS_PROXY_WRITE_NIL 5 + +#define AUTH_GSSAPI_P_NONE 1 +#define AUTH_GSSAPI_P_INTEGRITY 2 +#define AUTH_GSSAPI_P_PRIVACY 4 + +#ifdef NO_UIDMAPPER +int get_calling_username(int uid,char *name,int namelen) { + struct passwd *pw; + unsigned long len; + + pw = getpwuid(uid); + if(!pw) return -1; + len = strlen(pw->pw_name); + if(len >= namelen) len = namelen - 1; + memcpy(name,pw->pw_name,len); + name[len] = 0; + return len; +} +#else +#define get_calling_username wp_uidmapper_getname +#endif + +static unsigned long read_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = read(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } else if(s == 0) break; + } + return total; +} + +static unsigned long write_full(int fd,void *buf,unsigned long size) { + unsigned long total,s; + for(total = 0; total < size; total += s) { + s = write(fd,(char*)buf + total,size - total); + if(s == -1) { + if((errno == EAGAIN) || (errno == EINTR)) s = 0; + else return -1; + } + } + return total; +} + +int cmd_message(char *str1, ...) { + va_list list; + unsigned long cmd[2],size; + char *str; + + for(size = 0,str = str1,va_start(list,str1); str; str = va_arg(list,char*)) + size += strlen(str); + va_end(list); + + cmd[0] = AUTH_GSS_PROXY_MESSAGE; + cmd[1] = size; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + for(str = str1, va_start(list,str1); str; str = va_arg(list,char*)) + if(size = strlen(str)) if(write_full(1,str,size) == -1) { + va_end(list); + return -1; + } + va_end(list); + return 0; +} + +int cmd_read(gss_buffer_desc *pbuf) { + unsigned long cmd[2],len,size; + void *buf; + + cmd[0] = AUTH_GSS_PROXY_READ; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + + len = read_full(0,&size,sizeof(size)); + if(len != sizeof(size)) return -1; + if(size == 0) { + pbuf->value = 0; + pbuf->length = 0; + return 0; + } + + buf = malloc(size); + len = read_full(0,buf,size); + if(len != size) { + free(buf); + return -1; + } + pbuf->value = buf; + pbuf->length = size; + return 0; +} + +int cmd_success() { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_SUCCESS; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + return 0; +} + +int cmd_write(gss_buffer_desc *buf) { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_WRITE; + cmd[1] = buf->length; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + if(buf->length) if(write_full(1,buf->value,buf->length) == -1) return -1; + return 0; +} + +int cmd_write_nil() { + unsigned long cmd[2]; + cmd[0] = AUTH_GSS_PROXY_WRITE_NIL; + cmd[1] = 0; + if(write_full(1,cmd,sizeof(cmd)) == -1) return -1; + return 0; +} + +/* + * service principal in argv[1] + * reqested username in argv[2] + */ + +int main(int argc,char *argv[]) +{ + char *user = 0; + char userbuf[WP_BUF_SIZE]; + char *prog; + OM_uint32 smj,smn,dsmn,mctx; + gss_name_t crname = GSS_C_NO_NAME; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc chal,resp,buf; + int conf,i; + gss_qop_t qop; + gss_OID oid; + int calling_uid,eff_uid; + + if((prog = strrchr(argv[0], '/')) == NULL) + prog = argv[0]; + else + prog++; + + openlog(prog,LOG_PID,LOG_MAIL); + + calling_uid = getuid(); + eff_uid = geteuid(); +#ifdef DEBUG + syslog(LOG_INFO,"uid = %d, euid=%d\n",calling_uid,eff_uid); +#endif + +#ifdef WEBSERVER_UID + /* if euid != uid, change to web server user */ + if(calling_uid != eff_uid) if(setuid(WEBSERVER_UID)) { + syslog(LOG_ERR,"setuid ((%d != %d) -> %d) failed: %s", + calling_uid,eff_uid,WEBSERVER_UID,strerror(errno)); + cmd_write_nil(); + goto cleanup; + } +#endif + + if(argc < 2) { + syslog(LOG_WARNING,"not enough arguments"); + cmd_write_nil(); + goto cleanup; + } + if(get_calling_username(calling_uid,userbuf,WP_BUF_SIZE) == -1) { + syslog(LOG_WARNING,"cannot determine calling username"); + cmd_write_nil(); + goto cleanup; + } + if(argc == 2) { + user = userbuf; +#ifdef DEBUG + syslog(LOG_INFO,"calling=%s\n",user); +#endif + } else if(argc > 2) { + user = argv[2]; +#ifdef DEBUG + syslog(LOG_INFO,"requested=%s calling=%s\n",user,userbuf); +#endif +#ifndef NO_NAME_CHECK + if(strcmp(user,userbuf)) { + syslog(LOG_WARNING,"cannot act on behalf of user %s (%s)",user,userbuf); + cmd_write_nil(); + goto cleanup; + } +#endif + } + + /* expect empty challenge from server */ + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[initial] failed"); + goto cleanup; + } else if(chal.length) { + free(chal.value); + syslog(LOG_WARNING,"cmd_read[initial] not empty"); + goto cleanup; + } + + /* + * obtain credentials for requested service + */ + + buf.value = argv[1]; + buf.length = strlen(argv[1]); + if(gss_import_name (&smn,&buf,gss_nt_service_name,&crname) != + GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_import_name(%s) failed",buf.value); + cmd_write_nil(); + goto cleanup; + } + + /* initial init_sec_context call, and send data */ + memcpy(&oid,&gss_mech_krb5,sizeof(oid)); + smj = gss_init_sec_context + (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,oid, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS, + GSS_C_NO_BUFFER,0,&resp,0,0); + if((smj == GSS_S_COMPLETE) || (smj == GSS_S_CONTINUE_NEEDED)) { + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[init_sec_context] failed"); + goto cleanup; + } + } + + /* loop until init_sec_context is done */ + while(smj == GSS_S_CONTINUE_NEEDED) { + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[init_sec_context] failed"); + goto cleanup; + } else if(!chal.length) { + syslog(LOG_WARNING,"cmd_read[init_sec_context] empty"); + goto cleanup; + } else { + smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname, + GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,0, + GSS_C_NO_CHANNEL_BINDINGS,&chal,0, + &resp,0,0); + if(chal.value) free(chal.value); + if((smj == GSS_S_COMPLETE) || (smj == GSS_S_CONTINUE_NEEDED)) { + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[init_sec_context] failed"); + goto cleanup; + } + } + } + } + + switch(smj) { + case GSS_S_COMPLETE: + /* get challenge and unwrap it */ + if(cmd_read(&chal)) { + syslog(LOG_WARNING,"cmd_read[gss_unwrap] failed"); + goto cleanup; + } + smj = gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop); + if(chal.value) free(chal.value); + if(smj != GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_unwrap failed"); + cmd_write_nil(); + goto cleanup; + } else if(resp.length < 4) { + syslog(LOG_WARNING,"challenge too short"); + gss_release_buffer (&smn,&resp); + cmd_write_nil(); + goto cleanup; + } else if(!( ((char*)resp.value)[0] & AUTH_GSSAPI_P_NONE)) { + syslog(LOG_WARNING,"invalid challenge"); + gss_release_buffer (&smn,&resp); + cmd_write_nil(); + goto cleanup; + } + + /* prepare response to challenge */ + buf.length = 4 + (user ? strlen(user) : 0); + buf.value = malloc(buf.length); + memcpy (buf.value,resp.value,4); + gss_release_buffer (&smn,&resp); + *(char*)buf.value = AUTH_GSSAPI_P_NONE; + if(user) memcpy((char*)buf.value + 4, user, buf.length - 4); + + /* wrap response and send */ + smj = gss_wrap (&smn,ctx,0,qop,&buf,&conf,&resp); + free(buf.value); + if(smj != GSS_S_COMPLETE) { + syslog(LOG_WARNING,"gss_unwrap failed"); + cmd_write_nil(); + goto cleanup; + } + i = cmd_write(&resp); + gss_release_buffer (&smn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_write[gss_wrap] failed"); + goto cleanup; + } + + /* success! */ + if(cmd_success()) syslog(LOG_WARNING,"cmd_success failed"); + goto cleanup; + + case GSS_S_CREDENTIALS_EXPIRED: +#ifdef DEBUG + syslog(LOG_INFO,"Kerberos credentials expired (try running kinit)"); +#endif + if(cmd_message("Kerberos credentials expired (try running kinit)",0)) { + syslog(LOG_WARNING,"cmd_message[credentials expired] failed"); + goto cleanup; + } + cmd_write_nil(); + goto cleanup; + + case GSS_S_FAILURE: + if (smn == (OM_uint32) KRB5_FCC_NOFILE) { +#ifdef DEBUG + syslog(LOG_INFO,"No credentials cache found (try running kinit)"); +#endif + if(cmd_message("No credentials cache found (try running kinit)",0)) { + syslog(LOG_WARNING,"cmd_message[no cache file found] failed"); + goto cleanup; + } + } else { + mctx = 0; + do { + gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI failure: %s",resp.value); +#endif + i = cmd_message("GSSAPI failure: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[failure] failed"); + goto cleanup; + } + } while(mctx); + } + cmd_write_nil(); + goto cleanup; + + default: + mctx = 0; + do { + gss_display_status (&dsmn,smn,GSS_C_GSS_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI failure: %s",resp.value); +#endif + i = cmd_message("Unknown GSSAPI failure: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[unknown failure] failed"); + goto cleanup; + } + } while(mctx); + if(!mctx) do { + gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, + GSS_C_NO_OID,&mctx,&resp); +#ifdef DEBUG + syslog(LOG_INFO,"GSSAPI mechanism status: %s",resp.value); +#endif + i = cmd_message("GSSAPI mechanism status: ",resp.value,0); + gss_release_buffer (&dsmn,&resp); + if(i) { + syslog(LOG_WARNING,"cmd_message[unknown failure 2] failed"); + goto cleanup; + } + } while(mctx); + cmd_write_nil(); + goto cleanup; + } + + cleanup: + if(ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,0); + if(crname != GSS_C_NO_NAME) gss_release_name (&smn,&crname); + closelog(); + exit(0); + return 0; +} diff --git a/web/src/pubcookie/wp_tclsh.c b/web/src/pubcookie/wp_tclsh.c new file mode 100644 index 00000000..e7fe14a7 --- /dev/null +++ b/web/src/pubcookie/wp_tclsh.c @@ -0,0 +1,189 @@ +/* + * tclAppInit.c -- + * + * Provides a default version of the main program and Tcl_AppInit + * procedure for Tcl applications (without Tk). + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclAppInit.c,v 1.4 1999/02/03 02:58:26 stanton Exp $ + */ + +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifdef TCL_XT_TEST +#include <X11/Intrinsic.h> +#endif + +#include "tcl.h" + +/********** (start mihodge) *************************************/ +#include "wp_uidmapper_lib.h" +#include <errno.h> +#include <stdlib.h> /* getenv */ +/********** (end mihodge) *************************************/ + +/* + * The following variable is a special hack that is needed in order for + * Sun shared libraries to be used for Tcl. + */ + +extern int matherr(); +int *tclDummyMathPtr = (int *) matherr; + + +#ifdef TCL_TEST +extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); +extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif /* TCL_TEST */ +#ifdef TCL_XT_TEST +extern int Tclxttest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif + +/* + *---------------------------------------------------------------------- + * + * main -- + * + * This is the main program for the application. + * + * Results: + * None: Tcl_Main never returns here, so this procedure never + * returns either. + * + * Side effects: + * Whatever the application does. + * + *---------------------------------------------------------------------- + */ + +int +main(argc, argv) + int argc; /* Number of command-line arguments. */ + char **argv; /* Values of command-line arguments. */ +{ + /********** PUBCOOKIE-Specific Inclusion **************************/ + char *user,sessid[WP_BUF_SIZE],*cookie; + int uid; + unsigned key[WP_KEY_LEN]; + + memset((void *) key, 0, sizeof(unsigned int) * WP_KEY_LEN); + sessid[0] = '\0'; + user = getenv("REMOTE_USER"); + if(!((((cookie = getenv("QUERY_STRING")) + && wp_parse_cookie(cookie,"sessid","&@% ",sessid,WP_BUF_SIZE)) + || ((cookie = getenv("HTTP_COOKIE")) + && wp_parse_cookie(cookie,"sessid",";@ ",sessid,WP_BUF_SIZE))) + && wp_sessid2key(sessid,key))) + cookie = NULL; + + if((getuid() == WEBSERVER_UID) && (user || cookie)){ + if(wp_uidmapper_getuid(user ? user : "",key,&uid) == -1) { + fprintf(stderr,"wp_uidmapper_getname(%s,%s) failed\n",user ? user : "",sessid); + return 1; + } else if(setuid(uid)) { + fprintf(stderr,"setuid(%i) failed: %s\n",uid,strerror(errno)); + return 1; + } + } else { + setuid(getuid()); + } + /********** (end PUBCOOKIE) *************************************/ + +#ifdef TCL_XT_TEST + XtToolkitInitialize(); +#endif + Tcl_Main(argc, argv, Tcl_AppInit); + return 0; /* Needed only to prevent compiler warning. */ +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppInit -- + * + * This procedure performs application-specific initialization. + * Most applications, especially those that incorporate additional + * packages, will have their own version of this procedure. + * + * Results: + * Returns a standard Tcl completion code, and leaves an error + * message in interp->result if an error occurs. + * + * Side effects: + * Depends on the startup script. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_AppInit(interp) + Tcl_Interp *interp; /* Interpreter for application. */ +{ + if (Tcl_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + +#ifdef TCL_TEST +#ifdef TCL_XT_TEST + if (Tclxttest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } +#endif + if (Tcltest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, + (Tcl_PackageInitProc *) NULL); + if (TclObjTest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + if (Procbodytest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, + Procbodytest_SafeInit); +#endif /* TCL_TEST */ + + /* + * Call the init procedures for included packages. Each call should + * look like this: + * + * if (Mod_Init(interp) == TCL_ERROR) { + * return TCL_ERROR; + * } + * + * where "Mod" is the name of the module. + */ + + /* + * Call Tcl_CreateCommand for application-specific commands, if + * they weren't already created by the init procedures called above. + */ + + /* + * Specify a user-specific startup file to invoke if the application + * is run interactively. Typically the startup file is "~/.apprc" + * where "app" is the name of the application. If this line is deleted + * then no user-specific startup file will be run under any conditions. + */ + + Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); + return TCL_OK; +} diff --git a/web/src/pubcookie/wp_uidmapper.c b/web/src/pubcookie/wp_uidmapper.c new file mode 100644 index 00000000..662e9b3a --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper.c @@ -0,0 +1,312 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "id_table.h" +#include "wp_uidmapper_lib.h" + + +/* Makefile should #define: + * + * WP_UIDMAPPER_SOCKET + */ + +unsigned long send_full(int fd,void *buf,unsigned long len,int flags) { + unsigned long total,i; + for(total = 0; total < len; total += i) { + i = send(fd,(char*)buf + total, len - total,flags); + if(i == -1) return -1; + } + return total; +} + +static char *socketname = WP_UIDMAPPER_SOCKET; +static int socketname_remove = 0; + +void socketname_cleanup(void) { + unlink(socketname); +} + +void quit_handler(int signal) { + exit(signal); +} + +int main(int argc, char *argv[]) { + extern char *optarg; + extern int optind, opterr, optopt; + + int debug,log_opt; + mode_t sockmode; + + id_table_range *range; + id_table table; + struct sockaddr_un sun,rsun; + struct sigaction sa; + int is_err,i,ssock,uid; + unsigned int kbuf[WP_KEY_LEN]; + char rbuf[WP_BUF_SIZE],cbuf[WP_BUF_SIZE],rcmd; + struct msghdr rmh,smh; + struct iovec riov[3],siov[1]; +#ifndef DGRAM_MODE + int csock,rsun_len; +#endif + struct ucred cred; + + /* + * process command line arguments + */ + + debug = 0; + log_opt = 0; + sockmode = 0600; + + for(is_err = 0; !is_err && ((i = getopt(argc,argv,"dlrm:s:u:")) != -1); ) { + switch(i) { + case 'd': debug++; break; + case 'l': log_opt |= LOG_PERROR; break; + case 'm': sockmode = strtol(optarg,NULL,0); break; + case 'r': socketname_remove = 1; break; + case 's': socketname = optarg; break; + case 'u': umask(strtol(optarg,NULL,0)); break; + case '?': is_err = 1; break; + } + } + if((optind + 1) == argc) { + range = id_table_range_new(argv[optind]); + if(!range) is_err = 1; + } else { + is_err = 1; + } + if(is_err) { + fprintf(stderr,"Usage: uidmapper [-d] [-l] [-r] [-m mode] [-s socketname] [-u umask] uidranges\n"); + exit(1); + } + + /* + * main initialization + */ + + openlog(argv[0],log_opt,LOG_MAIL); + + if(id_table_init(&table,range)) { + syslog(LOG_ERR,"could not initialize tables: %s\n",strerror(errno)); + exit(1); + } + id_table_range_delete(range); + + sa.sa_handler = quit_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGHUP,&sa,0); + sigaction(SIGINT,&sa,0); + sigaction(SIGQUIT,&sa,0); + sigaction(SIGTERM,&sa,0); + + if(socketname_remove) + socketname_cleanup(); + + /* + * open socket + */ + +#ifdef DGRAM_MODE + ssock = socket(AF_UNIX,SOCK_DGRAM,0); +#else + ssock = socket(AF_UNIX,SOCK_STREAM,0); +#endif + if(ssock < 0) { + syslog(LOG_ERR,"%s: socket: %s\n",socketname,strerror(errno)); + exit(1); + } + /* sun.sun_len = strlen(socketname) + 1; */ + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,socketname); + if(bind(ssock,(struct sockaddr*)&sun,sizeof(sun))) { + syslog(LOG_ERR,"%s: bind: %s\n",socketname,strerror(errno)); + exit(1); + } + atexit(socketname_cleanup); + chmod(ssock,sockmode); + +#ifndef DGRAM_MODE + if(listen(ssock,8)) { + syslog(LOG_ERR,"%s: listen: %s\n",socketname,strerror(errno)); + exit(1); + } +#endif + +#ifdef DGRAM_MODE + if(debug >= 1) syslog(LOG_INFO,"SOCK_DGRAM socket opened"); +#else + if(debug >= 1) syslog(LOG_INFO,"SOCK_STREAM socket opened"); +#endif + + /* + * accept commands + */ + + riov[0].iov_base = &rcmd; + riov[0].iov_len = 1; + riov[1].iov_base = kbuf; + riov[1].iov_len = WP_KEY_LEN * sizeof(unsigned int); + riov[2].iov_base = rbuf; + riov[2].iov_len = WP_BUF_SIZE - 1; + rmh.msg_name = &rsun; + rmh.msg_namelen = sizeof(rsun); + rmh.msg_iov = riov; + rmh.msg_iovlen = 3; + rmh.msg_control = cbuf; + rmh.msg_controllen = riov[0].iov_len + riov[1].iov_len + riov[2].iov_len; + rmh.msg_flags = 0; + + /* siov[0].iov_base */ + /* siov[0].iov_len */ + smh.msg_name = NULL; + smh.msg_namelen = 0; + smh.msg_iov = siov; + /* smh.msg_iovlen */ + smh.msg_control = NULL; + smh.msg_controllen = 0; + smh.msg_flags = 0; + +#ifndef DGRAM_MODE + csock = -1; +#endif + + while(1) { +#ifdef DGRAM_MODE + i = recvmsg(ssock,&rmh,0); +#else + if(csock >= 0) close(csock); + rsun.sun_family = AF_UNIX; + rsun_len = sizeof(rsun); + csock = accept(ssock,(struct sockaddr*)&rsun,&rsun_len); + if(csock == -1) { + syslog(LOG_ERR,"accept: %s\n",strerror(errno)); + break; + } + if(debug >= 2) { + i = sizeof(cred); + if(getsockopt(csock,SOL_SOCKET,SO_PEERCRED,&cred,&i) == -1) { + syslog(LOG_INFO,"getsockopt(SO_PEERCRED) failed: %s",strerror(errno)); + } else { + syslog(LOG_INFO,"connection from pid=%i uid=%i gid=%i\n", + cred.pid,cred.uid,cred.gid); + } + } + i = recvmsg(csock,&rmh,0); +#endif + + if(i == -1) { + syslog(LOG_ERR,"recvmsg: %s\n",strerror(errno)); + break; + } + if(debug >= 2) + syslog(LOG_INFO,"recvd datagram [size=%i] from %s [size=%i]\n", + i,rsun.sun_path,rmh.msg_namelen); + + /* check that datagram is well formed */ + if(i < 1) { + syslog(LOG_WARNING,"recv: recvd datagram that is too small\n"); + continue; + } + i--; +#ifdef DGRAM_MODE + smh.msg_name = rmh.msg_name; + smh.msg_namelen = rmh.msg_namelen; +#endif + + if(rcmd == 'u') { + if(!i) { + syslog(LOG_WARNING,"recv: recvd 'u' datagram with no payload\n"); + continue; + } + rbuf[i - (WP_KEY_LEN * sizeof(unsigned int))] = 0; + uid = id_table_create_id(&table,rbuf,kbuf); + if(debug >= 1) syslog(LOG_INFO,"request uid(%s) = %i\n",rbuf,uid); + if(uid == -1) { + char sbuf[2 * WP_BUF_SIZE],*sep = strerror(errno); + sprintf(sbuf,"id_table_create_id(%s,[",rbuf); + for(i = 0; i < WP_KEY_LEN; i++) + sprintf(sbuf + strlen(sbuf), "%u,", kbuf[i]); + + sprintf(sbuf + strlen(sbuf) - 1, "]): %s\n",sep); + syslog(LOG_ERR,sbuf); + /* break; hobble along rather than die */ + } + + siov[0].iov_base = &uid; + siov[0].iov_len = sizeof(uid); + smh.msg_iovlen = 1; +#ifdef DGRAM_MODE + if(sendmsg(ssock,&smh,0) == -1) +#else + if(sendmsg(csock,&smh,0) == -1) +#endif + syslog(LOG_WARNING,"sendmsg: %s\n",strerror(errno)); + + } else if(rcmd == 'n') { + if(i != sizeof(uid)) { + syslog(LOG_WARNING,"recv: recvd 'n' datagram with invalid payload\n"); + continue; + } + + memcpy(&uid,kbuf,sizeof(uid)); + siov[0].iov_base = id_table_get_name(&table,uid); + if(debug >= 1) + syslog(LOG_INFO,"request name(%d) = %s\n",uid,siov[0].iov_base); + + if(siov[0].iov_base) { + siov[0].iov_len = strlen(siov[0].iov_base); + smh.msg_iovlen = 1; + } else { + smh.msg_iovlen = 0; + } +#ifdef DGRAM_MODE + if(sendmsg(ssock,&smh,0) == -1) +#else + if(sendmsg(csock,&smh,0) == -1) +#endif + syslog(LOG_WARNING,"sendmsg: %s\n",strerror(errno)); + + } else if(rcmd == 'c') { + if(debug >= 1) syslog(LOG_INFO,"request clear()"); + if(id_table_remove_stale(&table)) { + syslog(LOG_WARNING,"id_table_remove_stale: %s\n",strerror(errno)); + break; + } + } +#ifdef HONOR_QUIT + else if(rcmd == 'q') { + if(debug >= 1) syslog(LOG_INFO,"quit requested"); + break; + } +#endif + else { + syslog(LOG_WARNING,"invalid request received"); + } + } +#ifndef DGRAM_MODE + if(csock >= 0) close(csock); +#endif + + /* + * clean up (never really get this far) + */ + + id_table_destroy(&table); + close(ssock); + exit(0); + return 0; +} diff --git a/web/src/pubcookie/wp_uidmapper_lib.c b/web/src/pubcookie/wp_uidmapper_lib.c new file mode 100644 index 00000000..ddaf5175 --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper_lib.c @@ -0,0 +1,178 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "wp_uidmapper_lib.h" + + +static char *xdigits = "0123456789ABCDEF"; + +static int do_handshake(char *sockname, + struct iovec *out,int outlen,int *routbytes, + struct iovec *in,int inlen,int *rinbytes) { + int sock,i; + struct msghdr mh; + struct sockaddr_un sun; + +#ifdef DGRAM_MODE + sock = socket(AF_UNIX,SOCK_DGRAM,0); +#else + sock = socket(AF_UNIX,SOCK_STREAM,0); +#endif + if(sock < 0) return -1; + + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,sockname); + if(connect(sock,(struct sockaddr*)&sun,sizeof(sun))) return -1; + + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = out; + mh.msg_iovlen = outlen; + mh.msg_control = NULL; + mh.msg_controllen = 0; + mh.msg_flags = 0; + + if((i = sendmsg(sock,&mh,0)) == -1) { + close(sock); + return -1; + } + if(routbytes) *routbytes = i; + + if(in) { + mh.msg_iov = in; + mh.msg_iovlen = inlen; + mh.msg_flags = 0; + if((i = recvmsg(sock,&mh,0)) == -1) { + close(sock); + return -1; + } + if(rinbytes) *rinbytes = i; + } + close(sock); + return 0; +} + +int wp_uidmapper_getuid(char *name,unsigned int *key,int *puid) { + int uid,outbytes,inbytes; + char cmd; + struct iovec out[3],in[1]; + + cmd = 'u'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + out[1].iov_base = key; + out[1].iov_len = WP_KEY_LEN * sizeof(unsigned int); + out[2].iov_base = name ? name : ""; + out[2].iov_len = name ? strlen(name) : 0; + in[0].iov_base = &uid; + in[0].iov_len = sizeof(uid); + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,3,&outbytes,in,1,&inbytes)) + return -1; + if((outbytes != (1 + out[1].iov_len) + out[2].iov_len) || (inbytes != in[0].iov_len)) + return -1; + *puid = uid; + return 0; +} + +int wp_uidmapper_getname(int uid,char *name,int namelen) { + int outbytes,inbytes; + char cmd; + struct iovec out[2],in[1]; + + cmd = 'n'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + out[1].iov_base = &uid; + out[1].iov_len = sizeof(uid); + in[0].iov_base = name; + in[0].iov_len = namelen - 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,2,&outbytes,in,1,&inbytes)) + return -1; + if(outbytes != (1 + out[1].iov_len)) return -1; + name[inbytes] = 0; + return 0; +} + +int wp_uidmapper_clear() { + int outbytes; + char cmd; + struct iovec out[1]; + + cmd = 'c'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,1,&outbytes,NULL,0,NULL)) return -1; + if(outbytes != 1) return -1; + return 0; +} + +int wp_uidmapper_quit() { + int outbytes; + char cmd; + struct iovec out[1]; + + cmd = 'q'; + out[0].iov_base = &cmd; + out[0].iov_len = 1; + + if(do_handshake(WP_UIDMAPPER_SOCKET,out,1,&outbytes,NULL,0,NULL)) return -1; + if(outbytes != 1) return -1; + return 0; +} + +int wp_sessid2key(char *ids,unsigned int *ida) { + int i, j, k; + unsigned int n; + char *p; + + i = j = 0; + while(1){ + n = 0; + for(k = 0; k < 8; k++) + if((p = strchr(xdigits, toupper((int) ids[j++]))) != NULL) + n = (n << 4) | (p - xdigits); + else + return(0); + + ida[i] = n; + if(++i == WP_KEY_LEN) + return(ids[j] == '\0'); + else if(ids[j++] != '.') + return(0); + } +} + +int wp_parse_cookie (char *cookie,char *cname,char *terms,char *cvalue,int vmax) { + char *p, *q; + int i; + + if((p = strstr(cookie, cname)) != NULL){ + p += strlen(cname) + 1; /* skip cname and equals */ + q = cvalue; + while(*p && !strchr(terms, *p)){ + *q++ = *p++; + if((q - cvalue) >= vmax) + return(0); + } + + *q = '\0'; + return(1); + } + + return(0); +} diff --git a/web/src/pubcookie/wp_uidmapper_lib.h b/web/src/pubcookie/wp_uidmapper_lib.h new file mode 100644 index 00000000..e1832454 --- /dev/null +++ b/web/src/pubcookie/wp_uidmapper_lib.h @@ -0,0 +1,25 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#ifndef _WP_UIDMAPPER_LIB_H_ +#define _WP_UIDMAPPER_LIB_H_ + +int wp_uidmapper_getuid(char *name,unsigned int *key,int *puid); +int wp_uidmapper_getname(int uid,char *name,int namelen); +int wp_uidmapper_clear(); +int wp_uidmapper_quit(); +int wp_sessid2key(char *ids,unsigned int *ida); + +#define WP_BUF_SIZE 1024 +#define WP_KEY_LEN 6 + +#endif diff --git a/web/src/pubcookie/wp_umc.c b/web/src/pubcookie/wp_umc.c new file mode 100644 index 00000000..a55d2127 --- /dev/null +++ b/web/src/pubcookie/wp_umc.c @@ -0,0 +1,63 @@ +/* ======================================================================== + * Copyright 2006 University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "wp_uidmapper_lib.h" + + +int main(int argc,char *argv[]) { + char name[WP_BUF_SIZE],sessid[WP_BUF_SIZE]; + int uid,i,key[WP_KEY_LEN]; + + if(argc >= 2) { + if(*argv[1] == 'u') { + if(argc >= 3) { + memset(key,0,WP_KEY_LEN * sizeof(int)); + if(argc >= 4){ + if(wp_parse_cookie(argv[3],"sessid",";@",sessid,WP_BUF_SIZE)) + (void)wp_sessid2key(sessid,key); + } + + if(wp_uidmapper_getuid((argv[2][0] == '\0') ? NULL : argv[2],key,&uid) != -1) { + printf("uid = %i\n",uid); + return 0; + } else fprintf(stderr,"wp_uidmapper_getuid error: %s\n", + strerror(errno)); + } + } else if(*argv[1] == 'n') { + if(argc >= 3) { + i = wp_uidmapper_getname(strtol(argv[2],NULL,0),name,WP_BUF_SIZE); + if(i != -1) { + printf("name = %s\n",name); + return 0; + } else fprintf(stderr,"wp_uidmapper_getname error: %s\n", + strerror(errno)); + } + } else if(*argv[1] == 'c') { + if(wp_uidmapper_clear() != -1) { + printf("clear command sent\n"); + return 0; + } else fprintf(stderr,"wp_uidmapper_clear error: %s\n", + strerror(errno)); + } else if(*argv[1] == 'q') { + if(wp_uidmapper_quit() != -1) { + printf("quit command sent\n"); + return 0; + } else fprintf(stderr,"wp_uidmapper_quit error: %s\n", + strerror(errno)); + } + } + fprintf(stderr,"Usage: wp_umc [u name [key] ] [n uid] [c] [q]\n"); + return -1; +} |