Commit 3960bf9f0c42c9f83713f75a56911c19fd69a991

Authored by Totoro
1 parent 5646c9a9

CXM_message_cosntants.anubis:

Add Tegamigawa constants

CXM_making_a_web_site.anubis:
Add partial_content function without any HTML_Head_Tag

CXM_multihost_http_server.anubis:
Fix etag as quoted string in multihost_http_server.
When file is missing, now return 404 error instead of nothing
Add http_direct_handler, to be able to call a website from another way than
internal webserver listener
CXM_message_constants.anubis
1 -/*  
2 - *  
3 - * User: David RENE  
4 - * Date: 07/04/2007  
5 - * Time: 16:06  
6 - * (c) Calexium  
7 - *  
8 - */  
9 -  
10 -public define Word32 _NO_NAME_MSG = 0x00000000.  
11 -  
12 -// **************** MAILBOX PROTOCOL ***************  
13 -  
14 -public define Word32 _C_SCAN_FOR_BOXES = 0x33770001. // Ask Boxes to publish their informations  
15 -public define Word32 _C_PUBLISH_BOX_STATUS = 0x33770002. // Used by Boxes to publish their informations  
16 -public define Word32 _C_SHUTDOWN_BOX = 0x33770003. // Used to ask a box to shutdown  
17 -public define Word32 _CXM_SET_BOX_NETWORK_PARAMS = 0x33770004. // Define network configuration of boxes  
18 -public define Word32 _CXM_RESET_ADMIN_PWD = 0x33770005. // Ask the MailFountain to reset the admin pwd.  
19 -public define Word32 _CXM_FULL_RESET = 0x33770006. // Ask the MailFountain to proceed to a full reset of its data. After that, the MailFountain is totally empty (mail, config, domain, logs, etc...)  
20 -public define Word32 _CXM_FORCE_PUBLISH_MF_CONFIG = 0x33770007. // Ask the MailFountain to proceed a Config publishing to DomainManager  
21 -  
22 - // **************** PACKAGE BUILDER ***************  
23 -  
24 -public define Word32 _CXM_PKG_MSG_BASIS = 0x33770400. //  
25 -public define Word32 _CXM_PKG_CONTAINER = 0x33770401.  
26 -public define Word32 _CXM_PKG_HEADER_PART = 0x33770402. // Header Message for Script  
27 -public define Word32 _CXM_PKG_SCRIPT_PART = 0x33770403. // Main Message for Script  
28 -public define Word32 _CXM_PKG_S_ADD_FILE = 0x33770404. // script action to add file in the destination  
29 -public define Word32 _CXM_PKG_S_RUN = 0x33770405. // script action to run a command  
30 -public define Word32 _CXM_PKG_INDEX_PART = 0x33770440. // ID of package Index part  
31 -public define Word32 _CXM_PKG_IDX_ENTRY = 0x33770441. // Index entry information  
32 -  
33 - // **************** UPDATE SERVICE ***************  
34 -  
35 -public define Word32 _CXM_UPDATE_SERVICE_MSG_BASIS = 0x33770800. //  
36 -public define Word32 _CXM_UPD_SERVICE_ID = 0x33770801.  
37 -public define Word32 _CXM_UPD_HAS_UPDATE = 0x33770802. //  
38 -public define Word32 _CXM_UPD_LIST_CLASS_FILES = 0x33770803. // List the files contained in the class path  
39 -  
40 - // **************** SERVICE NEGOCIATION ***************  
41 -  
42 -public define Word32 _CXM_SERVICE_NEGOCIATION_BASIS = 0x33770C00. //  
43 -public define Word32 _CXM_REQUEST_FOR_SERVICE = 0x33770C01. //  
44 -public define Word32 _CXM_LOGIN = 0x33770C02. //  
45 -  
46 - // **************** GENERIC PROTOCOL ***************  
47 -  
48 -public define Word32 _CXM_GENERIC_PROTOCOL_BASIS = 0x33771000. //  
49 -public define Word32 _CXM_ACK = 0x33771001. //  
50 -public define Word32 _CXM_ACK_RESULT_MSG = 0x33771002. //  
51 -  
52 - // **************** FTP SERVICE ***************  
53 -  
54 -public define Word32 _CXM_FTP_SERVICE_MSG_BASIS = 0x33771400. //  
55 -public define Word32 _CXM_FTP_SERVICE_ID = 0x33771401.  
56 -public define Word32 _CXM_FTP_GET_FILE = 0x33771402.  
57 -public define Word32 _CXM_FTP_START_TRANSFERT = 0x33771403.  
58 -public define Word32 _CXM_FTP_DATA = 0x33771404.  
59 -  
60 - // ************** LOGGER SERVICE **************  
61 -  
62 -public define Word32 _CXM_LOGGER_SERVICE_MSG_BASIS = 0x33771800. //  
63 -public define Word32 _CXM_LOGGER_SERVICE_ID = 0x33771801.  
64 -public define Word32 _CXM_LOGGER_LOG = 0x33771802.  
65 -  
66 - // ************** DOMAIN SERVICE **************  
67 -  
68 -// MF <-> DomainManager  
69 -public define Word32 _CXM_DOMAIN_SERVICE_MSG_BASIS = 0x33771C00. //  
70 -public define Word32 _CXM_DOMAIN_SERVICE_ID = 0x33771C01.  
71 -public define Word32 _CXM_DOMAIN_PUBLISH_MF_CONFIG = 0x33771C02.  
72 -public define Word32 _CXM_DOMAIN_GET_NAME = 0x33771C03.  
73 -public define Word32 _CXM_DOMAIN_GET_MY_IP = 0x33771C04.  
74 -public define Word32 _CXM_DOMAIN_PUBLISH_MY_IP = 0x33771C05.  
75 -public define Word32 _CXM_DOMAIN_PUBLISH_DYN_TEST = 0x33771C06.  
76 -public define Word32 _CXM_DOMAIN_GET_STATUS = 0x33771C07.  
77 -public define Word32 _CXM_DOMAIN_GET_DOMAIN_INFO = 0x33771C08.  
78 -public define Word32 _CXM_DOMAIN_CRITICAL_ALERT = 0x33771C09.  
79 -public define Word32 _CXM_DOMAIN_COMMAND_RESULT = 0x33771C0A.  
80 -  
81 -  
82 -// DomainManager <-> Gandi  
83 -public define Word32 _CXM_GANDI_SERVICE_ID = 0x33771D00.  
84 -public define Word32 _CXM_GANDI_CHECK_AVAILABILITY = 0x33771D01. // 'NAME' (String): Base names (without extension) of the wanted domains  
85 - // --> CXM_ACK with 'DOMAINS' (String): Array of avaiblable domains  
86 -public define Word32 _CXM_GANDI_CREATE_CONTACT = 0x33771D02. // 'CLASS' (String):  
87 - // 'FIRSTNAME', 'LASTNAME', 'ADDRESS', 'ZIPCODE', 'CITY', 'COUNTRY', 'PHONE', 'EMAIL' (String)  
88 - // --> CXM_ACK with 'CONTACT_HANDLE' (String): Created handle for this contact  
89 -public define Word32 _CXM_GANDI_CREATE_DOMAIN = 0x33771D03. // 'DOMAIN' (String): Domain full name  
90 - // 'OWNER' (String): Owner handle  
91 - // --> CXM_ACK with 'DOMAIN_HANDLE' (String): Created handle for this domain  
92 - // ************** MF INSTALLER SERVICE **************  
93 -  
94 -public define Word32 _CXM_INSTALLER_SERVICE_MSG_BASIS= 0x33772000.  
95 -public define Word32 _CXM_INSTALLER_SERVICE_ID = 0x33772001.  
96 -public define Word32 _CXM_INSTALLER_REGISTER_APP_ID = 0x33772002.  
97 -public define Word32 _CXM_INSTALLER_GET_NEW_SERIALS = 0x33772003.  
98 -public define Word32 _CXM_INSTALLER_CONFIRM_SERIALS_PUBLICATION = 0x33772004.  
99 -public define Word32 _CXM_INSTALLER_GET_MODELS = 0x33772005. // returns the MF models list  
100 -  
101 -// *************************************************  
102 -// ************* MF API *************  
103 -  
104 -// ************* ACCOUNTS SERVICE *************  
105 -  
106 -public define Word32 _CXM_ACCOUNT_SERVICE_MSG_BASIS = 0x33772100.  
107 -  
108 -// ************* MAILINGS SERVICE *************  
109 -  
110 -public define Word32 _CXM_MAILING_SERVICE_MSG_BASIS = 0x33772200.  
111 -public define Word32 _CXM_MAILING_SERVICE_ID = 0x33772200. // same as MSG_BASIS  
112 -  
113 -public define Word32 _CXM_MAILING_CREATE_CONTACT = 0x33772201.  
114 -public define Word32 _CXM_MAILING_UPDATE_CONTACT = 0x33772202.  
115 -public define Word32 _CXM_MAILING_DELETE_CONTACT = 0x33772203.  
116 -  
117 -public define Word32 _CXM_MAILING_CREATE_MAILING = 0x33772211.  
118 -public define Word32 _CXM_MAILING_UPDATE_MAILING = 0x33772212.  
119 -public define Word32 _CXM_MAILING_DELETE_MAILING = 0x33772213.  
120 -  
121 -public define Word32 _CXM_MAILING_ADD_CONTACT_TO_MAILING = 0x33772221.  
122 -public define Word32 _CXM_MAILING_REMOVE_CONTACT_FROM_MAILING = 0x33772222.  
123 -  
124 -  
125 -// ************* DIRECTORY SERVICE *************  
126 -  
127 -public define Word32 _CXM_DIRECTORY_SERVICE_MSG_BASIS = 0x33772300.  
128 -  
129 -// ************* BACKUP SERVICE *************  
130 -  
131 -public define Word32 _CXM_BACKUP_SERVICE_MSG_BASIS = 0x33772400.  
132 -public define Word32 _CXM_BACKUP_SERVICE_ID = 0x33772401.  
133 -public define Word32 _CXM_BACKUP_GET_STATUS = 0x33772402. /// Get backup status for a given MF (can subscribe, subscribed, subscription end date...)  
134 -public define Word32 _CXM_BACKUP_STARTING_BACKUP = 0x33772403. /// Notify BackupService that backup process is starting  
135 -public define Word32 _CXM_BACKUP_FINISHING_BACKUP = 0x33772404. /// Notify BackupService that backup process is finishing  
136 -public define Word32 _CXM_BACKUP_STARTING_RESTORE = 0x33772405. /// Notify BackupService that restore process is starting  
137 -public define Word32 _CXM_BACKUP_FINISHING_RESTORE = 0x33772406. /// Notify BackupService that restore process is finishing  
138 -  
139 -// ************* STATISTICS SERVICE *************  
140 -  
141 -public define Word32 _CXM_STATS_SERVICE_MSG_BASIS = 0x33772500.  
142 -  
143 -// ************* SUPERVISER SERVICE *************  
144 -  
145 -public define Word32 _CXM_SUPERVISER_SERVICE_MSG_BASIS = 0x33772600.  
146 -public define Word32 _CXM_SUPERVISER_SERVICE_ID = 0x33772600.  
147 -public define Word32 _CXM_SUPERVISER_GET_STATUS = 0x33772601.  
148 -  
149 -// *************************************************  
150 -// ************* KERO_PBX API *************  
151 -  
152 -public define Word32 _CXM_KERO_PBX_MSG_BASIS = 0x33780000. // Ask Boxes to publish their informations 1 +/*
  2 + *
  3 + * User: David RENE
  4 + * Date: 07/04/2007
  5 + * Time: 16:06
  6 + * (c) Calexium
  7 + *
  8 + */
  9 +
  10 +public define Word32 _NO_NAME_MSG = 0x00000000.
  11 +
  12 +// **************** MAILBOX PROTOCOL ***************
  13 +
  14 +public define Word32 _C_SCAN_FOR_BOXES = 0x33770001. // Ask Boxes to publish their informations
  15 +public define Word32 _C_PUBLISH_BOX_STATUS = 0x33770002. // Used by Boxes to publish their informations
  16 +public define Word32 _C_SHUTDOWN_BOX = 0x33770003. // Used to ask a box to shutdown
  17 +public define Word32 _CXM_SET_BOX_NETWORK_PARAMS = 0x33770004. // Define network configuration of boxes
  18 +public define Word32 _CXM_RESET_ADMIN_PWD = 0x33770005. // Ask the MailFountain to reset the admin pwd.
  19 +public define Word32 _CXM_FULL_RESET = 0x33770006. // Ask the MailFountain to proceed to a full reset of its data. After that, the MailFountain is totally empty (mail, config, domain, logs, etc...)
  20 +public define Word32 _CXM_FORCE_PUBLISH_MF_CONFIG = 0x33770007. // Ask the MailFountain to proceed a Config publishing to DomainManager
  21 +
  22 + // **************** PACKAGE BUILDER ***************
  23 +
  24 +public define Word32 _CXM_PKG_MSG_BASIS = 0x33770400. //
  25 +public define Word32 _CXM_PKG_CONTAINER = 0x33770401.
  26 +public define Word32 _CXM_PKG_HEADER_PART = 0x33770402. // Header Message for Script
  27 +public define Word32 _CXM_PKG_SCRIPT_PART = 0x33770403. // Main Message for Script
  28 +public define Word32 _CXM_PKG_S_ADD_FILE = 0x33770404. // script action to add file in the destination
  29 +public define Word32 _CXM_PKG_S_RUN = 0x33770405. // script action to run a command
  30 +public define Word32 _CXM_PKG_INDEX_PART = 0x33770440. // ID of package Index part
  31 +public define Word32 _CXM_PKG_IDX_ENTRY = 0x33770441. // Index entry information
  32 +
  33 + // **************** UPDATE SERVICE ***************
  34 +
  35 +public define Word32 _CXM_UPDATE_SERVICE_MSG_BASIS = 0x33770800. //
  36 +public define Word32 _CXM_UPD_SERVICE_ID = 0x33770801.
  37 +public define Word32 _CXM_UPD_HAS_UPDATE = 0x33770802. //
  38 +public define Word32 _CXM_UPD_LIST_CLASS_FILES = 0x33770803. // List the files contained in the class path
  39 +
  40 + // **************** SERVICE NEGOCIATION ***************
  41 +
  42 +public define Word32 _CXM_SERVICE_NEGOCIATION_BASIS = 0x33770C00. //
  43 +public define Word32 _CXM_REQUEST_FOR_SERVICE = 0x33770C01. //
  44 +public define Word32 _CXM_LOGIN = 0x33770C02. //
  45 +
  46 + // **************** GENERIC PROTOCOL ***************
  47 +
  48 +public define Word32 _CXM_GENERIC_PROTOCOL_BASIS = 0x33771000. //
  49 +public define Word32 _CXM_ACK = 0x33771001. //
  50 +public define Word32 _CXM_ACK_RESULT_MSG = 0x33771002. //
  51 +
  52 + // **************** FTP SERVICE ***************
  53 +
  54 +public define Word32 _CXM_FTP_SERVICE_MSG_BASIS = 0x33771400. //
  55 +public define Word32 _CXM_FTP_SERVICE_ID = 0x33771401.
  56 +public define Word32 _CXM_FTP_GET_FILE = 0x33771402.
  57 +public define Word32 _CXM_FTP_START_TRANSFERT = 0x33771403.
  58 +public define Word32 _CXM_FTP_DATA = 0x33771404.
  59 +
  60 + // ************** LOGGER SERVICE **************
  61 +
  62 +public define Word32 _CXM_LOGGER_SERVICE_MSG_BASIS = 0x33771800. //
  63 +public define Word32 _CXM_LOGGER_SERVICE_ID = 0x33771801.
  64 +public define Word32 _CXM_LOGGER_LOG = 0x33771802.
  65 +
  66 + // ************** DOMAIN SERVICE **************
  67 +
  68 +// MF <-> DomainManager
  69 +public define Word32 _CXM_DOMAIN_SERVICE_MSG_BASIS = 0x33771C00. //
  70 +public define Word32 _CXM_DOMAIN_SERVICE_ID = 0x33771C01.
  71 +public define Word32 _CXM_DOMAIN_PUBLISH_MF_CONFIG = 0x33771C02.
  72 +public define Word32 _CXM_DOMAIN_GET_NAME = 0x33771C03.
  73 +public define Word32 _CXM_DOMAIN_GET_MY_IP = 0x33771C04.
  74 +public define Word32 _CXM_DOMAIN_PUBLISH_MY_IP = 0x33771C05.
  75 +public define Word32 _CXM_DOMAIN_PUBLISH_DYN_TEST = 0x33771C06.
  76 +public define Word32 _CXM_DOMAIN_GET_STATUS = 0x33771C07.
  77 +public define Word32 _CXM_DOMAIN_GET_DOMAIN_INFO = 0x33771C08.
  78 +public define Word32 _CXM_DOMAIN_CRITICAL_ALERT = 0x33771C09.
  79 +public define Word32 _CXM_DOMAIN_COMMAND_RESULT = 0x33771C0A.
  80 +
  81 +
  82 +// DomainManager <-> Gandi
  83 +public define Word32 _CXM_GANDI_SERVICE_ID = 0x33771D00.
  84 +public define Word32 _CXM_GANDI_CHECK_AVAILABILITY = 0x33771D01. // 'NAME' (String): Base names (without extension) of the wanted domains
  85 + // --> CXM_ACK with 'DOMAINS' (String): Array of avaiblable domains
  86 +public define Word32 _CXM_GANDI_CREATE_CONTACT = 0x33771D02. // 'CLASS' (String):
  87 + // 'FIRSTNAME', 'LASTNAME', 'ADDRESS', 'ZIPCODE', 'CITY', 'COUNTRY', 'PHONE', 'EMAIL' (String)
  88 + // --> CXM_ACK with 'CONTACT_HANDLE' (String): Created handle for this contact
  89 +public define Word32 _CXM_GANDI_CREATE_DOMAIN = 0x33771D03. // 'DOMAIN' (String): Domain full name
  90 + // 'OWNER' (String): Owner handle
  91 + // --> CXM_ACK with 'DOMAIN_HANDLE' (String): Created handle for this domain
  92 + // ************** MF INSTALLER SERVICE **************
  93 +
  94 +public define Word32 _CXM_INSTALLER_SERVICE_MSG_BASIS= 0x33772000.
  95 +public define Word32 _CXM_INSTALLER_SERVICE_ID = 0x33772001.
  96 +public define Word32 _CXM_INSTALLER_REGISTER_APP_ID = 0x33772002.
  97 +public define Word32 _CXM_INSTALLER_GET_NEW_SERIALS = 0x33772003.
  98 +public define Word32 _CXM_INSTALLER_CONFIRM_SERIALS_PUBLICATION = 0x33772004.
  99 +public define Word32 _CXM_INSTALLER_GET_MODELS = 0x33772005. // returns the MF models list
  100 +
  101 +// *************************************************
  102 +// ************* MF API *************
  103 +
  104 +// ************* ACCOUNTS SERVICE *************
  105 +
  106 +public define Word32 _CXM_ACCOUNT_SERVICE_MSG_BASIS = 0x33772100.
  107 +
  108 +// ************* MAILINGS SERVICE *************
  109 +
  110 +public define Word32 _CXM_MAILING_SERVICE_MSG_BASIS = 0x33772200.
  111 +public define Word32 _CXM_MAILING_SERVICE_ID = 0x33772200. // same as MSG_BASIS
  112 +
  113 +public define Word32 _CXM_MAILING_CREATE_CONTACT = 0x33772201.
  114 +public define Word32 _CXM_MAILING_UPDATE_CONTACT = 0x33772202.
  115 +public define Word32 _CXM_MAILING_DELETE_CONTACT = 0x33772203.
  116 +
  117 +public define Word32 _CXM_MAILING_CREATE_MAILING = 0x33772211.
  118 +public define Word32 _CXM_MAILING_UPDATE_MAILING = 0x33772212.
  119 +public define Word32 _CXM_MAILING_DELETE_MAILING = 0x33772213.
  120 +
  121 +public define Word32 _CXM_MAILING_ADD_CONTACT_TO_MAILING = 0x33772221.
  122 +public define Word32 _CXM_MAILING_REMOVE_CONTACT_FROM_MAILING = 0x33772222.
  123 +
  124 +
  125 +// ************* DIRECTORY SERVICE *************
  126 +
  127 +public define Word32 _CXM_DIRECTORY_SERVICE_MSG_BASIS = 0x33772300.
  128 +
  129 +// ************* BACKUP SERVICE *************
  130 +
  131 +public define Word32 _CXM_BACKUP_SERVICE_MSG_BASIS = 0x33772400.
  132 +public define Word32 _CXM_BACKUP_SERVICE_ID = 0x33772401.
  133 +public define Word32 _CXM_BACKUP_GET_STATUS = 0x33772402. /// Get backup status for a given MF (can subscribe, subscribed, subscription end date...)
  134 +public define Word32 _CXM_BACKUP_STARTING_BACKUP = 0x33772403. /// Notify BackupService that backup process is starting
  135 +public define Word32 _CXM_BACKUP_FINISHING_BACKUP = 0x33772404. /// Notify BackupService that backup process is finishing
  136 +public define Word32 _CXM_BACKUP_STARTING_RESTORE = 0x33772405. /// Notify BackupService that restore process is starting
  137 +public define Word32 _CXM_BACKUP_FINISHING_RESTORE = 0x33772406. /// Notify BackupService that restore process is finishing
  138 +
  139 +// ************* STATISTICS SERVICE *************
  140 +
  141 +public define Word32 _CXM_STATS_SERVICE_MSG_BASIS = 0x33772500.
  142 +
  143 +// ************* SUPERVISER SERVICE *************
  144 +
  145 +public define Word32 _CXM_SUPERVISER_SERVICE_MSG_BASIS = 0x33772600.
  146 +public define Word32 _CXM_SUPERVISER_SERVICE_ID = 0x33772600.
  147 +public define Word32 _CXM_SUPERVISER_GET_STATUS = 0x33772601.
  148 +
  149 +// ************* TEGAMIGAWA SERVICE *************
  150 +
  151 +public define Word32 _CXM_TEGAMIGAWA_SERVICE_MSG_BASIS = 0x33772700.
  152 +public define Word32 _CXM_TEGAMIGAWA_SERVICE_ID = 0x33772700.
  153 +public define Word32 _CXM_TEGAMIGAWA_REGISTER_CLIENT = 0x33772701.
  154 +
  155 +// *************************************************
  156 +// ************* KERO_PBX API *************
  157 +
  158 +public define Word32 _CXM_KERO_PBX_MSG_BASIS = 0x33780000. // Ask Boxes to publish their informations
web/CXM_making_a_web_site.anubis
1 -  
2 -  
3 - *Project* Anubis  
4 -  
5 - *Title* Making interactive Web sites.  
6 -  
7 - *Copyright* Copyright (c) Alain Prouté 2004-2005.  
8 - Copyright (c) Calexium 2007.  
9 -  
10 -  
11 - *Authors* Alain Prouté  
12 - David René  
13 -  
14 - *Revised* May 2007  
15 -  
16 -  
17 - *Overview*  
18 -  
19 - In this file we propose simple tools for making well structured interactive and secured  
20 - web sites.  
21 -  
22 -  
23 - ----------------------------------- Table of Contents ---------------------------------  
24 -  
25 - * (1) Structure of a web site.  
26 - ** (1.1) Three sorts of data.  
27 - ** (1.2) How requests are handled.  
28 - ** (1.3) What web pages are made of.  
29 - ** (1.4) Actions.  
30 - ** (1.5) States.  
31 -  
32 - * (2) Carrying on.  
33 - ** (2.1) Describing your web sites.  
34 - ** (2.2) Directories on the server's disk.  
35 - ** (2.3) Starting your web sites.  
36 -  
37 - * (3) The HTML interface.  
38 - ** (3.1) Types used by the HTML interface.  
39 - ** (3.2) ``in form'' versus ``off form''.  
40 - ** (3.3) Defining your own style.  
41 - ** (3.4) Actioners and forms.  
42 - ** (3.5) Local popup.  
43 -  
44 - ---------------------------------------------------------------------------------------  
45 -  
46 -  
47 -read tools/basis.anubis  
48 -read tools/printable_tree.anubis  
49 -read system/string.anubis  
50 -read system/logger.anubis  
51 -read CXM_common.anubis  
52 -read CXM_multihost_http_server.anubis  
53 -read web/mime.anubis  
54 -read CXM_cookies.anubis  
55 -  
56 -  
57 - * (1) Structure of a web site.  
58 -  
59 - First of all we need to explain what a web site should be made of. Ideally, the  
60 - visitor (also called the 'client') should see the web site working as any other  
61 - interactive computer software. So, it should be clear that a 'session' (i.e. a visit  
62 - to the web site, including the consultation of several pages) is some kind of  
63 - conversation between the visitor and the web site, and that the web site should  
64 - maintain a 'current state' of this conversation. At each new request (click) from the  
65 - visitor, this state must be updated. This whole conversation is called a 'session' and  
66 - should not be confused with a single request.  
67 -  
68 -  
69 -  
70 - ** (1.1) Three sorts of data.  
71 -  
72 - All the data needed for putting a web site at work may be dispatched into three  
73 - categories:  
74 -  
75 - 1. Constant data (data that never change). These data may be hard coded into the  
76 - Anubis source files of the web site.  
77 -  
78 - 2. Permanent data (data which always exist independantly of the users connected to  
79 - the web site). These data are normally recorded into data bases.  
80 -  
81 - 3. Session data (data which depend on a particular visitor and which exist only  
82 - during the time he visits the web site). These data are stored into so-called  
83 - 'states'.  
84 -  
85 -  
86 - It is important to determine which data belongs to which category. This is part of your  
87 - design decisions.  
88 -  
89 -  
90 -  
91 - ** (1.2) How requests are handled.  
92 -  
93 - We want to separate the following two functionalities (which are used at each request  
94 - (click) during a single session):  
95 -  
96 - - computing the new state from the previous state and from the client request, and  
97 - updating the data base,  
98 -  
99 - - computing the page to be sent to the client from the new current state and from  
100 - the informations in the data base.  
101 -  
102 -  
103 - The next picture shows the structure we have in mind:  
104 -  
105 -  
106 - request +---------+ HTML page (with a hidden state name)  
107 - .-------------------| client |<--------------.  
108 - | .-----------------| | |  
109 - | | previous state +---------+ |  
110 - | | name (if any) |  
111 - | | | client side  
112 - ............................................................................  
113 - | | | server side  
114 - | | |  
115 - | | .-------------------. |  
116 - | | | previous state | |  
117 - V V V | |  
118 - +---------------+ +---------------+ +--------------+  
119 - | compute state | | server's disk | | compute page |  
120 - +---------------+ +---------------+ +--------------+  
121 - ^ | | ^ ^ ^ ^ ^  
122 - | | | | | | | |  
123 - | | `--------------------+--------------------' | |  
124 - | | new state | | |  
125 - read | `------------------------+--------------------' |  
126 - write | new state name |  
127 - update V |  
128 - +-----------+ |  
129 - | data base |--------------------------------------------'  
130 - +-----------+ read only  
131 -  
132 -  
133 - When the client begins a session, there is no previous state. In this case, a default  
134 - 'initial state' is used instead.  
135 -  
136 - The data base may be updated by 'compute state' box, but should not be update by the  
137 - 'compute page' box. The 'compute page' box should be allowed only to read the data  
138 - base.  
139 -  
140 - In this file, all the above stuff is defined, except the 'compute state' and 'compute  
141 - page' boxes. You just have to provide the function for computing a new state (compute  
142 - state) and the function for computing the page (compute page) from the new state. You  
143 - don't have to worry about state names, saving and retrieving states and the like.  
144 -  
145 -  
146 -  
147 -  
148 -  
149 - ** (1.3) What web pages are made of.  
150 -  
151 - What the client can see in his browser's window may be called a 'page'. Within a page,  
152 - we have several sorts of components:  
153 -  
154 - - 'local' components, i.e. all components which do not open a connection, like  
155 - texts, images, etc... possibly using JavaScript programmation,  
156 -  
157 - - 'actioners', which, when clicked upon, open a connection with our web site; they  
158 - may appear as links or buttons, etc...  
159 -  
160 - - 'foreign links', which when clicked upon, open a connection with another web site  
161 - (or ours eventually).  
162 -  
163 - Of course, what an actioner does is just ask our web site to perform an action. To that  
164 - end, the actioner essentially sends the name of the action to be performed. However, it  
165 - may be necessary to provide additional informations which may be seen as 'operands' of  
166 - the action. In order to attach operands to an action, HTML provides the notion of  
167 - 'form'. Indeed, a form contains essentially a set of input fields into which the client  
168 - may put values for the required operands of the action, and a submit button, which is  
169 - the actioner itself. Notice that a single form may contain several submit buttons,  
170 - which simply means that there are several distincts actions taking the same set of  
171 - operands.  
172 -  
173 - Restrictions must be put on the use of all theses gadgets. Indeed, for example,  
174 - putting a form within another form is officially meaningless in HTML, and the client's  
175 - browser may be seriously disturbed by this. In this file, we propose an interface to  
176 - the HTML language, which forbids such meaningless things, simply by imposing a strict  
177 - typing of HTML concepts.  
178 -  
179 - Each web site may be accessible through two communication channels:  
180 -  
181 - - a non secured channel (HTTP),  
182 - - a secured channel (HTTPS).  
183 -  
184 - Nevertheless, the whole thing should be considered as a single web site. For example,  
185 - you may have a secured page, obtained through HTTPS, containing public images obtained  
186 - through HTTP. An actioner in a non secured page may open a secured connection, and  
187 - conversely.  
188 -  
189 - Summarizing, a web page is made of local elements, foreign links and actioners.  
190 - Actioners receive operands from forms, and they also choose to communicate through the  
191 - non secured or through the secured channel.  
192 -  
193 -  
194 -  
195 - +-------------------+  
196 - | page |  
197 - | | +---------------+  
198 - | +--------------+ | | next page |  
199 - | | form | | | (non secured) |  
200 - | | +----------+ | | HTTP | |  
201 - | | | actioner |---------------------------->| |  
202 - | | +----------+ | | +---------------+  
203 - | | | |  
204 - | | +----------+ | | +---------------+  
205 - | | | actioner |---------------------------->| next page |  
206 - | | +----------+ | | HTTPS | (secured) |  
207 - | | | | | |  
208 - | +--------------+ | | |  
209 - | | +---------------+  
210 - | |  
211 - +-------------------+  
212 -  
213 -  
214 - Notice that actioners need no be necessarily put into forms. In that case, they work as  
215 - ordinary links, but they still may receive operands as we shall see.  
216 -  
217 -  
218 -  
219 -  
220 - ** (1.4) Actions.  
221 -  
222 - The client opens a new connection with our web site whenever he clicks on an  
223 - actioner. The result is that a request is sent, essentially made of a list of 'web  
224 - arguments'. Each web argument is a pair (name,value). One of these web arguments, the  
225 - 'action' web argument (whose name is "a"), determines the action to be performed. The  
226 - other web arguments (not including "s", used to identify the state) are the operands  
227 - for this action.  
228 -  
229 - Hence, the 'compute state' box in the picture above, splits naturally into as many  
230 - sub-boxes as there are actions. For this reason, we define the following type for  
231 - representing actions (where '$State' is the type representing session informations):  
232 -  
233 -public type Web_Action($State):  
234 - http_action (String name, // name of action  
235 - ($State) -> Bool allow, // true if action allowed  
236 - (HTTP_Info http_info,  
237 - List(Web_arg) web_args, // actually only 'operands' web arguments  
238 - $State state) -> $State do_it),  
239 - https_action (String name, // name of action  
240 - ($State) -> Bool allow, // true if action allowed  
241 - (HTTP_Info http_info,  
242 - List(Web_arg) web_args, // actually only 'operands' web arguments  
243 - $State state) -> $State do_it),  
244 - http_https_action (String name,  
245 - ($State) -> Bool allow,  
246 - (HTTP_Info http_info,  
247 - List(Web_arg) web_args,  
248 - $State state) -> $State do_it).  
249 -  
250 - 'http_action's are executed only under HTTP, and 'https_action's are executed only  
251 - under HTTPS. 'http_https_action's may be executed under both types of connections.  
252 -  
253 - Each action has a name, which is used to identify the action. Each action also has a  
254 - function 'allow' whose job is to verify that the action is allowed in the current  
255 - state, and a function 'do_it' for performing the action. The function 'do_it' receives  
256 - a lot of informations:  
257 -  
258 - - 'HTTP informations':  
259 - - the IP address of the client,  
260 - - the URI requested by the client (after redirection),  
261 - - the list of HTTP headers generated by the client's browser,  
262 - - the list of web arguments sent by the client (except "s" and "a"),  
263 - - the previous state (or the 'initial' or 'ticket expired' state if no previous  
264 - state can be found).  
265 -  
266 - In most cases, HTTP informations are not used. This is the reason why they are gathered  
267 - for simplicity into a unique datum of type 'HTTP_Info'.  
268 -  
269 -// For your convenience, we introduce the following simpler variants:  
270 -//  
271 -//public define Web_Action($State)  
272 -// http_action  
273 -// (  
274 -// String name,  
275 -// $State -> Bool allow,  
276 -// (List(Web_arg),$State) -> $State do_it  
277 -// ) =  
278 -// http_action(name,  
279 -// (Maybe($State) ms) |-> if ms is  
280 -// {  
281 -// failure then true,  
282 -// success(s) then allow(s)  
283 -// },  
284 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
285 -// {  
286 -// failure then (failure, []),  
287 -// success(s2) then (success(do_it(l,s2)), [])  
288 -// }).  
289 -//  
290 -//public define Web_Action($State)  
291 -// https_action  
292 -// (  
293 -// String name,  
294 -// $State -> Bool allow,  
295 -// (List(Web_arg),$State) -> $State do_it  
296 -// ) =  
297 -// https_action(name,  
298 -// (Maybe($State) ms) |-> if ms is  
299 -// {  
300 -// failure then true,  
301 -// success(s) then allow(s)  
302 -// },  
303 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
304 -// {  
305 -// failure then (failure, []),  
306 -// success(s2) then (success(do_it(l,s2)), [])  
307 -// }).  
308 -//  
309 -//public define Web_Action($State)  
310 -// http_https_action  
311 -// (  
312 -// String name,  
313 -// $State -> Bool allow,  
314 -// (List(Web_arg),$State) -> $State do_it  
315 -// ) =  
316 -// http_https_action(name,  
317 -// (Maybe($State) ms) |-> if ms is  
318 -// {  
319 -// failure then true,  
320 -// success(s) then allow(s)  
321 -// },  
322 -// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is  
323 -// {  
324 -// failure then (failure, []),  
325 -// success(s2) then (success(do_it(l,s2)), [])  
326 -// }).  
327 -  
328 -  
329 -  
330 - When you define your web site, you must provide the list of all the actions of the  
331 - site. When a new state has been computed, a graphical representation of this state  
332 - must be sent to the client. To that end, you must provide a function (named below  
333 - 'compute_page') of type:  
334 -  
335 - $State -> HTTP_Answer  
336 -  
337 - where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML  
338 - pages.  
339 -  
340 -public type HTTP_Answer:...  
341 -  
342 - It should be clear that states and pages are deeply linked together. Indeed, we really  
343 - understand the page shown to the client as a representation of the current state of the  
344 - conversation between the client and the web site, but also containing informations  
345 - taken from the data bases.  
346 -  
347 -  
348 -  
349 -  
350 -  
351 - ** (1.5) States.  
352 -  
353 - Now, we explain how you can define the type (say 'State') to be used as an instance of  
354 - the type parameter '$State'. The following is just a suggestion.  
355 -  
356 - Each state determines a page (since 'compute_page' computes a page from a  
357 - state). However, some components of the state may be independant of the page. It may be  
358 - the case for example for the indication of the natural language used by the  
359 - client. Hence, a state should be made of (at least) two parts:  
360 -  
361 - - informations which are the same for all pages,  
362 - - informations which are particular to each page.  
363 -  
364 - For example, you could define:  
365 -  
366 - type Page: // one alternative per page, with particular informations  
367 - login(...), // in the components  
368 - main_page(...),  
369 - ...etc...  
370 -  
371 - Now, the type 'State' could be defined as follows:  
372 -  
373 - type State:  
374 - state(Language, // informations valid for all pages  
375 - ...,  
376 - Page). // informations particular to a page  
377 -  
378 - However, if you are making a secured web site within which clients should be identified  
379 - (by id and password), it may be a good idea to have two sorts of states, one for non  
380 - identified clients and one for identified clients. In this case, define the type  
381 - 'State' as follows (this is just a suggestion):  
382 -  
383 - type State:  
384 - non_identified(Language),  
385 - identified(String id,  
386 - Language,  
387 - Page).  
388 -  
389 - When a request arrives, check if the previous state is 'identified(...)' or  
390 - 'non_identified(...)', and don't provide access to certain pages to non identified  
391 - clients. This is required for security.  
392 -  
393 - Some more words on security. If your site needs to identify clients, define the  
394 - initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and  
395 - password of the client. If the id and password are correct, then change the state of  
396 - the client to 'identified(...)'. No other action should be able to do that. Now, be  
397 - confident that clients cannot forge states. The only information they have is the name  
398 - of a state, not the state itself which is never sent over the network, but only stored  
399 - on the server's disk. The name of the state is constructed using strong cryptographical  
400 - methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even  
401 - state names cannot be seen by a third party. So, if the system retrieves a previous  
402 - state of the form 'identified(...)', you can be confident that your client is well  
403 - identified, and you can send him confidential informations.  
404 -  
405 - States have a limited life time. It may happen that a client clicks on a button at a  
406 - time its state is out of date. In this case, this system considers that the new state  
407 - is a special state named 'ticket expired'. You must provide a function producing this  
408 - state when you describe your web site. The page corresponding to this state must just  
409 - inform the client that he/she waited a too long time before clicking on a button, and  
410 - has to restart (a new conversation) from the begining.  
411 -  
412 -  
413 -  
414 - * (2) Carrying on.  
415 -  
416 - ** (2.1) Describing your web sites.  
417 -  
418 - Before you may start your web site, you must describe it, i.e. produce a datum of the  
419 - opaque type 'Web_Site'.  
420 -  
421 -public type Web_Site:...  
422 -  
423 - Producing such a datum may be performed by:  
424 -  
425 -public define Web_Site  
426 - make_web_site_description  
427 - (  
428 - List(String) common_names, // for example: ["www.our-business.com",  
429 - // "192.168.0.1"]  
430 - // the second one is just for testing  
431 - String site_directory, // where 'public' and other directories are  
432 - // located (should NOT end with '/')  
433 - String state_directory,  
434 - One -> One init,  
435 - (HTTP_Info,  
436 - List(Web_arg),  
437 - Bool is_https) -> $State initial_state,  
438 - ($State expired,  
439 - Maybe(String),  
440 - HTTP_Info,  
441 - List(Web_arg),  
442 - Bool is_https) -> $State ticket_expired_state,  
443 - (Maybe(String),  
444 - HTTP_Info,  
445 - List(Web_arg),  
446 - Bool is_https) -> $State ticket_lost_state,  
447 - List(Web_Action($State)) actions,  
448 - $State -> HTTP_Answer compute_page,  
449 - $State -> List(HTTP_header) additional_headers,  
450 - Int timeout, // seconds (todo: minutes)  
451 - Redirections redirections,  
452 - String charset,  
453 - List(String) journal_extensions,  
454 - List(String) journal_headers,  
455 - String authorization_secret,  
456 - List(MIME) known_mime_types,  
457 - (String action_name,  
458 - List(Web_arg) args)-> One before_send_file  
459 - ).  
460 -  
461 -  
462 - Explanations:  
463 -  
464 - 'common_names' is the list of names of the site (the name the browser must send as the  
465 - value of the 'Host' HTTP header in order to access the site must be in that list). Such  
466 - a name generally looks like this:  
467 -  
468 - www.somewhere.com  
469 -  
470 - If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of  
471 - the site must be exactly the same as the name on the certificate (which is precisely  
472 - called the 'common name' in the X.509 jargon). If the two names do not match, the site  
473 - will still work, but the transaction will not be transparent to the client. His browser  
474 - will complain that the name of the certificate does not match the name of the site, and  
475 - he will have to accept the certificate manually.  
476 -  
477 - 'site_directory' is the absolute path to the directory where the files needed by the  
478 - site are located. Usually this directory looks like:  
479 -  
480 - my_anubis/web_sites/www.somewhere.com  
481 -  
482 - However, this information is not computed from 'common_name', so that you can change  
483 - the common name (for example temporarily, for networking reasons) without loosing  
484 - access to the files.  
485 -  
486 - 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state  
487 - whose graphical representation is a page explaining to the user that its 'ticket' (or  
488 - 'session information') has expired, and that he/she must close all popup windows and  
489 - start a new session. The arguments of the function contain the previous (expired)  
490 - state and all current informations concerning the user. This arguments may be useful  
491 - for example for producing the expiration message in the language chosen by the user.  
492 - You can also (and this may be much smarter) send a 'ticket prolongation page'  
493 - (including a new login for example), and resume the same conversation, since you have  
494 - all the pertinent informations at hand. In the case the ticket is definitely lost, the  
495 - second fonction 'ticket_lost_state' is used.  
496 -  
497 - Notice that despite the fact that the parameter $State is involved in the arguments of  
498 - the above function, the type 'Web_Site' does not depend on this parameter. This allows  
499 - to produce lists of web site descriptions, where each description may be constructed  
500 - with a different instance of $State. This is required because distinct sites must have  
501 - distinct types of session informations. This is made possible by the fact that the  
502 - type is obscure, and the constructor replaced by a function which assembles  
503 - 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single  
504 - entity not depending on $State. You should have a look to the private part of this file  
505 - if you want more precisions about this programming technique.  
506 -  
507 - 'charset' is a string which will determine the character encoding to be used by the  
508 - browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",  
509 - etc...  
510 -  
511 - 'before_send_file' is a function which is executed just before the HTTP server sends a  
512 - file. It gets an action name and the web arguments received with the request for that  
513 - file. Notice that this action name and these web arguments may be put into a  
514 - 'private_download' element, and will come back to the server at the time of the  
515 - download.  
516 -  
517 -  
518 -  
519 - ** (2.2) Directories on the server's disk.  
520 -  
521 - The description of your site contains the name of the directory within which the  
522 - required files are located. This may be for example:  
523 -  
524 - my_anubis/web_sites/www.our-business.com/  
525 -  
526 - This is called the 'site directory' (for the given site). Within the site directory,  
527 - the following directories are created by this program:  
528 -  
529 - states  
530 - public  
531 - journal  
532 - private_download  
533 - upload_temporary  
534 -  
535 - The directory 'states' is used for storing states (session informations). Out of date  
536 - states are automatically removed after some time.  
537 -  
538 - The tree rooted at 'public' contains files that the server is allowed to send to the  
539 - clients. For security reasons, the server never sends a file which is not within the  
540 - tree whose root is this 'public' directory (except for the 'private download' mecanism;  
541 - see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis')  
542 - must have been recognized before the file may be sent.  
543 -  
544 - The directory 'journal' contains the jounal files. The roles of the remaining  
545 - directories 'private_download' and 'upload_temporary' is explained in  
546 - 'multihost_http_server.anubis', where you will also find further informations on  
547 - 'public' and 'journal'.  
548 -  
549 -  
550 -  
551 -  
552 - ** (2.3) Web servers parameters.  
553 -  
554 - The web servers have several parameters useful for administration. They are described  
555 - as follows:  
556 -  
557 - public type WebServersParameters:  
558 - wsparms(Var(Bool) shutdown_required,  
559 -  
560 -  
561 -  
562 -  
563 - ** (2.4) Starting your web sites.  
564 -  
565 - When you have described all your web sites (you may want to have several web sites, and  
566 - they are distinguished by their 'common name'), you may start them all together using  
567 - 'start_web_sites' below. This function returns a result of the following type:  
568 -  
569 -public type Start_Web_Sites_Result:  
570 - cannot_bind_to_port(Word32),  
571 - cannot_bind_to_port(Word32,Word32),  
572 - ok(Server http_server,  
573 - Server https_server).  
574 -  
575 - Indeed, it may happen that the system cannot bind (begin to listen) to one of the two  
576 - ports (or to both). The main reason is that another server is already listening on that  
577 - port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that  
578 - the 's' bit has not been set for 'user' and 'group' (there is not such problem under  
579 - Windows). Also notice that the Linux kernel may need a rather long time (up to several  
580 - minutes) before liberating a listening port. Now, if the system can bind to the two  
581 - ports, the pair of the two servers is returned. Two tools are useful for manipulating  
582 - servers:  
583 -  
584 - shutdown of type Server -> One  
585 - is_down of type Server -> Bool  
586 -  
587 - They are defined in 'predefined.anubis' (together with the type 'Server').  
588 -  
589 -  
590 -public define Start_Web_Sites_Result  
591 - start_web_sites  
592 - (  
593 - Word32 ip_address, // the IP address shared by the web sites  
594 - Word32 http_port, // usually: 80  
595 - Word32 https_port, // usually: 443  
596 - String ssl_certificate_common_name,  
597 - List(Web_Site) web_sites, // web sites to be started  
598 - (One) -> Bool shutdown_required  
599 - ).  
600 -  
601 - 'ip_address' is the IP address on which the two servers listen. If you put 0, the  
602 - servers listen on all the IP addresses of the machine. This may be useful if the  
603 - machine has several network interfaces.  
604 -  
605 - 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec'  
606 - loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server  
607 - certificate. This is due to a problem of conception of SSL itself. See the book 'SSL  
608 - and TLS' by Eric Rescorla (at Addison Wesley) for more explanations.  
609 -  
610 - Notice that the number of servers is always 2, regardless of the number of web sites  
611 - you are starting.  
612 -  
613 - The dynamic variable 'shutdown_required' may be used to control the shutdown of the two  
614 - servers from within the web site (typically the administration part). The servers will  
615 - shutdown as soon as this variable contains 'true'. So you must provide a variable  
616 - containing 'false' otherwise your servers will not run. You may also use the primitive  
617 - 'must_restart' (see 'predefined.anubis') to control the restarting of your servers.  
618 -  
619 -  
620 -  
621 -  
622 -  
623 -  
624 - * (3) The HTML interface.  
625 -  
626 - We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination  
627 - of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more  
628 - reactive and attractive on the client side.  
629 -  
630 -  
631 - ** (3.1) Types used by the HTML interface.  
632 -  
633 - For easy reference, we gather below the definitions of all the types used by the HTML  
634 - interface, and we comment them immediately.  
635 -  
636 -  
637 -public type HTML_Size:  
638 - absolute(Int), // in pixels  
639 - percentage(Int).  
640 -  
641 -  
642 -public type Text_Option:  
643 - size(Int), // size of character font to use  
644 - font(String), // name of character font to use (such as "helvetica",...)  
645 - color(RGB), // color to be used for characters  
646 - italic,  
647 - oblique,  
648 - small_capitals,  
649 - bold,  
650 - underlined,  
651 - left_justified,  
652 - right_justified,  
653 - justified, // justified on both sides  
654 - line_through,  
655 - nowrap,  
656 - class(String), //CSS class  
657 - id(String),  
658 - style(String),  
659 - title(String),  
660 - attr(String, String).  
661 -  
662 -public define Text_Option  
663 - tooltip(String s) = title(s).  
664 -  
665 - A list of 'Text_Option' must be given with each text you want to put in your page.  
666 -  
667 - This indicate the way of reading text.  
668 -public type Reading_Way:  
669 - ltr, //the text is readable from "Left To Right" like english  
670 - rtl. //the text is readable from "Right To Left" like arabic  
671 -  
672 -  
673 -// Following types are define to prohib any arguments order error  
674 -  
675 -/**  
676 - * String value for 'id' attribut  
677 - */  
678 -public type HtmlId:  
679 - htmlId(String id).  
680 -  
681 -/**  
682 - * String value for 'class' attribut  
683 - */  
684 -public type HtmlClass:  
685 - htmlClass(String class).  
686 -  
687 -/**  
688 - * Name used in arguments list when form is submitted.  
689 - */  
690 -public type WebArgName:  
691 - wan(String name).  
692 -  
693 -/**  
694 - * Value passed to arguments list when form is submitted (for RadioButton and CheckBox).  
695 - */  
696 -public type WebArgValue:  
697 - wav(String value).  
698 -  
699 -/**  
700 - * Initial value of an input field.  
701 - */  
702 -public type InitialValue:  
703 - init(String value).  
704 -  
705 -public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y).  
706 -public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y).  
707 -public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y).  
708 -public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y).  
709 -public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y).  
710 -  
711 -  
712 -public type HtmlEvents:  
713 - // Form element events  
714 - onchange,  
715 - onsubmit,  
716 - onreset,  
717 - onselect,  
718 - onblur,  
719 - onfocus,  
720 - // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)  
721 - onkeydown,  
722 - onkeypress,  
723 - onkeyup,  
724 - // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)  
725 - onclick,  
726 - ondblclick,  
727 - onmousedown,  
728 - onmousemove,  
729 - onmouseout,  
730 - onmouseover,  
731 - onmouseup.  
732 -  
733 -public type CoreAttrs:  
734 - id (String),  
735 - class (String),  
736 - style (String),  
737 - title (String),  
738 - lang (String),  
739 - dir (Reading_Way),  
740 - accesskey (Word8),  
741 - tabindex (Int),  
742 - attr (String, String),  
743 - event (HtmlEvents, String).  
744 -  
745 -public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").  
746 -  
747 -public type InputAttrs:  
748 - class (String),  
749 - style (String),  
750 - title (String),  
751 - lang (String),  
752 - dir (Reading_Way),  
753 - accesskey (Word8),  
754 - tabindex (Int),  
755 - attr (String, String),  
756 - event (HtmlEvents, String).  
757 -  
758 -public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").  
759 -  
760 -public define CoreAttrs  
761 - tooltip(String s) = title(s).  
762 -public define InputAttrs  
763 - tooltip(String s) = title(s).  
764 -  
765 -public type I18n:  
766 - lang (String),  
767 - dir (Reading_Way).  
768 -  
769 -//public type DIV_Option:  
770 -// id (String),  
771 -// class (String),  
772 -// style (String),  
773 -// tooltip (String),  
774 -// lang (String),  
775 -// dir (Reading_Way),  
776 -// attr (String, String),  
777 -// event (HtmlEvents, String).  
778 -//  
779 -  
780 - A list of 'DIV_Option' must be given with each DIV you want to put in your page.  
781 -  
782 -define String event_name  
783 - (  
784 - HtmlEvents e  
785 - ) =  
786 - if e is  
787 - {  
788 - // Form element events  
789 - onchange then "onchange",  
790 - onsubmit then "onsubmit",  
791 - onreset then "onreset",  
792 - onselect then "onselect",  
793 - onblur then "onblur",  
794 - onfocus then "onfocus",  
795 - // Keyboard events  
796 - onkeydown then "onkeydown",  
797 - onkeypress then "onkeypress",  
798 - onkeyup then "onkeyup",  
799 - // Mouse events  
800 - onclick then "onclick",  
801 - ondblclick then "ondblclick",  
802 - onmousedown then "onmousedown",  
803 - onmousemove then "onmousemove",  
804 - onmouseout then "onmouseout",  
805 - onmouseover then "onmouseover",  
806 - onmouseup then "onmouseup"  
807 - }.  
808 -  
809 -public type Table_Option:  
810 - background_color(RGB), // applied to all cells in the table  
811 - background_image(String url),  
812 - border(Int width_of_outer_edge, // if not present, all values are 0  
813 - Int width_of_top_of_relief,  
814 - Int width_of_inner_edge,  
815 - RGB border_color),  
816 - width(Int), // sets a minimal width for the table  
817 - percentage_width(Int),  
818 - attr(String name, String value),  
819 - class(String class_name).  
820 -  
821 -  
822 -public define Table_Option nude = border(0,0,0,rgb(0,0,0)).  
823 -  
824 -  
825 - A list of 'Table_Option' must be given with each table.  
826 -  
827 -  
828 -public type BackgroundOption:  
829 - repeat, // repeat the background in both directions  
830 - repeat_horizontal, // repeat the background only horizontally  
831 - repeat_vertical, // repeat the background only verticall  
832 - no_repeat, // don't repeat the background  
833 - center.  
834 -  
835 -  
836 -public type Cell_Option:  
837 - core_attrs(List(CoreAttrs)),  
838 - left, // put the content of the cell on the left  
839 - h_center, // center the content of the cell horizontally  
840 - right, // put the content of the cell on the right  
841 - top, // put the content of the cell upwards  
842 - v_center, // center the content of tye cell vertically,  
843 - bottom, // put the content of the cell downwards  
844 - base_line, // align the content vertically according to base lines  
845 - background_color(RGB),  
846 - background_image(String url, BackgroundOption),  
847 - width(Int), // sets a minimal width for the cell  
848 - percentage_width(Int),  
849 - height(Int), // sets a minimal height for the cell  
850 - columns(Int), // lets the cell span over several columns  
851 - rows(Int), // lets the cell span over several rows  
852 - nowrap, // do not allow text wrapping within the cell  
853 - class(String class_name).  
854 -  
855 - A list of 'Cell_Option' must be given with each cell and each row in a table. Options  
856 - given with a row apply to all the cells in the row, but are superseded by options given  
857 - with cells, which apply only to the cell they are given with.  
858 -  
859 -  
860 -public type HTML_Cell($T):  
861 - cell(List(Cell_Option) options, $T content).  
862 -  
863 -public type HTML_Header_Cell($T):  
864 - header_cell(List(Cell_Option) options, $T content).  
865 -  
866 - The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form',  
867 - depending on where you put your table (within a form or not within a form). For your  
868 - convenience, we define the following particular case:  
869 -  
870 -public define HTML_Cell($T)  
871 - cell  
872 - (  
873 - $T content  
874 - ) =  
875 - cell([],content).  
876 -  
877 -public define HTML_Header_Cell($T)  
878 - header_cell  
879 - (  
880 - $T content  
881 - ) =  
882 - header_cell([],content).  
883 -  
884 -  
885 -public type HTML_Row($T):  
886 - row(List(Cell_Option) options, List(HTML_Cell($T)) cells).  
887 -  
888 -public type HTML_Header_Row($T):  
889 - empty,  
890 - header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells).  
891 -  
892 -public type HTML_Footer_Row($T):  
893 - empty,  
894 - footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells).  
895 -  
896 - Same remark as for 'HTML_Cell($T)'. We define several convenience functions:  
897 -  
898 -public define HTML_Row($T)  
899 - row  
900 - (  
901 - List(HTML_Cell($T)) cells  
902 - ) =  
903 - row([],cells).  
904 -  
905 -public define HTML_Row($T)  
906 - row  
907 - (  
908 - HTML_Cell($T) cell  
909 - ) =  
910 - row([],[cell]).  
911 -  
912 -public define HTML_Header_Row($T)  
913 - header_row  
914 - (  
915 - List(HTML_Header_Cell($T)) cells  
916 - ) =  
917 - header_row([],cells).  
918 -  
919 -public define HTML_Header_Row($T)  
920 - header_row  
921 - (  
922 - HTML_Header_Cell($T) cell  
923 - ) =  
924 - header_row([],[cell]).  
925 -  
926 -public type Actioner_Connection:  
927 - same, // use same type of connection as current page  
928 - http, // use non secured connection  
929 - https. // use secured connection  
930 -  
931 -public type Other_Window_Option:  
932 - resizable, // the new window may be resized by the client  
933 - scrollbars, // the new window has scrollbars  
934 - width(Int), // the new window has the specified width  
935 - height(Int). // the new window has the specified height  
936 -  
937 -public type Actioner_Target:  
938 - same,  
939 - same (String label),  
940 - other(String window_name, List(Other_Window_Option)).  
941 -  
942 -public type Actioner_Aspect:  
943 - link (List(Text_Option), String text, Maybe(String) name),// hypertext link  
944 - img_link (String img_url, String alt_text),  
945 - push_button (List(CoreAttrs),String text),  
946 - button (String url_off, String url_on), // rollover button  
947 - button (String url_off, String url_on, Int w, Int h), // idem with size  
948 - submit (List(CoreAttrs),String text),  
949 - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices),  
950 - immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected).  
951 -  
952 -  
953 -  
954 -public type Actioner_Local_Action:  
955 - close_window.  
956 -  
957 -  
958 -public define Actioner_Aspect  
959 - link  
960 - (  
961 - List(Text_Option) options,  
962 - String text  
963 - ) =  
964 - link(options, text, failure).  
965 -  
966 -public define Actioner_Aspect  
967 - link  
968 - (  
969 - String text  
970 - ) =  
971 - link([], text, failure).  
972 -  
973 -  
974 -public define Actioner_Aspect  
975 - link  
976 - (  
977 - List(Text_Option) options,  
978 - Int i  
979 - ) =  
980 - link(options,to_decimal(i), failure).  
981 -  
982 -public define Actioner_Aspect  
983 - link  
984 - (  
985 - Int i  
986 - ) =  
987 - link([], i).  
988 -  
989 -public define Actioner_Aspect  
990 - button  
991 - (  
992 - String url_img  
993 - ) =  
994 - button(url_img,url_img).  
995 -  
996 - Actioners are explained in details below.  
997 -  
998 -  
999 -public type TextAreaOption:  
1000 - input_attrs(List(InputAttrs)),  
1001 - disabled,  
1002 - read_only,  
1003 - wrap_lines.  
1004 -  
1005 -public type CSS_Style:  
1006 - text_options(List(Text_Option)).  
1007 -  
1008 -public type CSS_File:  
1009 - css_file(String file_name).  
1010 -  
1011 -public type JS_Attribute:  
1012 - attr (String, String).  
1013 -  
1014 -public type JS_File:  
1015 - js_file(String file_name,  
1016 - List(JS_Attribute) attributes).  
1017 -  
1018 -public type Script:  
1019 - script( String script_type,  
1020 - String content).  
1021 -  
1022 -public define JS_File  
1023 - js_file  
1024 - (  
1025 - String file_name  
1026 - ) =  
1027 - js_file(file_name, []).  
1028 -  
1029 -public type HTML_Meta:...  
1030 -  
1031 -public type HTML_Off_Form:...  
1032 -  
1033 -public type HTML_Head_Tag:  
1034 - meta(HTML_Meta),  
1035 - title(String),  
1036 - js(JS_File),  
1037 - js_inline(Script),  
1038 - css(CSS_File),  
1039 - css_inline(String css_styles) /* Note: <style> and </style> tags are not necessaries */  
1040 - .  
1041 -  
1042 - /* It contains  
1043 - * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ...  
1044 - * - a HTML_Off_Form representing the HTML code for the part of the page we want to display  
1045 - */  
1046 -public type HTML_Partial_Content:  
1047 - partial_content  
1048 - (  
1049 - List(HTML_Head_Tag),  
1050 - HTML_Off_Form  
1051 - )  
1052 - .  
1053 -  
1054 -public define List(HTML_Head_Tag)  
1055 - to_HTML_Head_Tag  
1056 - (  
1057 - List(CSS_File) css_file_list  
1058 - )=  
1059 - map((CSS_File css_f) |-> css(css_f), css_file_list).  
1060 -  
1061 -public define List(HTML_Head_Tag)  
1062 - to_HTML_Head_Tag  
1063 - (  
1064 - List(JS_File) js_file_list  
1065 - )=  
1066 - map((JS_File js_f) |-> js(js_f), js_file_list).  
1067 -  
1068 -public type HTML_In_Form:  
1069 - literal_pt (Printable_tree),  
1070 - literal (String),  
1071 - sequence (List(HTML_In_Form) items),  
1072 - text (List(Text_Option), String the_text),  
1073 - preformated (List(Text_Option), String),  
1074 - paragraph (List(Text_Option), HTML_In_Form content),  
1075 - image (List(CoreAttrs), String url, String alternate),  
1076 - image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
1077 - table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)),  
1078 - center (HTML_In_Form),  
1079 - mail_to (String email, HTML_In_Form element),  
1080 - scroller (Int width, Int height,  
1081 - Int content_width, Int content_height,  
1082 - HTML_In_Form content),  
1083 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1084 - String action_name, List((String,String)) extra_ops,  
1085 - List(Actioner_Local_Action)),  
1086 - foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
1087 - foreign_link (List(Text_Option), String url),  
1088 - foreign_link (List(Text_Option), String url, String name),  
1089 - private_download (String abs_path, String name, String extra_ext,  
1090 - Maybe((String,List((String,String)))) action),  
1091 - text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1092 - text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1093 - password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),  
1094 - text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height),  
1095 - file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width),  
1096 - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices),  
1097 - selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected),  
1098 - // List((String,String)) = List((code,name)) where :  
1099 - // code is the web-arg value  
1100 - // name appears in selector  
1101 - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices),  
1102 - selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected),  
1103 - radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1104 - radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1105 - check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1106 - check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),  
1107 - div (List(CoreAttrs), HTML_In_Form content),  
1108 - div_empty (List(CoreAttrs)),  
1109 - hidden (HtmlId id, WebArgName name, InitialValue init).  
1110 -  
1111 -  
1112 - 'HTML_In_Form' defines all the elements you may put within a form. We define a  
1113 - convenience function:  
1114 -  
1115 -public define HTML_In_Form literal(Printable_tree t) = literal_pt(t).  
1116 -  
1117 -public define HTML_In_Form image(String url) = image([], url, url).  
1118 -  
1119 -public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height).  
1120 -  
1121 -public define HTML_In_Form  
1122 - foreign_link  
1123 - (  
1124 - Int tsize,  
1125 - String url,  
1126 - String name  
1127 - ) =  
1128 - foreign_link([size(tsize)],url,name).  
1129 -  
1130 -public define HTML_In_Form  
1131 - actioner  
1132 - (  
1133 - Actioner_Connection conn,  
1134 - Actioner_Target targ,  
1135 - Actioner_Aspect asp,  
1136 - String action_name,  
1137 - List((String,String)) extra_ops  
1138 - ) =  
1139 - actioner(conn,targ,asp,action_name,extra_ops,[]).  
1140 -  
1141 -public define HTML_In_Form  
1142 - actioner  
1143 - (  
1144 - Actioner_Connection conn,  
1145 - Actioner_Target targ,  
1146 - Actioner_Aspect asp,  
1147 - ) =  
1148 - actioner(conn, targ, asp, "", [], []).  
1149 -  
1150 -  
1151 -public define HTML_In_Form  
1152 - text_area  
1153 - (  
1154 - WebArgName name,  
1155 - InitialValue init,  
1156 - Int width,  
1157 - Int height  
1158 - ) =  
1159 - text_area([], "", htmlId(""), name,init,width,height).  
1160 -  
1161 -public define HTML_In_Form  
1162 - text_area  
1163 - (  
1164 - List(TextAreaOption) options,  
1165 - WebArgName name,  
1166 - InitialValue init,  
1167 - Int width,  
1168 - Int height  
1169 - ) =  
1170 - text_area(options, "", htmlId(""), name,init,width,height).  
1171 -  
1172 -public define HTML_In_Form  
1173 - table  
1174 - (  
1175 - List(HTML_Row(HTML_In_Form)) rows  
1176 - ) =  
1177 - table([],empty,rows,empty).  
1178 -  
1179 -public define HTML_In_Form  
1180 - table  
1181 - (  
1182 - List(Table_Option) options,  
1183 - List(HTML_Row(HTML_In_Form)) rows  
1184 - ) =  
1185 - table(options,empty,rows,empty).  
1186 -  
1187 -public define HTML_In_Form  
1188 - table  
1189 - (  
1190 - HTML_Header_Row(HTML_In_Form) h_row,  
1191 - List(HTML_Row(HTML_In_Form)) rows  
1192 - ) =  
1193 - table([],h_row,rows,empty).  
1194 -  
1195 -public define HTML_In_Form  
1196 - table  
1197 - (  
1198 - List(Table_Option) options,  
1199 - HTML_Header_Row(HTML_In_Form) h_row,  
1200 - List(HTML_Row(HTML_In_Form)) rows  
1201 - ) =  
1202 - table(options,h_row,rows,empty).  
1203 -  
1204 -public define HTML_In_Form  
1205 - private_download  
1206 - (  
1207 - String abs_path,  
1208 - String name,  
1209 - String extra_ext  
1210 - ) =  
1211 - private_download(abs_path,name,extra_ext,failure).  
1212 -  
1213 -public define HTML_In_Form  
1214 - private_download  
1215 - (  
1216 - String abs_path,  
1217 - String name,  
1218 - String extra_ext,  
1219 - String action_name,  
1220 - List((String,String)) args  
1221 - ) =  
1222 - private_download(abs_path,name,extra_ext,success((action_name,args))).  
1223 -  
1224 -public define HTML_In_Form  
1225 - text  
1226 - (  
1227 - String s  
1228 - ) =  
1229 - text([],s).  
1230 -  
1231 -public define HTML_In_Form  
1232 - radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1233 - = radio_button (options, label_text, htmlId(n.name), n, value, checked).  
1234 -  
1235 -public define HTML_In_Form  
1236 - radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1237 - = radio_button_r (options, label_text, htmlId(n.name), n, value, checked).  
1238 -  
1239 -public define HTML_In_Form  
1240 - check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1241 - = check_box (options, label_text, htmlId(n.name), n, value, checked).  
1242 -  
1243 -public define HTML_In_Form  
1244 - check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)  
1245 - = check_box_r (options, label_text, htmlId(n.name), n, value, checked).  
1246 -  
1247 -public define HTML_In_Form  
1248 - file_upload (WebArgName name, Int width)  
1249 - = file_upload([], "", htmlId(""), name, width).  
1250 -  
1251 -public define HTML_In_Form  
1252 - hidden (WebArgName name, InitialValue init)  
1253 - = if name is wan(web_name) then  
1254 - hidden(htmlId(web_name), name, init).  
1255 -  
1256 -public type HTML_Body:...  
1257 -  
1258 -public type HTML_Off_Form:  
1259 - literal_pt (Printable_tree),  
1260 - literal (String),  
1261 - sequence (List(HTML_Off_Form) items),  
1262 - text (List(Text_Option), String the_text),  
1263 - preformated (List(Text_Option), String),  
1264 - paragraph (List(Text_Option), HTML_Off_Form content),  
1265 - image (List(CoreAttrs), String url, String alternate),  
1266 - image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
1267 - table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)),  
1268 - center (HTML_Off_Form),  
1269 - mail_to (String email, HTML_Off_Form element),  
1270 - scroller (Int width, Int height,  
1271 - Int content_width, Int content_height,  
1272 - HTML_Off_Form content),  
1273 - fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content),  
1274 - fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),  
1275 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1276 - String action_name, List((String,String)) extra_ops,  
1277 - List(Actioner_Local_Action)),  
1278 - actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,  
1279 - String action_name, List((String,String)) extra_ops,  
1280 - List(Actioner_Local_Action), String form_name),  
1281 - foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
1282 - foreign_link (List(Text_Option), String url),  
1283 - foreign_link (List(Text_Option), String url, String name),  
1284 - private_download (String abs_path, String name, String extra_ext,  
1285 - Maybe((String,List((String,String)))) action),  
1286 - label (String name),  
1287 - form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content),  
1288 - form (HtmlId form_id, List(CoreAttrs),  
1289 - String action_name, List((String,String)) extra_ops,  
1290 - HTML_In_Form content),  
1291 - div (List(CoreAttrs), HTML_Off_Form content),  
1292 - div_empty (List(CoreAttrs)),  
1293 - iframe (List(CoreAttrs),  
1294 - List(CSS_Style) /*styles*/,  
1295 - List(CSS_File) /*css_files*/,  
1296 - List(JS_File) /*js_files*/,  
1297 - HTML_Body /*body*/).  
1298 -  
1299 - 'HTML_Off_Form' defines all the elements you may put outside any form.  
1300 -  
1301 -  
1302 -public define HTML_Off_Form image(String url) = image([], url, url).  
1303 -  
1304 -public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height).  
1305 -  
1306 -public define HTML_Off_Form  
1307 - form  
1308 - (  
1309 - String form_name,  
1310 - List(CoreAttrs) options,  
1311 - HTML_In_Form content  
1312 - ) =  
1313 - form(htmlId(form_name), options, content).  
1314 -  
1315 -public define HTML_Off_Form  
1316 - form  
1317 - (  
1318 - String form_name,  
1319 - List(CoreAttrs) options,  
1320 - String action_name,  
1321 - List((String,String)) extra_ops,  
1322 - HTML_In_Form content  
1323 - ) =  
1324 - form(htmlId(form_name), options, action_name, extra_ops, content).  
1325 -  
1326 -  
1327 -public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t).  
1328 -public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file)  
1329 - = fixed_size_2(width,height,name_of_HTML_file).  
1330 -  
1331 -  
1332 -public define HTML_Off_Form  
1333 - foreign_link  
1334 - (  
1335 - Int tsize,  
1336 - String url,  
1337 - String name  
1338 - ) =  
1339 - foreign_link([size(tsize)],url,name).  
1340 -  
1341 -  
1342 -public define HTML_Off_Form  
1343 - actioner  
1344 - (  
1345 - Actioner_Connection conn,  
1346 - Actioner_Target targ,  
1347 - Actioner_Aspect asp,  
1348 - String action_name,  
1349 - List((String,String)) extra_ops  
1350 - ) =  
1351 - actioner(conn,targ,asp,action_name,extra_ops,[]).  
1352 -  
1353 -public define HTML_Off_Form  
1354 - table  
1355 - (  
1356 - List(HTML_Row(HTML_Off_Form)) rows  
1357 - ) =  
1358 - table([],empty,rows,empty).  
1359 -  
1360 -public define HTML_Off_Form  
1361 - table  
1362 - (  
1363 - List(Table_Option) options,  
1364 - List(HTML_Row(HTML_Off_Form)) rows  
1365 - ) =  
1366 - table(options,empty,rows,empty).  
1367 -  
1368 -public define HTML_Off_Form  
1369 - table  
1370 - (  
1371 - HTML_Header_Row(HTML_Off_Form) h_row,  
1372 - List(HTML_Row(HTML_Off_Form)) rows  
1373 - ) =  
1374 - table([],h_row,rows,empty).  
1375 -  
1376 -public define HTML_Off_Form  
1377 - table  
1378 - (  
1379 - List(Table_Option) options,  
1380 - HTML_Header_Row(HTML_Off_Form) h_row,  
1381 - List(HTML_Row(HTML_Off_Form)) rows  
1382 - ) =  
1383 - table(options,h_row,rows,empty).  
1384 -  
1385 - We add two convenience functions for 'row'. The reason why we add two functions, one  
1386 - for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an  
1387 - arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so,  
1388 - the arguments of the function do not refer to any of the types defined here.  
1389 -  
1390 -public define HTML_Row(HTML_In_Form)  
1391 - row  
1392 - (  
1393 - HTML_In_Form content  
1394 - ) =  
1395 - row([],[cell([],content)]).  
1396 -  
1397 -public define HTML_Row(HTML_Off_Form)  
1398 - row  
1399 - (  
1400 - HTML_Off_Form content  
1401 - ) =  
1402 - row([],[cell([],content)]).  
1403 -  
1404 -  
1405 -public define HTML_Off_Form  
1406 - private_download  
1407 - (  
1408 - String abs_path,  
1409 - String name,  
1410 - String extra_ext  
1411 - ) =  
1412 - private_download(abs_path,name,extra_ext,failure).  
1413 -  
1414 -  
1415 -public define HTML_Off_Form  
1416 - private_download  
1417 - (  
1418 - String abs_path,  
1419 - String name,  
1420 - String extra_ext,  
1421 - String action_name,  
1422 - List((String,String)) args  
1423 - ) =  
1424 - private_download(abs_path,name,extra_ext,success((action_name,args))).  
1425 -  
1426 -public define HTML_Off_Form  
1427 - text  
1428 - (  
1429 - List(Text_Option) lto,  
1430 - Int i  
1431 - ) =  
1432 - text(lto,to_decimal(i)).  
1433 -  
1434 -  
1435 -public define HTML_Off_Form  
1436 - text  
1437 - (  
1438 - Int i  
1439 - ) =  
1440 - text([],i).  
1441 -  
1442 -public define HTML_Off_Form  
1443 - text  
1444 - (  
1445 - String s  
1446 - ) =  
1447 - text([],s).  
1448 -  
1449 - - Cell a gap between two other cells :  
1450 -  
1451 -public define HTML_Cell(HTML_Off_Form)  
1452 - width_gap  
1453 - (  
1454 - Int w  
1455 - ) =  
1456 - cell([width(w)],text([],"")).  
1457 -  
1458 -public define HTML_Cell(HTML_In_Form)  
1459 - width_gap  
1460 - (  
1461 - Int w  
1462 - ) =  
1463 - cell([width(w)],text([],"")).  
1464 -  
1465 -  
1466 - - Row a gap between two other rows :  
1467 -  
1468 -public define HTML_Row(HTML_Off_Form)  
1469 - height_gap  
1470 - (  
1471 - Int h  
1472 - ) =  
1473 - row([],[cell([height(h)],text([],""))]).  
1474 -  
1475 -public define HTML_Row(HTML_In_Form)  
1476 - height_gap  
1477 - (  
1478 - Int h  
1479 - ) =  
1480 - row([],[cell([height(h)],text([],""))]).  
1481 -  
1482 -  
1483 - Notice that the two types have alternatives in common (same name, same arguments types,  
1484 - up to the value of the parameter $T), which correspond to elements which may be put  
1485 - anywhere in the page.  
1486 -  
1487 -  
1488 -  
1489 -  
1490 -define String  
1491 - format  
1492 - (  
1493 - List(Text_Option) l  
1494 - ).  
1495 -  
1496 -  
1497 -  
1498 -  
1499 -define Printable_tree  
1500 - format_css_styles  
1501 - (  
1502 - List(CSS_Style) l  
1503 - ) =  
1504 - if l is  
1505 - {  
1506 - [ ] then [ ],  
1507 - [h . t] then  
1508 - [ if h is  
1509 - {  
1510 - text_options(tos) then  
1511 - [" body, span, p { ", format(tos), " }\n" ]  
1512 - }  
1513 - . format_css_styles(t)]  
1514 - }.  
1515 -  
1516 -  
1517 -  
1518 -public type HTML_Meta:  
1519 - keywords (List(String)),  
1520 - refresh (Actioner_Connection connection,  
1521 - Actioner_Target target,  
1522 - String action_name,  
1523 - Int delay), // in seconds  
1524 - refresh (String url, Int delay), // in seconds  
1525 - meta (String name, String content),  
1526 - http_equiv (String name, String content),  
1527 - generic_meta (List((String,String))),  
1528 - literal (String).  
1529 -  
1530 - Meta tags are put in the 'head' of the HTML page.  
1531 -  
1532 -  
1533 -public type Body_Option:  
1534 - core_attrs(List(CoreAttrs)),  
1535 - background_color (RGB),  
1536 - background_image (String url),  
1537 - background_image (String url, List(BackgroundOption)).  
1538 -  
1539 -public type HTML_Body:  
1540 - body(List(Body_Option) options, HTML_Off_Form content).  
1541 -  
1542 -  
1543 -public type HTTP_Answer:  
1544 - html_page (HTTP_Status /*http_status*/,  
1545 - List(HTML_Head_Tag) /*html <head> tags*/,  
1546 - HTML_Body /*body*/),  
1547 - html_page (HTTP_Status /*http_status*/,  
1548 - String /*title*/,  
1549 - List(HTML_Meta) /*meta_tags*/,  
1550 - List(CSS_Style) /*styles*/,  
1551 - List(CSS_File) /*css_files*/,  
1552 - List(JS_File) /*js_files*/,  
1553 - List(Script) /*script*/,  
1554 - HTML_Body /*body*/),  
1555 - plain_text (HTTP_Status /*http_status*/,  
1556 - String /*text*/),  
1557 - custom_text (HTTP_Status /*http_status*/,  
1558 - String /*mime_type*/,  
1559 - String /*content*/),  
1560 - custom_binary(HTTP_Status /*http_status*/,  
1561 - String /*mime_type*/,  
1562 - ByteArray /*content*/,  
1563 - List(HTTP_header)/*other headers*/),  
1564 - custom_tree (HTTP_Status /*http_status*/,  
1565 - String /*mime_type*/,  
1566 - Printable_tree /*content*/),  
1567 - http_raw (Printable_tree),  
1568 - html_content (HTTP_Status /*http_status*/,  
1569 - HTML_Off_Form).  
1570 -  
1571 -  
1572 -public define HTTP_Answer  
1573 - html_page  
1574 - (  
1575 - String title,  
1576 - List(HTML_Meta) metas,  
1577 - HTML_Body body  
1578 - ) =  
1579 - html_page(http_ok, title,metas,[],[],[],[],body).  
1580 -  
1581 -public define HTTP_Answer  
1582 - html_page  
1583 - (  
1584 - String title,  
1585 - List(HTML_Meta) metas,  
1586 - List(CSS_Style) styles,  
1587 - HTML_Body body  
1588 - ) =  
1589 - html_page(http_ok, title, metas, styles, [], [], [], body).  
1590 -  
1591 - 'HTTP_Answer' represents the final product of the construction of a web page.  
1592 -  
1593 -  
1594 -  
1595 -  
1596 - *** (3.2) ``in form'' versus ``off form''.  
1597 -  
1598 - There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some  
1599 - of them may have a content, which is yet another HTML element (or several). Hence, it  
1600 - is meaningful to say that an element is 'within' another one. Now, putting any element  
1601 - within any other one may be meaningless. For example, an input element must be put  
1602 - within a form (otherwise, it is useless), and a from within another form has no precise  
1603 - meaning (and is forbidden by the HTML specification).  
1604 -  
1605 - Actually, the main criterium is ``within a form or not within a form''. So, HTML  
1606 - elements in a given page are separated into two categories: those who are within a  
1607 - form, and the others. Nevertheless, there are elements which may belong to both  
1608 - categories, like images and texts. We want to make use of the strong typing mecanism of  
1609 - Anubis in order to forbid non meaningful placement of elements.  
1610 -  
1611 - The type 'HTML_In_Form' defines elements to be put within forms. Similarly,  
1612 - 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive,  
1613 - and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course),  
1614 - but the two types are not cross recursive. This is the reason why it is impossible to  
1615 - put a form within a form. In order to construct a web page, you essentially have to  
1616 - produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form').  
1617 -  
1618 - In practice, you don't have to worry so much about these two types, because elements  
1619 - which may be put anywhere are constructed for both types by functions with the same  
1620 - name and the same arguments. Hence, for both types, you just write the same thing. You  
1621 - are warned by the compiler only when you try to put an element at a place it is not  
1622 - allowed.  
1623 -  
1624 -  
1625 -  
1626 - *** (3.3) Defining your own style.  
1627 -  
1628 - We provide generic tools for constructing HTML elements. However, your web site needs  
1629 - to have a ``style''.  
1630 -  
1631 - To that end, you need to write down a set of ``styling functions'', using the tools  
1632 - defined here. These styling functions allow the introduction of your colors and other  
1633 - visual characteristics into the constructed elements once and for all. For example, you  
1634 - may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using  
1635 - some 'text_color'. You may write something like this:  
1636 -  
1637 - define RGB text_color = rgb(10,40,40).  
1638 -  
1639 - define HTML_Off_Form  
1640 - text  
1641 - (  
1642 - String the_text  
1643 - ) =  
1644 - text([font("helvetica"),size(14),color(text_color)],  
1645 - the_text).  
1646 -  
1647 - (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a  
1648 - page, you just write:  
1649 -  
1650 - text("... some text ...")  
1651 -  
1652 - and you don't have to provide the font, size and color for each text. If you want to  
1653 - have several styles of text presentation, you just write several sets of such  
1654 - convenience functions. This also suggests a trick. You may want for example different  
1655 - colors for 'in form' texts and 'off form' texts. This may be achieved automatically by  
1656 - defining two functions as above, with the same name and same argument type, but  
1657 - returning either a 'HTML_In_Form' or a 'HTML_Off_Form'.  
1658 -  
1659 - If this preliminary work is well done, you will not waste your time later when you  
1660 - concentrate on the actual informational content of your pages.  
1661 -  
1662 - This general principle should be applied to all sorts of elements. This is the best  
1663 - thing to do in order to separate the functions defining the visual style from the  
1664 - functions defining the informational content itself, so that changing the style without  
1665 - changing the content becomes easy. This is also the best way for having a clean and  
1666 - easily readable source for your web site.  
1667 -  
1668 -  
1669 -  
1670 -  
1671 -  
1672 - *** (3.4) Actioners and forms.  
1673 -  
1674 - We have gathered several notions from HTML into that of an 'actioner'. An actioner is  
1675 - an HTML element which opens a connection to our server when clicked upon. Actioners may  
1676 - have different visual aspects. They may look like hypertext links or like buttons  
1677 - (rollovers), or even like selectors (with immediate action). In any case, their  
1678 - behavior is the same: they open a connection to our server, and send a set of 'web  
1679 - arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes  
1680 - the action to be performed, and the others should be considered as operands for this  
1681 - action. Actually, the precise behavior of the actioner has several variants.  
1682 -  
1683 - The connection with the server may be secured (HTTPS) or non secured (HTTP). See the  
1684 - type 'Actioner_Connection' above.  
1685 -  
1686 - You must also choose where the answer must be rendered. This may be in the same window  
1687 - or in another window (or frame). If it is in another window, the name of that window  
1688 - must be given. If the window does not exist, the browser will create it. Optionally,  
1689 - you may give the dimensions of the new window and other characteristics. See the type  
1690 - 'Actioner_Target' above.  
1691 -  
1692 - The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the  
1693 - case of a rollover button, you provide the URLs of two images (of the same size)  
1694 - representing the button:  
1695 -  
1696 - url_off: to be used when the mouse is not over the button,  
1697 - url_on: to be used when the mouse is over the button.  
1698 -  
1699 - You can also create rollover buttons without creating images. Just use the second  
1700 - alternative named 'button'. The server creates the images automatically.  
1701 -  
1702 - The purpose of forms is just to give operands to actioners. If the actioner is placed  
1703 - within a form, all the input elements which are within this form provide operands to  
1704 - the actioner (except sometimes when they are not set by the client). If it is not put  
1705 - within a form, the actioner gets no operand, except if the name of a form is explicitly  
1706 - given, in which case the actioner gets all the inputs from that form as  
1707 - operands. Furthermore, you may want to give extra operands to the actioner. This may be  
1708 - useful for separating families of actioners with the same action name. Extra operands  
1709 - 'name=value' must be given in the form of pairs '(name,value)'.  
1710 -  
1711 - Notice that the name of a form may be used by an actioner which is off the form, so as  
1712 - to get the operands provided by this form. Also notice that several actioners may refer  
1713 - to the same form, being either in the form, or referring to the form from the  
1714 - outside. These actioners simply get the same set of operands, even if they correspond  
1715 - to distinct actions.  
1716 -  
1717 - Input elements may be put only within a form.  
1718 -  
1719 -  
1720 -  
1721 - *** (3.5) Local popup.  
1722 -  
1723 - This element looks like a link or a rollover button. When this button is clicked upon,  
1724 - a 'popup window' appears. Actually, this popup window is just a layer in the same HTML  
1725 - page, which becomes suddenly visible. It is realized with a '<div>' HTML tag. In  
1726 - particular, clicking on the button does not open any connection. This is why it is  
1727 - called 'local'. The arguments have the following roles:  
1728 -  
1729 - Actioner_Aspect aspect of the button (same semantics as for actioners)  
1730 - content content of the popup window  
1731 - x, y, position of the popup window on the HTML page (not relative  
1732 - to the button but to the page itself)  
1733 - title title of the popup window  
1734 - color color of the title bar and close button in the popup window.  
1735 - A lightened version of this color is used for the background  
1736 - of the popup window.  
1737 - width width of the title bar  
1738 -  
1739 -  
1740 -  
1741 -  
1742 -  
1743 - --- That's all for the public part ! --------------------------------------------------  
1744 -  
1745 -  
1746 -  
1747 -  
1748 -  
1749 - ----------------------------------- Table of Contents ---------------------------------  
1750 -  
1751 - *** [1] States.  
1752 - *** [1.1] Saving and retrieving states.  
1753 - *** [1.2] Deleting out of date states.  
1754 -  
1755 - *** [2] Tools.  
1756 - *** [2.1] Directories.  
1757 - *** [2.2] Secondary documents.  
1758 -  
1759 - *** [3] Managing web arguments.  
1760 - *** [3.1] Prefixing web arguments names.  
1761 - *** [3.2] Separating web arguments.  
1762 - *** [3.3] Applying an action.  
1763 -  
1764 - *** [4] Web site descriptions and the 'awp handlers'.  
1765 - *** [4.1] The type 'Web_Site'.  
1766 - *** [4.2] Making a web site description.  
1767 - *** [4.3] Starting the servers.  
1768 -  
1769 - *** [5] HTML Formating.  
1770 - *** [5.1] The type 'HTML_Any($T)'.  
1771 - *** [5.2] Formating a color.  
1772 - *** [5.3] Creating buttons.  
1773 - *** [5.4] Formating an actioner.  
1774 - *** [5.5] Formating a private download link.  
1775 - *** [5.6] Formating rows and cells in a table.  
1776 - *** [5.7] Formating elements which may be put anywhere.  
1777 - *** [5.8] Formating 'in form' elements.  
1778 - *** [5.9] Formating 'off form' elements.  
1779 - *** [5.10] Formating meta-tags.  
1780 -  
1781 - ---------------------------------------------------------------------------------------  
1782 -  
1783 -  
1784 -  
1785 -  
1786 -public define String  
1787 - doctype_w3c_header  
1788 - =  
1789 - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "+  
1790 - "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".  
1791 -  
1792 -public define String  
1793 - html_header  
1794 - =  
1795 - "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n".  
1796 -  
1797 -  
1798 - *** [1] States.  
1799 -  
1800 - We have to define functions for saving a state, retrieving a state, deleting out of  
1801 - date states. We need one such function per web site. The types of the first two  
1802 - functions depend on the parameter $State. This is not the case of the third one. The  
1803 - fact that the instance of $State is variable from one web sites to the other implies  
1804 - rather subtle manipulations using full functionality.  
1805 -  
1806 -  
1807 - *** [1.1] Saving and retrieving states.  
1808 -  
1809 - Each state is saved into a file on the server's disk (in the directory represented by  
1810 - the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The  
1811 - state is saved together with a time stamp whose value is obtained by adding the current  
1812 - time to the given timeout for states. The state receives a name obtained by hashing  
1813 - (using sha1) the content of the file itself, and then encoding the hash with  
1814 - 'web_arg_encode'. The name of the file into which the state is saved is the  
1815 - concatenation of "s" and the name of the state.  
1816 -  
1817 -read CXM_web_arg_encode.anubis  
1818 -  
1819 - The tool below constructs the function which is able to save a state on the server's  
1820 - disk.  
1821 -  
1822 -define ($State s) -> String // the function constructed returns the name of the state  
1823 - make_save_state_function  
1824 - (  
1825 - Int timeout,  
1826 - String state_directory  
1827 - ) =  
1828 - ($State s) |->  
1829 - with time_stamp = now+timeout,  
1830 - to_be_saved = (time_stamp,s),  
1831 - state_name = web_arg_encode(sha1(s)),  
1832 - if save(to_be_saved,state_directory+"/s"+state_name) is ok  
1833 - then state_name  
1834 - else (print("Cannot create state file in '"+state_directory+"'.\n"); "").  
1835 -  
1836 -  
1837 - When a request arrives, we need to retrieve the previous state from the server's  
1838 - disk. We receive the name of that state. If the state is out of date, the state file is  
1839 - kept 3 days, and then deleted.  
1840 -  
1841 -type PreviousState($State):  
1842 - not_found, // cannot retrieve the previous state  
1843 - out_of_date($State), // the previous state is out of date  
1844 - still_valid($State). // the previous state is still valid  
1845 -  
1846 -define (String state_name) -> PreviousState($State)  
1847 - make_retrieve_state_function  
1848 - (  
1849 - String state_directory  
1850 - ) =  
1851 - (String state_name) |->  
1852 - with file_path = state_directory+"/s"+state_name,  
1853 - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)  
1854 - then (  
1855 - if d is (time_stamp,s) then  
1856 - if time_stamp < now  
1857 - then (  
1858 - forget(remove(file_path));  
1859 - out_of_date(s)  
1860 - )  
1861 - else still_valid(s) // state has been successfully retrieved  
1862 - )  
1863 - else not_found.  
1864 -  
1865 -  
1866 -  
1867 - *** [1.2] Deleting out of date states.  
1868 -  
1869 - We also need to delete states which are out of date and which will never be deleted by  
1870 - the above method. This may be performed by a machine doing this periodically (say once  
1871 - per states life time period).  
1872 -  
1873 -define (List(String) file_names) -> One  
1874 - make_delete_out_of_date_states_function  
1875 - (  
1876 - Maybe($State) dummy,  
1877 - String state_directory  
1878 - ) =  
1879 - (List(String) file_names) |-df->  
1880 - if file_names is  
1881 - {  
1882 - [ ] then unique,  
1883 - [h . t] then  
1884 - with file_path = state_directory+"/"+h,  
1885 - if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)  
1886 - then (  
1887 - if d is (time_stamp,data) then  
1888 - if time_stamp < now  
1889 - then (forget(remove(file_path)); df(t))  
1890 - else df(t)  
1891 - )  
1892 - else (forget(remove(file_path)); df(t))  
1893 - }.  
1894 -  
1895 -  
1896 - The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'.  
1897 -  
1898 - Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the  
1899 - function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler  
1900 - does not accept a parameter in the body of a function (here the parameter is required  
1901 - by the use of 'retrieve') if this parameter does not appear in the type of the  
1902 - function. This is because this would create ambiguities that no explicit typing may  
1903 - ever resolve. If you put a double slash in front of the declaration of 'dummy' above,  
1904 - and if you compile this file, you will get a message like this one:  
1905 -  
1906 - Error in 'making_a_web_site.anubis', line 1300, column 7:  
1907 - A definition may not contain parameters which are not present  
1908 - in the declaration part (hidden parameters):  
1909 - $State  
1910 -  
1911 - The type of the function constructed by 'make_delete_out_of_date_states_function' is  
1912 - independant of the parameter $State. This is important because this allows to create  
1913 - the list of such functions for all web sites. From this list, it is possible to call  
1914 - the functions one after the other, so deleting out of date states for all web  
1915 - sites. Actually, the next function receives a list of pairs (state_directory,function),  
1916 - one for each web site.  
1917 -  
1918 -define One  
1919 - delete_out_of_date_states // for all web sites  
1920 - (  
1921 - List((String, List(String) -> One)) directories_and_functions  
1922 - ) =  
1923 - if directories_and_functions is  
1924 - {  
1925 - [ ] then unique,  
1926 - [h . t] then if h is (state_directory,function) then  
1927 - function(directory_list(state_directory,"s*"));  
1928 - delete_out_of_date_states(t)  
1929 - }.  
1930 -  
1931 -  
1932 - The above function must be called periodically in a separate virtual machine. The  
1933 - period we have choosen is (rather logically) the life time of states itself. This may  
1934 - be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not  
1935 - be really infinite, because the servers may be shutdown. Hence, our loop must test  
1936 - (rather frequently; say every second) if the servers are down. If they are, the loop  
1937 - must be exited.  
1938 -  
1939 -define One  
1940 - delete_states_loop  
1941 - (  
1942 - List((String,List(String) -> One)) directories_and_functions,  
1943 - Int timeout,  
1944 - Int next_time,  
1945 - Server http_server,  
1946 - Server https_server,  
1947 - (One) -> Bool shutdown_required  
1948 - ) =  
1949 - if shutdown_required(unique)  
1950 - then (shutdown(http_server); shutdown(https_server))  
1951 - else unique;  
1952 - if (is_down(http_server) & is_down(https_server))  
1953 - then unique  
1954 - else if now > next_time  
1955 - then  
1956 - (  
1957 - delete_out_of_date_states(directories_and_functions);  
1958 - delete_states_loop(directories_and_functions,  
1959 - timeout,  
1960 - now+timeout,  
1961 - http_server,  
1962 - https_server,  
1963 - shutdown_required)  
1964 - )  
1965 - else  
1966 - (  
1967 - sleep(1000); // sleep just one second and try again  
1968 - delete_states_loop(directories_and_functions,  
1969 - timeout,  
1970 - next_time,  
1971 - http_server,  
1972 - https_server,  
1973 - shutdown_required)  
1974 - ).  
1975 -  
1976 - The above loop must be run in a separate virtual machine. This will be done just after  
1977 - the two servers are started.  
1978 -  
1979 -  
1980 -  
1981 -  
1982 -  
1983 - *** [2] Tools.  
1984 -  
1985 - *** [2.1] Directories.  
1986 -  
1987 - We need a tool for creating directories (if needed).  
1988 -  
1989 - (This tool has been moved to 'tools/basis.anubis').  
1990 -  
1991 -  
1992 -  
1993 -  
1994 - *** [2.2] Secondary documents.  
1995 -  
1996 - Some HTML elements (like '<object>', '<frame>') cannot receive their content directly  
1997 - from the current document, but only through an URL. For this reason, we implement a  
1998 - mecanism for creating secondary documents on the fly. To that end we use the 'private  
1999 - download' mecanism.  
2000 -  
2001 - A secondary document is formated by the same functions as the main document itself. The  
2002 - next function takes an 'off form' element, creates the file containing the secondary  
2003 - document in HTML format, and returns the URL at which the document will be available.  
2004 -  
2005 -define String  
2006 - create_secondary_document  
2007 - (  
2008 - String sd, // site directory  
2009 - String as, // authorization_secret  
2010 - String sn, // state name  
2011 - $T -> Printable_tree format_element,  
2012 - $T content,  
2013 - HTML_Size width  
2014 - ) =  
2015 - with private_download_directory = sd+"/private_download",  
2016 - hash = web_arg_encode(sha1(content)),  
2017 - file_content = (Printable_tree)  
2018 - [doctype_w3c_header,  
2019 - "<html><body><table ",  
2020 - if width is  
2021 - {  
2022 - absolute(w) then ["width=\"",w-25],  
2023 - percentage(w) then ["width=\"95%\""]  
2024 - },"\"><tbody><tr><td align=right>",  
2025 - format_element(content),  
2026 - "</td></tr></tbody></table></body></html>"  
2027 - ],  
2028 - file_name = "sd"+hash+".html",  
2029 - file_path = private_download_directory+"/"+file_name,  
2030 - if write_to_file(file_path,file_content) is  
2031 - {  
2032 - cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "",  
2033 - write_error(n) then print("Error writing file '"+file_path+"'.\n"); "",  
2034 - ok then file_name+"?zauth="+  
2035 - make_authorization(sd,as,private_download_directory+"/"+file_name)  
2036 - }.  
2037 -  
2038 -  
2039 -  
2040 -  
2041 - *** [2.3] Generating unique ids.  
2042 -  
2043 - In order to uniquely name object for JavaScript we generate unique ids from a counter.  
2044 -  
2045 -define Int  
2046 - new_idnum  
2047 - (  
2048 - Var(Int) ic_v // 'idnum' counter variable  
2049 - ) =  
2050 - protect  
2051 - with result = *ic_v+1,  
2052 - ic_v <- result;  
2053 - result.  
2054 -  
2055 -  
2056 -  
2057 -  
2058 -  
2059 -  
2060 - *** [3] Managing web arguments.  
2061 -  
2062 - Web arguments are those pairs 'name=value' which are transmitted through the HTTP  
2063 - protocol. We need precise naming conventions for these web arguments.  
2064 -  
2065 -  
2066 -  
2067 - *** [3.1] Prefixing web arguments names.  
2068 -  
2069 - CR 2008-07-08 Prefixing Removed  
2070 -  
2071 -  
2072 -  
2073 - *** [3.2] Separating web arguments.  
2074 -  
2075 - When a new request arrives, we need to separate the web arguments, that is to say:  
2076 -  
2077 - - find the value of "s", and recover the corresponding state,  
2078 - - find the value of "a", which is the name of the action to be performed,  
2079 - - get the list of all the remaining web arguments (operands of the action).  
2080 -  
2081 - We must also determine if the previous state may be recovered. If it is not the case  
2082 - (either because the previous state name is invalid, or the previous state is out of  
2083 - date), we must check if there is an action name. Indeed, the presence of an action name  
2084 - indicates that the user has clicked on one of our buttons or links. If on the contrary  
2085 - there is no action name the user has just entered our address in his browser. In this  
2086 - last case, we must send the first page of our site (maybe a 'login' page), but if there  
2087 - is an action, we must send a page just saying that the session ticket has expired. If  
2088 - the previous state is recovered and there is no action, the new state is the same as  
2089 - the previous state.  
2090 -  
2091 - The result of the separation of the web arguments is of type:  
2092 -  
2093 -type Separated_Web_Args($State):  
2094 - swa(PreviousState($State) previous_state,  
2095 - Maybe(String) action_name,  
2096 - List(Web_arg) operands).  
2097 -  
2098 -  
2099 -  
2100 - The next function constructs the function which separates the web arguments.  
2101 -  
2102 -define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State)  
2103 - make_separate_web_args_function  
2104 - (  
2105 - String state_directory,  
2106 - String -> PreviousState($State) retrieve_state,  
2107 - String website_name  
2108 - ) =  
2109 - (List(Web_arg) lwa, HTTP_Info info) |-swaf->  
2110 - if lwa is  
2111 - {  
2112 - [ ] then  
2113 - //  
2114 - // no web arg found => no previous state and no action  
2115 - //  
2116 - if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is  
2117 - {  
2118 - failure then swa(not_found,failure,[]),  
2119 - success(cookie) then swa(retrieve_state(value(cookie)),failure,[])  
2120 - },  
2121 -  
2122 - //swa(failure,failure,[]),  
2123 -  
2124 - [wa_1 . wa_others] then  
2125 - //  
2126 - // at least one web arg =>  
2127 - // separate other web args, and insert the first one as needed  
2128 - //  
2129 - if (Separated_Web_Args($State))swaf(wa_others, info) is  
2130 - {  
2131 - swa(ps1, // possible previous state  
2132 - an1, // maybe an action name  
2133 - op1) // operands so far  
2134 - then  
2135 - if wa_1 is  
2136 - {  
2137 - web_arg(n, value) then  
2138 - with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n,  
2139 - if name = "a" then  
2140 - swa(ps1,success(value),op1)  
2141 - else if name = "t" then  
2142 - swa(ps1,an1,[web_arg("target",value) . op1])  
2143 - else  
2144 - swa(ps1,an1,[web_arg(name,value) . op1]),  
2145 -  
2146 - upload(n,v,t) then  
2147 - swa(ps1,an1,[wa_1 . op1])  
2148 - }  
2149 - }  
2150 - }.  
2151 -  
2152 -  
2153 -  
2154 -  
2155 -  
2156 -  
2157 - *** [3.3] Applying an action.  
2158 -  
2159 - When the web arguments are separated (and their names cleaned up from prefixes), we may  
2160 - apply the action to the operands and the current state. We search for the action to be  
2161 - applied in the list of actions. If no action is found, the new state is the same as  
2162 - the previous state. Also, we deny the application of an HTTP action if the request  
2163 - arrives through the HTTPS channel and conversely.  
2164 -  
2165 -  
2166 -define ($State previous,  
2167 - String action_name,  
2168 - HTTP_Info http_info,  
2169 - List(Web_arg) lwa,  
2170 - Bool is_https) -> $State  
2171 - make_apply_action_function  
2172 - (  
2173 - List(Web_Action($State)) actions_list  
2174 - ) =  
2175 - with f =  
2176 - ($State previous,  
2177 - String action_name,  
2178 - HTTP_Info http_info,  
2179 - List(Web_arg) lwa,  
2180 - Bool is_https,  
2181 - List(Web_Action($State)) actions) |-f->  
2182 - //println("Looking for action ["+action_name+"]");  
2183 - if actions is  
2184 - {  
2185 - [ ] then print("action '"+action_name+  
2186 - "' not found.\n"); previous,  
2187 - [ac1 . others] then if ac1 is  
2188 - {  
2189 - http_action(an,allow,do_it) then  
2190 - if an = action_name  
2191 - then if is_https  
2192 - then (print("HTTP action '"+an+  
2193 - "' called through HTTPS (denied).\n");  
2194 - previous)  
2195 - else if allow(previous)  
2196 - then do_it(http_info,lwa,previous)  
2197 - else previous  
2198 - else f(previous,action_name,http_info,lwa,is_https,others),  
2199 -  
2200 - https_action(an,allow,do_it) then  
2201 - if an = action_name  
2202 - then if is_https  
2203 - then if allow(previous)  
2204 - then do_it(http_info,lwa,previous)  
2205 - else previous  
2206 - else (print("HTTPS action '"+an+  
2207 - "' called through HTTP (denied).\n");  
2208 - previous)  
2209 - else f(previous,action_name,http_info,lwa,is_https,others),  
2210 -  
2211 - http_https_action(an,allow,do_it) then  
2212 - if an = action_name  
2213 - then  
2214 - //println("Action ["+action_name+"] found");  
2215 - if allow(previous)  
2216 - then do_it(http_info,lwa,previous)  
2217 - else previous  
2218 - else f(previous,action_name,http_info,lwa,is_https,others),  
2219 -  
2220 - }  
2221 - },  
2222 - ($State previous,  
2223 - String action_name,  
2224 - HTTP_Info http_info,  
2225 - List(Web_arg) lwa,  
2226 - Bool is_https) |->  
2227 - f(previous, action_name, http_info, lwa, is_https, actions_list).  
2228 -  
2229 -  
2230 -  
2231 -  
2232 -  
2233 -  
2234 -  
2235 -  
2236 - *** [4] Web site descriptions and the 'awp handlers'.  
2237 -  
2238 - *** [4.1] The type 'Web_Site'.  
2239 -  
2240 - The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We  
2241 - need another one, because, we have some extra informations to record for each site.  
2242 -  
2243 -public type Web_Site:  
2244 - web_site((Word32,Word32) -> Web_Site_Description description,  
2245 - List(String) -> One delete_out_of_date).  
2246 -  
2247 -  
2248 -  
2249 -  
2250 - *** [4.2] Making a web site description.  
2251 -  
2252 - Below is the function which creates a web site description. It first creates (if  
2253 - needed) the directories for the site, then constructs the tool functions for the site,  
2254 - and the site handler. Finally, it constructs the web site description.  
2255 -  
2256 - We gather common (constant) informations in the following type:  
2257 -  
2258 -public type CommonInfo:  
2259 - info(String common_name,  
2260 - Word32 http_port,  
2261 - Word32 https_port,  
2262 - String site_directory,  
2263 - String authorization_secret  
2264 - ).  
2265 -  
2266 - We need a forward declaration.  
2267 -  
2268 -public define Printable_tree  
2269 - format  
2270 - (  
2271 - CommonInfo cinfo,  
2272 - String state_name,  
2273 - List(HTTP_header) headers,  
2274 - HTTP_Answer page,  
2275 - Bool is_https,  
2276 - String charset  
2277 - ).  
2278 -  
2279 -  
2280 -define Printable_tree  
2281 - format  
2282 - (  
2283 - HTML_Size s  
2284 - ) =  
2285 - if s is  
2286 - {  
2287 - absolute(x) then ["\"",x,"\""],  
2288 - percentage(x) then ["\"",x,"%\""]  
2289 - }.  
2290 -  
2291 -define List(HTTP_header)  
2292 - make_state_cookie_headers  
2293 - (  
2294 - String website_name,  
2295 - String state_name  
2296 - )  
2297 - =  
2298 - [  
2299 - http_header("Set-Cookie", "state_"+website_name+"="+state_name)  
2300 - ]  
2301 - .  
2302 -  
2303 - public define Web_Site  
2304 - make_web_site_description  
2305 - (  
2306 - List(String) common_names, // for example: ["www.our-business.com",  
2307 - // "192.168.0.1"]  
2308 - // the second one is just for testing  
2309 - String site_directory, // where 'public' and other directories are  
2310 - // located (should NOT end with '/')  
2311 - One -> One init,  
2312 - (HTTP_Info,  
2313 - List(Web_arg),  
2314 - Bool is_https) -> $State initial_state,  
2315 - ($State expired,  
2316 - HTTP_Info,  
2317 - List(Web_arg),  
2318 - Bool is_https) -> $State ticket_expired_state,  
2319 - (HTTP_Info,  
2320 - List(Web_arg),  
2321 - Bool is_https) -> $State ticket_lost_state,  
2322 - List(Web_Action($State)) actions,  
2323 - $State -> HTTP_Answer compute_page,  
2324 - $State -> List(HTTP_header) additional_headers,  
2325 - Int timeout, // seconds (todo: minutes)  
2326 - Redirections redirections,  
2327 - String charset,  
2328 - List(String) journal_extensions,  
2329 - List(String) journal_headers,  
2330 - String authorization_secret,  
2331 - List(MIME) known_mime_types,  
2332 - (String action_name,  
2333 - List(Web_arg) args)-> One before_send_file  
2334 - ).  
2335 -  
2336 -  
2337 -public define Web_Site  
2338 - make_web_site_description  
2339 - (  
2340 - String website_name,  
2341 - List(String) common_names, // for example: ["www.our-business.com"]  
2342 - String site_directory,  
2343 - String state_directory,  
2344 - One -> One init,  
2345 - (HTTP_Info,  
2346 - List(Web_arg),  
2347 - Bool is_https) -> $State initial_state,  
2348 - ($State expired,  
2349 - Maybe(String),  
2350 - HTTP_Info,  
2351 - List(Web_arg),  
2352 - Bool is_https) -> $State ticket_expired_state,  
2353 - (Maybe(String),  
2354 - HTTP_Info,  
2355 - List(Web_arg),  
2356 - Bool is_https) -> $State ticket_lost_state,  
2357 - List(Web_Action($State)) actions,  
2358 - $State -> HTTP_Answer compute_page,  
2359 - $State -> List(HTTP_header) additional_headers,  
2360 - Int timeout,  
2361 - Redirections redirections,  
2362 - String charset,  
2363 - List(String) journal_extensions,  
2364 - List(String) journal_headers,  
2365 - String secret,  
2366 - List(MIME) known_mime_types,  
2367 - (String action_name,  
2368 - List(Web_arg) args) -> One before_send_file  
2369 - //Bool using_state_cookies  
2370 - ) =  
2371 - init(unique);  
2372 -  
2373 -  
2374 - //  
2375 - // make required directories (if needed)  
2376 - //  
2377 - with //web_sites_directory = (String) make_directory(my_anubis_directory+"/web_sites"),  
2378 - base_directory = (String) make_directory(site_directory),  
2379 - // state_directory = make_directory(site_directory+"/states"),  
2380 - forget((String)make_directory(site_directory+"/public"));  
2381 - //  
2382 - // construct tool functions  
2383 - // TODO 'make_separate_web_args_function' must retrieve state_cookies before parsing web_args if using_state_cookies is true  
2384 - with save_state = make_save_state_function(timeout, state_directory),  
2385 - retrieve_state = make_retrieve_state_function(state_directory),  
2386 - separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name),  
2387 - apply_action = make_apply_action_function(actions),  
2388 - //  
2389 - // construct the site handler  
2390 - //  
2391 - site_handler = (Word32 http_port, Word32 https_port) |->  
2392 - ((String host_name,  
2393 - HTTP_Info http_info,  
2394 - List(Web_arg) lwa,  
2395 - Bool is_https) |->  
2396 - //(Printable_tree)  
2397 - if separate_web_args(lwa, http_info) is  
2398 - {  
2399 - swa(mb_previous_state, mb_action_name, operands) then  
2400 - with new_state = if mb_previous_state is  
2401 - {  
2402 - not_found then  
2403 - //println("previous state not found");  
2404 - if mb_action_name is  
2405 - {  
2406 - failure then initial_state(http_info, operands, is_https),  
2407 - success(_) then  
2408 - ticket_lost_state(mb_action_name, http_info,operands,is_https)  
2409 - },  
2410 -  
2411 - out_of_date(state) then  
2412 - ticket_expired_state(state, mb_action_name, http_info,operands,is_https),  
2413 -  
2414 - still_valid(state) then  
2415 - if mb_action_name is  
2416 - {  
2417 - failure then state,  
2418 - success(action_name) then  
2419 - apply_action(state,action_name,http_info,operands,is_https)  
2420 - }  
2421 - },  
2422 - //if state_and_headers is (session_ticket, mb_new_state, headers) then  
2423 - with state_name = save_state(new_state),  
2424 - //println("Cookie new STATE NAME "+state_name);  
2425 - with cookie_headers = if mb_action_name is  
2426 - {  
2427 - failure then [],  
2428 - success(action_name) then  
2429 - if substr(action_name, 0, 5)="ajax_" then  
2430 - []  
2431 - else  
2432 - make_state_cookie_headers(website_name, state_name)  
2433 - },  
2434 -  
2435 - format(info(host_name, http_port, https_port, site_directory, secret),  
2436 - state_name,  
2437 - additional_headers(new_state) + cookie_headers,  
2438 - compute_page(new_state),  
2439 - is_https,  
2440 - charset)  
2441 - }),  
2442 - //  
2443 - // make the delete_out_of_date function  
2444 - //  
2445 - delete_out_of_date =  
2446 - make_delete_out_of_date_states_function((Maybe($State))failure,  
2447 - site_directory+"/states"),  
2448 - //  
2449 - // construct the web site description  
2450 - //  
2451 - web_site((Word32 http_port, Word32 https_port) |->  
2452 - web_site_description(common_names,  
2453 - site_directory,  
2454 - redirections,  
2455 - charset,  
2456 - journal_extensions,  
2457 - journal_headers,  
2458 - secret,  
2459 - known_mime_types,  
2460 - site_handler(http_port,https_port),  
2461 - (HTTP_Info http_info, List(Web_arg) lwa) |-> if separate_web_args(lwa, http_info ) is  
2462 - swa(mb_previous_state,mb_action_name,operands) then  
2463 - if mb_action_name is  
2464 - {  
2465 - failure then unique  
2466 - success(an) then before_send_file(an,operands)  
2467 - }  
2468 - //using_state_cookies  
2469 - ),  
2470 - delete_out_of_date).  
2471 -  
2472 -// Compatibility function for older websites  
2473 -public define Web_Site  
2474 - make_web_site_description  
2475 - (  
2476 - List(String) common_names, // for example: ["www.our-business.com"]  
2477 - String site_directory,  
2478 - String state_directory,  
2479 - One -> One init,  
2480 - (HTTP_Info,  
2481 - List(Web_arg),  
2482 - Bool is_https) -> $State initial_state,  
2483 - ($State expired,  
2484 - Maybe(String),  
2485 - HTTP_Info,  
2486 - List(Web_arg),  
2487 - Bool is_https) -> $State ticket_expired_state,  
2488 - (Maybe(String),  
2489 - HTTP_Info,  
2490 - List(Web_arg),  
2491 - Bool is_https) -> $State ticket_lost_state,  
2492 - List(Web_Action($State)) actions,  
2493 - $State -> HTTP_Answer compute_page,  
2494 - $State -> List(HTTP_header) additional_headers,  
2495 - Int timeout,  
2496 - Redirections redirections,  
2497 - String charset,  
2498 - List(String) journal_extensions,  
2499 - List(String) journal_headers,  
2500 - String secret,  
2501 - List(MIME) known_mime_types,  
2502 - (String action_name,  
2503 - List(Web_arg) args) -> One before_send_file  
2504 - //Bool using_state_cookies  
2505 - )  
2506 - =  
2507 - make_web_site_description("", common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file)  
2508 - .  
2509 -  
2510 -  
2511 -  
2512 - *** [4.3] Starting the servers.  
2513 -  
2514 -public define Start_Web_Sites_Result  
2515 - start_web_sites  
2516 - (  
2517 - Word32 ip_address, // the IP address shared by the web sites  
2518 - Word32 http_port, // usually: 80  
2519 - Word32 https_port, // usually: 443  
2520 - String ssl_certificate_common_name,  
2521 - List(Web_Site) web_sites, // web sites to be started  
2522 - (One) -> Bool shutdown_required  
2523 - ) =  
2524 - with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port),  
2525 - with http_server_r =  
2526 - start_http_server(ip_address,http_port,  
2527 - map(get_description,web_sites),  
2528 - load_denial_of_service_info),  
2529 - with https_server_r =  
2530 - start_https_server(ip_address,https_port,  
2531 - ssl_certificate_common_name,  
2532 - map(get_description,web_sites),  
2533 - load_denial_of_service_info),  
2534 - if http_server_r is ok(http_server)  
2535 - then  
2536 - (  
2537 - if https_server_r is ok(https_server)  
2538 - then  
2539 - (  
2540 - start_http_servers_tasks(map(get_description,web_sites),  
2541 - [http_server,https_server],  
2542 - 600); // period of 10 minutes  
2543 - delegate  
2544 - delete_states_loop(  
2545 - map((Web_Site ws) |->  
2546 - (site_directory(description(ws)(http_port,https_port))+  
2547 - "/states",delete_out_of_date(ws)),  
2548 - web_sites),  
2549 - 3600*24*3, // keep out of date states 3 days  
2550 - now,  
2551 - http_server,  
2552 - https_server,  
2553 - shutdown_required),  
2554 - ok(http_server,https_server)  
2555 - )  
2556 - else cannot_bind_to_port(https_port)  
2557 - )  
2558 - else  
2559 - (  
2560 - if https_server_r is ok(https_server)  
2561 - then cannot_bind_to_port(http_port)  
2562 - else cannot_bind_to_port(http_port,https_port)  
2563 - ).  
2564 -  
2565 -  
2566 -public define One  
2567 - start_web_sites  
2568 - (  
2569 - Word32 ip_address, // the IP address shared by the web sites  
2570 - Word32 http_port, // usually: 80  
2571 - Word32 https_port, // usually: 443  
2572 - String ssl_certificate_common_name,  
2573 - List(Web_Site) web_sites, // web sites to be started  
2574 - (One) -> Bool shutdown_required,  
2575 - Logger log  
2576 - ) =  
2577 - if (Start_Web_Sites_Result)start_web_sites(ip_address,  
2578 - http_port,  
2579 - https_port,  
2580 - ssl_certificate_common_name,  
2581 - web_sites,  
2582 - shutdown_required) is  
2583 - {  
2584 - cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n),  
2585 - cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m),  
2586 - ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).")  
2587 - }.  
2588 -  
2589 -  
2590 -  
2591 -  
2592 -  
2593 - *** [5] HTML Formating.  
2594 -  
2595 - We need to translate HTML elements as defined above into actual HTML text.  
2596 -  
2597 - Actioners require special informations, which must be transmitted when needed by the  
2598 - 'format' functions:  
2599 -  
2600 - - the 'common name', which is used for URLs,  
2601 - - the HTTP/HTTPS port number,  
2602 - - the 'state name', which must be transmitted when the actioner is clicked upon,  
2603 - - the 'form name' (if any) to which the actioner refers.  
2604 -  
2605 - If the actioner is off form, and if it refers to a form, the name of that form is  
2606 - already known by the actioner. On the contrary, if the actioner is 'in form', it refers  
2607 - implicitly to the form containing it. The name of that form is transmitted to the  
2608 - 'format' functions called from within the formating of that form.  
2609 -  
2610 -  
2611 -  
2612 -  
2613 - *** [5.1] The type 'HTML_Any($T)'.  
2614 -  
2615 - The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The  
2616 - parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'.  
2617 -  
2618 -type HTML_Any($T):  
2619 - any_text (List(Text_Option), String the_text),  
2620 - any_preformated (List(Text_Option), String),  
2621 - any_paragraph (List(Text_Option), $T content),  
2622 - any_image (List(CoreAttrs), String url, String alternate),  
2623 - any_image (List(CoreAttrs), String url, String alternate, Int width, Int height),  
2624 - any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)),  
2625 - any_center ($T),  
2626 - any_mail_to (String email, $T element),  
2627 - any_scroller (Int width, Int height,  
2628 - Int content_width, Int content_height,  
2629 - $T content),  
2630 - any_fixed_size (HTML_Size width, HTML_Size height, $T content),  
2631 - any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),  
2632 - any_actioner (Actioner_Connection,  
2633 - Actioner_Target,  
2634 - Actioner_Aspect,  
2635 - String action_name,  
2636 - List((String,String)) extra_ops,  
2637 - List(Actioner_Local_Action),  
2638 - Maybe(String) form_name),  
2639 - any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url),  
2640 - any_foreign_link (List(Text_Option), String url),  
2641 - any_foreign_link (List(Text_Option), String url, String name),  
2642 - any_private_download (String abs_path, String name, String extra_ext,  
2643 - Maybe((String,List((String,String))))),  
2644 - any_div (List(CoreAttrs), $T element),  
2645 - any_div_empty (List(CoreAttrs)),  
2646 - any_coreattrs (List(CoreAttrs)).  
2647 -  
2648 -  
2649 -  
2650 - *** [5.2] Formating a color.  
2651 -  
2652 - RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters  
2653 - hexadecimal values.  
2654 -  
2655 -define String  
2656 - html_format  
2657 - (  
2658 - RGB color  
2659 - ) =  
2660 - if color is rgb(r,g,b) then  
2661 - "#" + to_hexa(r)  
2662 - + to_hexa(g)  
2663 - + to_hexa(b).  
2664 -  
2665 -  
2666 - The following is a very arbitrary definition of the opposite color. The thing which is  
2667 - important is that it is far from the original, so that characters in 'opposite' color  
2668 - are clearly visible over the original.  
2669 -  
2670 -define RGB  
2671 - opposite  
2672 - (  
2673 - RGB color  
2674 - ) =  
2675 - if color is rgb(r,g,b) then  
2676 - rgb(255-r,  
2677 - 255-g,  
2678 - 255-b).  
2679 -  
2680 -  
2681 -  
2682 -  
2683 - *** [5.3] Creating buttons.  
2684 -  
2685 - We want to be able to create buttons in the form of a pair of images (rollovers)  
2686 - automatically. We use the JPEG interface, because for the time being Anubis cannot  
2687 - handle other kinds of images.  
2688 -  
2689 -  
2690 - Computing printed text length.  
2691 -  
2692 - define Int  
2693 - printed_text_width  
2694 - (  
2695 - Word8 -> Int char_size,  
2696 - List(Word8) l  
2697 - ) =  
2698 - if l is  
2699 - {  
2700 - [] then (Int) 0,  
2701 - [h . t] then char_size(h) + 1+ printed_text_width(char_size,t)  
2702 - }.  
2703 -  
2704 - define Int  
2705 - printed_text_width  
2706 - (  
2707 - SystemFont font,  
2708 - String s  
2709 - ) =  
2710 - printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))),  
2711 - explode(s)).  
2712 -  
2713 -  
2714 -  
2715 - Converting RGB to RGBA.  
2716 -  
2717 -define RGBA  
2718 - to_rgba  
2719 - (  
2720 - RGB color  
2721 - ) =  
2722 - if color is rgb(r,g,b) then rgba(r,g,b,255).  
2723 -  
2724 -  
2725 - Drawing a 'relief'.  
2726 -  
2727 - define One  
2728 - draw_relief  
2729 - (  
2730 - RGBAImage dest,  
2731 - RGBA color,  
2732 - Int contrast,  
2733 - Int x,  
2734 - Int y,  
2735 - Int width,  
2736 - Int height  
2737 - ) =  
2738 - with l = lighten(color,contrast),  
2739 - d = darken(color,contrast),  
2740 - draw_rectangle(dest,rect(x,y,x+width,y+1),l);  
2741 - draw_rectangle(dest,rect(x,y+1,x+1,y+height),l);  
2742 - draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d);  
2743 - draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d).  
2744 -  
2745 -  
2746 - Creating a button background.  
2747 -  
2748 - define RGBAImage  
2749 - create_button_background  
2750 - (  
2751 - RGBA color,  
2752 - Int width,  
2753 - Int height  
2754 - ) =  
2755 - with result = create_rgba_image(width,height,color),  
2756 - draw_relief(result,color,100,0,0,width,height);  
2757 - draw_relief(result,color,70,1,1,width-2,height-2);  
2758 - draw_relief(result,color,55,2,2,width-4,height-4);  
2759 - draw_relief(result,color,35,3,3,width-6,height-6);  
2760 - draw_relief(result,color,20,4,4,width-8,height-8);  
2761 - draw_relief(result,color,10,5,5,width-10,height-10);  
2762 - draw_relief(result,color,5,6,6,width-12,height-12);  
2763 - result.  
2764 -  
2765 -  
2766 - Drawing the text over the background.  
2767 -  
2768 - define One  
2769 - draw_button_text  
2770 - (  
2771 - RGBAImage image,  
2772 - String text,  
2773 - Int text_index,  
2774 - Int pixel_x,  
2775 - Int y,  
2776 - Rectangle clip,  
2777 - RGBA color,  
2778 - SystemFont font,  
2779 - ) =  
2780 - if nth(text_index,text) is  
2781 - {  
2782 - failure then unique,  
2783 - success(c) then  
2784 - with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color),  
2785 - draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font)  
2786 - }.  
2787 -  
2788 - define One  
2789 - draw_button_text  
2790 - (  
2791 - RGBAImage image,  
2792 - String text,  
2793 - Int text_width,  
2794 - RGBA light_color,  
2795 - RGBA dark_color,  
2796 - SystemFont font  
2797 - ) =  
2798 - with image_width = width(image),  
2799 - image_height = height(image),  
2800 - x_pos = (image_width-text_width)>>1,  
2801 - clip = rect(0,0,image_width,image_height),  
2802 - new_light_color = lighten(light_color,150),  
2803 - new_dark_color = darken(dark_color,40),  
2804 - draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font);  
2805 - draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font).  
2806 -  
2807 -  
2808 - The next function creates the two images for a button. The information given is the  
2809 - main color of the button, the text of the button and the minimal width (in pixels) of  
2810 - the button. The function does not create the button if the images already exist. The  
2811 - two images are stored in the directory 'site_directory/buttons'. The names of the files  
2812 - are of the form:  
2813 -  
2814 - bxxxx_off.jpg  
2815 - bxxxx_on.jpg  
2816 -  
2817 - where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like  
2818 - 'rm'), and where 'xxxx' is created from the given informations by the formula:  
2819 -  
2820 - xxxx = web_arg_encode(sha1((color,text,width)))  
2821 -  
2822 - Hence, distinct informations give distinct file names.  
2823 -  
2824 -  
2825 - define String // returns xxxx  
2826 - create_button_images  
2827 - (  
2828 - String site_directory,  
2829 - RGBA color,  
2830 - String text,  
2831 - Int width,  
2832 - SystemFont font  
2833 - ) =  
2834 - with xxxx = web_arg_encode(sha1((color,text,width))),  
2835 - buttons_dir = site_directory+"/public/buttons",  
2836 - off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg",  
2837 - on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg",  
2838 - if file_exists(on_filepath)  
2839 - then xxxx  
2840 - else with  
2841 - text_width = printed_text_width(font,text),  
2842 - button_width = max(width,text_width+12),  
2843 - button_height = (Int)20,  
2844 - light_color = lighten(color,60),  
2845 - very_light_color = lighten(light_color,30),  
2846 - dark_color = darken(color,40),  
2847 - background_off =  
2848 - create_button_background(color,button_width,button_height),  
2849 - background_on =  
2850 - create_button_background(light_color,button_width,button_height),  
2851 -  
2852 - draw_button_text(background_off,text,text_width,very_light_color,dark_color,font);  
2853 - draw_button_text(background_on, text,text_width,very_light_color,dark_color,font);  
2854 - forget(write_image_to_JPEG_file(to_JPEG(background_off),  
2855 - off_filepath,  
2856 - 100));  
2857 - forget(write_image_to_JPEG_file(to_JPEG(background_on),  
2858 - on_filepath,  
2859 - 100));  
2860 - xxxx.  
2861 -  
2862 -  
2863 -  
2864 -  
2865 -  
2866 - *** [5.4] Formating an actioner.  
2867 -  
2868 - An actioner works as follows. Assume first that it refers to a form. When it is clicked  
2869 - upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the  
2870 - form, and submits the form, using the JavaScript command 'form_name.submit()'. If the  
2871 - actioner does not refer to a form, it fires the URL directly via 'href', because in  
2872 - that case, the actioner is always an <a> tag.  
2873 -  
2874 - The URL itself is composed using the connection sort (same, http or https), the common  
2875 - name and port number (if needed), the state name, the action name, and the extra  
2876 - operands, which are put into a query string. It may look like this:  
2877 -  
2878 - http://common_name:port/?s=state_name&a=action_name&oname=value...  
2879 -  
2880 - Each extra operand is a pair of strings: (name,value). It is formated as:  
2881 -  
2882 - &oname=value  
2883 -  
2884 -  
2885 -define String  
2886 - format_extra_operands  
2887 - (  
2888 - List((String,String)) l  
2889 - ) =  
2890 - if l is  
2891 - {  
2892 - [ ] then "",  
2893 - [h . t] then if h is (n,v) then  
2894 - "&amp;"+n+"="+v+format_extra_operands(t)  
2895 - }.  
2896 -  
2897 -  
2898 - It seams that the standard requires "&amp;" instead of "&" !  
2899 -  
2900 - In case the target is another window, we need to format the options for this window.  
2901 -  
2902 -define String  
2903 - format  
2904 - (  
2905 - List(Other_Window_Option) l  
2906 - ) =  
2907 - if l is  
2908 - {  
2909 - [ ] then "",  
2910 - [h . t] then if h is  
2911 - {  
2912 - resizable then "resizable",  
2913 - scrollbars then "scrollbars",  
2914 - width(w) then "width="+w,  
2915 - height(h2) then "height="+h2  
2916 - } + if t is [ ] then "" else (","+format(t))  
2917 - }.  
2918 -  
2919 -  
2920 -  
2921 - Formating choices for a <select> tag.  
2922 -  
2923 -public define Printable_tree  
2924 - format_choices  
2925 - (  
2926 - List(String) l  
2927 - ) =  
2928 - if l is  
2929 - {  
2930 - [ ] then [ ],  
2931 - [h . t] then ["<option>", h, "</option>\n" . format_choices(t)]  
2932 - }.  
2933 -  
2934 -  
2935 -public define Printable_tree  
2936 - format_choices  
2937 - (  
2938 - List(String) l,  
2939 - InitialValue selected  
2940 - ) =  
2941 - if l is  
2942 - {  
2943 - [ ] then [ ],  
2944 - [h . t] then if h = selected.value  
2945 - then ["<option selected=\"selected\">", h, "</option>\n" . format_choices(t)]  
2946 - else ["<option>", h, "</option>\n" . format_choices(t,selected)]  
2947 - }.  
2948 -  
2949 -  
2950 -public define Printable_tree  
2951 - format_choices  
2952 - (  
2953 - List((WebArgValue,String)) l  
2954 - ) =  
2955 - if l is  
2956 - {  
2957 - [ ] then [ ],  
2958 - [h . t] then  
2959 - if h is (val,item)  
2960 - then ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t)]  
2961 - }.  
2962 -  
2963 -public define Printable_tree  
2964 - format_choices  
2965 - (  
2966 - List((WebArgValue,String)) l,  
2967 - InitialValue selected  
2968 - ) =  
2969 - if l is  
2970 - {  
2971 - [ ] then [ ],  
2972 - [h . t] then  
2973 - if h is (val,item) then  
2974 - if val.value = selected.value  
2975 - then ["<option value=\""+val.value+"\" selected=\"selected\">", item, "</option>\n" . format_choices(t)]  
2976 - else ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t,selected)]  
2977 - }.  
2978 -  
2979 -  
2980 -  
2981 -variable Int count = 0.  
2982 -  
2983 - Note: this counter is private to the virtual machine, hence there is one counter by  
2984 - client and by page : it seems that a new VM (simply a delegate) is started for each request.  
2985 -  
2986 -define Int  
2987 - new_count  
2988 - =  
2989 - count <- *count+1;  
2990 - *count.  
2991 -  
2992 -  
2993 - The next function composes the URL. It is a JavaScript URL when the target is another  
2994 - window.  
2995 -  
2996 -define String  
2997 - make_actioner_url  
2998 - (  
2999 - CommonInfo cinfo,  
3000 - Actioner_Connection connection,  
3001 - Actioner_Target target,  
3002 - String state_name,  
3003 - String action_name,  
3004 - List((String,String)) extra_ops,  
3005 - Bool is_https  
3006 - ) =  
3007 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
3008 - with strict_url =  
3009 - if connection is  
3010 - {  
3011 - same then "/",  
3012 - http then "http://"+common_name+":"+http_port+"/",  
3013 - https then "https://"+common_name+":"+https_port+"/",  
3014 - } +  
3015 - "?a=" + action_name +  
3016 - format_extra_operands(extra_ops),  
3017 - if target is  
3018 - {  
3019 - same then strict_url,  
3020 - same(label) then strict_url+"#"+label,  
3021 - other(wn,ops) then  
3022 -  
3023 - "javascript:void window.open('"+strict_url+"&amp;t="+wn+"','"+  
3024 - "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"  
3025 - }.  
3026 -  
3027 -define String  
3028 - make_foreign_link_url  
3029 - (  
3030 - Actioner_Target target,  
3031 - String url  
3032 - ) =  
3033 - if target is  
3034 - {  
3035 - same then "/",  
3036 - same(label) then "/#"+label,  
3037 - other(wn,ops) then  
3038 -  
3039 - "javascript:void window.open('"+url+"','"+  
3040 - "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"  
3041 - }.  
3042 -  
3043 -  
3044 - Depending on the fact that the actioner refers to a form or not, the URL is used in two  
3045 - different ways. If the actioner does not refer to a form, it is realized by a '<a>'  
3046 - tag, with a 'href' attribute. If it refers to a form, it is still realized by a '<a>'  
3047 - tag, but with no href attribute. In this case, we use the 'onMouseDown' or 'onChange'  
3048 - event handler. The handler calls a JavaScript function which puts the URL as the value  
3049 - of the 'action' attribute of the form, and submits the form.  
3050 -  
3051 -type URL_or_JavaScript:  
3052 - url (String),  
3053 - javascript (Printable_tree script, Printable_tree handler).  
3054 -  
3055 -  
3056 - It was as shown below, in order to allow submission of a form from outside the form,  
3057 - but this makes problems:  
3058 -  
3059 -define URL_or_JavaScript  
3060 - format_action  
3061 - (  
3062 - String the_url,  
3063 - Actioner_Aspect aspect,  
3064 - Maybe(String) mb_id,  
3065 - Maybe(String) mb_form_name  
3066 - ) =  
3067 - if mb_form_name is  
3068 - {  
3069 - failure then  
3070 - url(the_url),  
3071 - success(form_name) then  
3072 - with n = new_count,  
3073 - fn_name = "pfu_" + if mb_id is  
3074 - {  
3075 - failure then form_name + "_" + n,  
3076 - success(id) then id,  
3077 - },  
3078 - javascript(  
3079 - [  
3080 - "<script type=\"text/javascript\" language =\"JavaScript\">\n",  
3081 - "function ", fn_name, "() {\n",  
3082 - " var fa = document.forms.",form_name,";\n",  
3083 - " var u = \"",the_url,"\";\n",  
3084 - " fa.action = u;",  
3085 - if aspect is submit(_, _) then " }\n"  
3086 - else "\n fa.submit(); }\n",  
3087 - "</script>\n"  
3088 - ],  
3089 - [fn_name,"();"]  
3090 - )  
3091 - }.  
3092 -  
3093 -  
3094 -  
3095 - Now, we format the actioner according to its aspect.  
3096 -  
3097 -define List(Text_Option)  
3098 - get_text_options  
3099 - (  
3100 - List(Text_Option) l  
3101 - )  
3102 - =  
3103 - if l is  
3104 - {  
3105 - [] then [],  
3106 - [h . t ] then  
3107 - if h is class(_) then  
3108 - get_text_options(t)  
3109 - else if h is id(_) then  
3110 - get_text_options(t)  
3111 - else if h is style(_) then  
3112 - get_text_options(t)  
3113 - else if h is title(_) then  
3114 - get_text_options(t)  
3115 - else  
3116 - [ h . get_text_options(t) ]  
3117 -  
3118 - }.  
3119 -  
3120 - /**  
3121 - * Extract the CSS class list from the list of Text_Option  
3122 - */  
3123 -define List(CoreAttrs)  
3124 - get_css_class  
3125 - (  
3126 - List(Text_Option) l  
3127 - )  
3128 - =  
3129 - if l is  
3130 - {  
3131 - [] then [],  
3132 - [h . t ] then  
3133 -  
3134 -  
3135 - if h is class(name) then  
3136 - [ class(name) . get_css_class(t) ]  
3137 - else if h is id(name) then  
3138 - [ id(name) . get_css_class(t) ]  
3139 - else if h is style(the_style) then  
3140 - [ style(the_style) . get_css_class(t) ]  
3141 - else if h is title(name) then  
3142 - [ tooltip(name) . get_css_class(t) ]  
3143 - else if h is attr(name, value) then  
3144 - [ attr(name, value) . get_css_class(t) ]  
3145 - else  
3146 - get_css_class(t)  
3147 - }  
3148 - .  
3149 -  
3150 -define Printable_tree  
3151 - format  
3152 - (  
3153 - List(Actioner_Local_Action) l  
3154 - ) =  
3155 - if l is  
3156 - {  
3157 - [ ] then [ ],  
3158 - [h . t] then [if h is  
3159 - {  
3160 - close_window then [" window.close(); "]  
3161 - }  
3162 - . format(t)]  
3163 - }.  
3164 -  
3165 -public define String  
3166 - format_attrs  
3167 - (  
3168 - List(CoreAttrs) attributs  
3169 - )=  
3170 - if attributs is  
3171 - {  
3172 - [] then "",  
3173 - [h . t] then  
3174 - with current = if h is  
3175 - {  
3176 - id(id_name) then  
3177 - " id=\"" + id_name + "\"",  
3178 - class(class_name) then  
3179 - " class=\"" + class_name + "\"",  
3180 - style(style_string) then  
3181 - " style=\"" + style_string + "\"",  
3182 -  
3183 - title(title_string) then  
3184 - " title=\"" + title_string + "\"",  
3185 -  
3186 - lang(lang) then  
3187 - " xml:lang=" + lang,  
3188 - dir(reading_Way) then  
3189 - if reading_Way is  
3190 - {  
3191 - ltr then " dir=ltr",  
3192 - rtl then " dir=rtl"  
3193 - },  
3194 -  
3195 - accesskey(key) then  
3196 - " accesskey=\"" + key + "\"",  
3197 - tabindex(index) then  
3198 - " tabindex=\"" + index + "\"",  
3199 -  
3200 - attr(name, value) then  
3201 - " " + name + "=\"" + value + "\"",  
3202 -  
3203 - event(e, value) then  
3204 - " " + event_name(e) + "=\"" + value + "\"",  
3205 - },  
3206 - current + format_attrs(t)  
3207 - }.  
3208 -  
3209 -define String  
3210 - format_attrs  
3211 - (  
3212 - List(InputAttrs) attributs  
3213 - )=  
3214 - if attributs is  
3215 - {  
3216 - [] then "",  
3217 - [h . t] then  
3218 - with current = if h is  
3219 - {  
3220 - class(class_name) then  
3221 - " class=\"" + class_name + "\"",  
3222 - style(style_string) then  
3223 - " style=\"" + style_string + "\"",  
3224 -  
3225 - title(title_string) then  
3226 - " title=\"" + title_string + "\"",  
3227 -  
3228 - lang(lang) then  
3229 - " xml:lang=" + lang,  
3230 - dir(reading_Way) then  
3231 - if reading_Way is  
3232 - {  
3233 - ltr then " dir=ltr",  
3234 - rtl then " dir=rtl"  
3235 - },  
3236 -  
3237 - accesskey(key) then  
3238 - " accesskey=\"" + key + "\"",  
3239 - tabindex(index) then  
3240 - " tabindex=\"" + index + "\"",  
3241 -  
3242 - attr(name, value) then  
3243 - " " + name + "=\"" + value + "\"",  
3244 -  
3245 - event(e, value) then  
3246 - " " + event_name(e) + "=\"" + value + "\"",  
3247 - },  
3248 - current + format_attrs(t)  
3249 - }.  
3250 -  
3251 -define String  
3252 - format_text_options  
3253 - (  
3254 - List(Text_Option) l  
3255 - )  
3256 - =  
3257 - with text_options = get_text_options(l),  
3258 - css_classes = get_css_class(l),  
3259 - if text_options is  
3260 - {  
3261 - [] then "",  
3262 - [_ . _] then " style=\"" + format(text_options) + "\" "  
3263 - }  
3264 - +  
3265 - if css_classes is  
3266 - {  
3267 - [] then "",  
3268 - [_ . _] then format_attrs(css_classes)  
3269 - }.  
3270 -  
3271 -//define String  
3272 -// _format  
3273 -// (  
3274 -// List(CoreAttrs) opt  
3275 -// )=  
3276 -// if opt is  
3277 -// {  
3278 -// [] then "",  
3279 -// [h .t] then  
3280 -// with current = if h is  
3281 -// {  
3282 -// id(id_name) then  
3283 -// " id=\"" + id_name + "\"",  
3284 -// class(class_name) then  
3285 -// " class=\"" + class_name + "\"",  
3286 -// style(style_string) then  
3287 -// " style=\"" + style_string + "\"",  
3288 -//  
3289 -// title(title_string) then  
3290 -// " title=\"" + title_string + "\"",  
3291 -// lang(lang) then  
3292 -// " xml:lang=" + lang,  
3293 -// dir(reading_Way) then  
3294 -// if reading_Way is  
3295 -// {  
3296 -// ltr then " dir=ltr",  
3297 -// rtl then " dir=rtl"  
3298 -// },  
3299 -// attr(name, value) then  
3300 -// " " + name + "=\"" + value + "\"",  
3301 -// event(e, value) then  
3302 -// " " + event_name(e) + "=\"" + value + "\""  
3303 -// },  
3304 -// current + _format(t)  
3305 -// }  
3306 -// .  
3307 -  
3308 -define Printable_tree  
3309 - format_div_option  
3310 - (  
3311 - List(CoreAttrs) options  
3312 - )=  
3313 - ["<div" + format_attrs(options) + ">"] .  
3314 -  
3315 -  
3316 -define Maybe(String)  
3317 - extract_id  
3318 - (  
3319 - List(CoreAttrs) attrbs  
3320 - ) =  
3321 - if attrbs is  
3322 - {  
3323 - [] then failure,  
3324 - [h . t] then  
3325 - if h is id(value) then success(value)  
3326 - else extract_id(t)  
3327 - }.  
3328 -  
3329 -define Maybe(String)  
3330 - extract_id  
3331 - (  
3332 - Actioner_Aspect aspect  
3333 - ) =  
3334 - if aspect is  
3335 - {  
3336 - link(_,_,_) then failure,  
3337 - img_link(_,_) then failure,  
3338 - push_button(opts,_) then extract_id(opts),  
3339 - button(_,_) then failure,  
3340 - button(_,_,_,_) then failure,  
3341 - submit(opts,_) then extract_id(opts),  
3342 - immediate_selector(_,_,_,_) then failure,  
3343 - immediate_selector(_,_,_,_,_) then failure,  
3344 - }.  
3345 -  
3346 -to do Complete format_foreign_link  
3347 -//TODO Complete format_foreign_link  
3348 -define Printable_tree  
3349 - format_foreign_link  
3350 - (  
3351 -// CommonInfo cinfo,  
3352 - Actioner_Target target,  
3353 - Actioner_Aspect aspect,  
3354 - String url,  
3355 - Bool is_https,  
3356 - ) =  
3357 - //if cinfo is info(common_name,http_port,https_port,site_dir,secret) then  
3358 - with full_url = make_foreign_link_url(target,url),  
3359 -// with action = format_action(full_url, aspect, extract_id(aspect), mb_form_name),  
3360 - if aspect is  
3361 - {  
3362 -  
3363 - link(opt, text, mb_name) then  
3364 - with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",  
3365 - [  
3366 - "<a href=\"", full_url, "\"", format_text_options(opt), name_tag, ">",  
3367 - text,  
3368 - "</a>"  
3369 - ],  
3370 - img_link(img,alt_text) then  
3371 - [  
3372 - "<a href=\"", full_url ,"\"><img src=\"", img,  
3373 - "\" alt=\"" + alt_text + "\" border=\"0\"></a>"  
3374 - ],  
3375 - push_button(options, text) then  
3376 - ["<a href=\"",full_url,"\"", format_attrs(options), ">",  
3377 - text, "</a>"  
3378 - ],  
3379 - button(url_off,url_on) then  
3380 - [ ],  
3381 -  
3382 - button(url_off,url_on,w,h) then  
3383 - [ ],  
3384 -  
3385 - submit(options, text) then  
3386 - [ ],  
3387 -  
3388 - immediate_selector(opt,name,size,choices) then  
3389 - [ ],  
3390 - immediate_selector(opt,name,size,choices,selected) then  
3391 - [ ],  
3392 - }.  
3393 -  
3394 -define Printable_tree  
3395 - format_actioner  
3396 - (  
3397 - CommonInfo cinfo,  
3398 - String state_name,  
3399 - Actioner_Connection connection,  
3400 - Actioner_Target target,  
3401 - Actioner_Aspect aspect,  
3402 - String action_name,  
3403 - List((String,String)) extra_ops,  
3404 - List(Actioner_Local_Action) local_actions,  
3405 - Maybe(String) mb_form_name,  
3406 - Bool is_https,  
3407 - ) =  
3408 - if cinfo is info(common_name,http_port,https_port,site_dir,secret) then  
3409 - with url = make_actioner_url(cinfo,connection,target,  
3410 - state_name,action_name,extra_ops,is_https),  
3411 - with action = format_action(url, aspect, extract_id(aspect), mb_form_name),  
3412 - if aspect is  
3413 - {  
3414 -  
3415 - link(opt, text, mb_name) then  
3416 - with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",  
3417 - [  
3418 - "<a href=\"", url, "\"", format_text_options(opt), name_tag, ">",  
3419 - text,  
3420 - "</a>"  
3421 - ],  
3422 - img_link(img, alt_text) then  
3423 - [  
3424 - "<a href=\"", url ,"\"><img src=\"", img,  
3425 - "\" alt=\"" + alt_text + "\" border=\"0\"></a>"  
3426 - ],  
3427 - push_button(options, text) then  
3428 - [  
3429 - if action is  
3430 - {  
3431 - url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",  
3432 - text, "</a>"  
3433 - ],  
3434 - javascript(s,h) then  
3435 - if action_name = "" then  
3436 - ["<input type=\"button\" value=\"",text,"\"", format_attrs(options), " />"]  
3437 - else  
3438 - [s,"<input type=\"button\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]  
3439 - }  
3440 - ],  
3441 - button(url_off,url_on) then  
3442 - [ if action is  
3443 - {  
3444 - url(u) then ["<a href=\"",u],  
3445 - javascript(s,h) then [s,"<a onMouseDown=\"",h]  
3446 - },  
3447 - "\" style=\"text-decoration:none\">",  
3448 - "<img alt=\"",url_off,"\" src=\"",url_off,"\" border=0",  
3449 - " onMouseOver=\"this.src='",url_on,"'\" ",  
3450 - " onMouseOut=\"this.src='",url_off,"'\">",  
3451 - "</a>"  
3452 - ],  
3453 -  
3454 - button(url_off,url_on,w,h) then  
3455 - [ if action is  
3456 - {  
3457 - url(u) then ["<a href=\"",u],  
3458 - javascript(s,h2) then [s,"<a onMouseDown=\"",h2]  
3459 - },  
3460 - "\" style=\"text-decoration:none\">",  
3461 - "<img width=",w," height=",h," alt=\"",url_off,"\" src=\"",url_off,"\" border=0",  
3462 - " onMouseOver=\"this.src='",url_on,"'\" ",  
3463 - " onMouseOut=\"this.src='",url_off,"'\">",  
3464 - "</a>"  
3465 - ],  
3466 -  
3467 - submit(options, text) then  
3468 - [  
3469 - if action is  
3470 - {  
3471 - url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",  
3472 - text, "</a>"  
3473 - ],  
3474 - javascript(s,h) then  
3475 - if action_name = "" then // special case where URL (so the action_name) is provided by the form itself  
3476 - // so javascript isn't needed. This is the standard HMTL way.  
3477 - ["<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " />"]  
3478 - else  
3479 - [s,"<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]  
3480 - }  
3481 - ],  
3482 -  
3483 - immediate_selector(options,name,size,choices) then  
3484 - [ if action is  
3485 - {  
3486 - url(u) then ["<select href=\"",u]  
3487 - javascript(s,h) then [s,"<select onchange=\"",h]  
3488 - },  
3489 - "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",  
3490 - format_choices(choices),"</select>"  
3491 - ],  
3492 - immediate_selector(options,name,size,choices,selected) then  
3493 - [ if action is  
3494 - {  
3495 - url(u) then ["<select href=\"",u]  
3496 - javascript(s,h) then [s,"<select onchange=\"",h]  
3497 - },  
3498 - "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",  
3499 - format_choices(choices, selected),"</select>"  
3500 - ],  
3501 - }.  
3502 -  
3503 -  
3504 -  
3505 -  
3506 -  
3507 -  
3508 - *** [5.5] Formating a private download link.  
3509 -  
3510 - We get the absolute path of the file to be downloaded, and the name under which it  
3511 - should appear to the client. The function 'format_private_download' creates an  
3512 - hypertext link for downloading the file. The secured mecanism of private download is  
3513 - used. This function is called by the function which formats HTML_Any($T) elements.  
3514 -  
3515 -  
3516 -define Printable_tree  
3517 - format_private_download  
3518 - (  
3519 - CommonInfo cinfo,  
3520 - String sn, // state name  
3521 - String abs_path, // absolute file path on server  
3522 - String name, // name of file as it appears in the browser  
3523 - String extra, // extra extension  
3524 - Maybe((String,List((String,String)))) action  
3525 -  
3526 - ) =  
3527 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
3528 - with private_download_directory = site_directory+"/private_download",  
3529 - with auth = make_authorization(site_directory,secret,abs_path),  
3530 - [  
3531 - "<a href=\"",name,extra,"?zauth=",auth,  
3532 - if action is  
3533 - {  
3534 - failure then [ ]  
3535 - success(a) then if a is (an,args) then  
3536 - ["&amp;a=",an,format_extra_operands(args)]  
3537 - },  
3538 - "\">",  
3539 - name,  
3540 - "</a>"  
3541 - ].  
3542 -  
3543 -  
3544 -  
3545 -  
3546 - *** [5.6] Formating rows and cells in a table.  
3547 -  
3548 -define Int  
3549 - percent  
3550 - (  
3551 - Int p  
3552 - ) =  
3553 - if p < 0 then 0 else if p > 100 then 100 else p.  
3554 -  
3555 -  
3556 -  
3557 -  
3558 - Formating cell options.  
3559 -  
3560 -  
3561 -  
3562 -define String  
3563 - format  
3564 - (  
3565 - BackgroundOption o  
3566 - ) =  
3567 - if o is  
3568 - {  
3569 - repeat then "",  
3570 - repeat_horizontal then "; background-repeat: repeat-x",  
3571 - repeat_vertical then "; background-repeat: repeat-y",  
3572 - no_repeat then "; background-repeat: no-repeat",  
3573 - center then "; background-position: center top"  
3574 - }.  
3575 -  
3576 -define String  
3577 - format  
3578 - (  
3579 - List(BackgroundOption) l  
3580 - ) =  
3581 - if l is  
3582 - {  
3583 - [ ] then "",  
3584 - [h . t] then format(h)+format(t)  
3585 - }.  
3586 -  
3587 -  
3588 -define String  
3589 - format  
3590 - (  
3591 - List(Cell_Option) options  
3592 - ) =  
3593 - if options is  
3594 - {  
3595 - [ ] then "",  
3596 - [h . t] then  
3597 - if h is  
3598 - {  
3599 - core_attrs(core_attr_list) then format_attrs(core_attr_list),  
3600 - left then " align=\"left\"",  
3601 - h_center then " align=\"center\"",  
3602 - right then " align=\"right\"",  
3603 - top then " valign=\"top\"",  
3604 - v_center then " valign=\"middle\"",  
3605 - bottom then " valign=\"bottom\"",  
3606 - base_line then " valign=\"baseline\"",  
3607 - background_color(c) then " bgcolor=\""+html_format(c)+"\"",  
3608 - background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"",  
3609 - width(w) then " width=\""+w+"\"",  
3610 - percentage_width(n) then " width=\""+percent(n)+"%\"",  
3611 - height(h2) then " height=\""+h2+"\"",  
3612 - columns(n) then " colspan=\""+n+"\"",  
3613 - rows(n) then " rowspan=\""+n+"\"",  
3614 - nowrap then " nowrap",  
3615 - class(class_name) then " class=\""+class_name+"\""  
3616 - }  
3617 - + format(t)  
3618 - }.  
3619 -  
3620 -  
3621 - Normalizing a list of cell options (horizontal position must be specified; the default  
3622 - is 'left').  
3623 -  
3624 - Formating cells in a row.  
3625 -  
3626 -define Printable_tree  
3627 - format  
3628 - (  
3629 - List(HTML_Cell($T)) cells,  
3630 - $T -> Printable_tree format_element  
3631 - ) =  
3632 - if cells is  
3633 - {  
3634 - [ ] then [ ],  
3635 - [h . t] then if h is cell(options,element) then  
3636 - ["<td",format(reverse(options)),">",  
3637 - format_element(element),  
3638 - "</td>"  
3639 - . format(t,format_element)]  
3640 - }.  
3641 -  
3642 -define Printable_tree  
3643 - format  
3644 - (  
3645 - List(HTML_Header_Cell($T)) cells,  
3646 - $T -> Printable_tree format_element  
3647 - ) =  
3648 - if cells is  
3649 - {  
3650 - [ ] then [ ],  
3651 - [h . t] then if h is header_cell(options,element) then  
3652 - ["<th ",format(reverse(options)),">",  
3653 - format_element(element),  
3654 - "</th>"  
3655 - . format(t,format_element)]  
3656 - }.  
3657 -  
3658 - Formating the rows in a table.  
3659 -  
3660 -define Printable_tree  
3661 - format  
3662 - (  
3663 - List(HTML_Row($T)) rows,  
3664 - $T -> Printable_tree format_element,  
3665 - ) =  
3666 - if rows is  
3667 - {  
3668 - [ ] then [ ],  
3669 - [h . t] then if h is row(options,cells) then  
3670 - ["<tr",format(reverse(options)),">",  
3671 - format(cells,format_element),  
3672 - "</tr>\n"  
3673 - . format(t,format_element)]  
3674 - }.  
3675 -  
3676 -define Printable_tree  
3677 - format  
3678 - (  
3679 - HTML_Header_Row($T) row,  
3680 - $T -> Printable_tree format_element  
3681 - ) =  
3682 - if row is  
3683 - {  
3684 - empty then [ ],  
3685 - header_row(options,cells) then  
3686 - ["<thead> <tr",format(reverse(options)),">",  
3687 - format(cells,format_element),  
3688 - "</tr> </thead>\n"  
3689 - ]  
3690 - }.  
3691 -  
3692 -define Printable_tree  
3693 - format  
3694 - (  
3695 - HTML_Footer_Row($T) row,  
3696 - $T -> Printable_tree format_element  
3697 - ) =  
3698 - if row is  
3699 - {  
3700 - empty then [ ],  
3701 - footer_row(options,cells) then  
3702 - ["<tfoot> <tr",format(reverse(options)),">",  
3703 - format(cells,format_element),  
3704 - "</tr> </tfoot>\n"  
3705 - ]  
3706 - }.  
3707 -  
3708 -define Printable_tree  
3709 - format1  
3710 - (  
3711 - List(TextAreaOption) l  
3712 - ) =  
3713 - if l is  
3714 - {  
3715 - [] then [],  
3716 - [h . t] then if h is  
3717 - {  
3718 - input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)],  
3719 - disabled then [" disabled=\"disabled\" " . format1(t)]  
3720 - read_only then [" readonly=\"readonly\" " . format1(t)]  
3721 - wrap_lines then [" wrap=\"wrap\" " . format1(t)]  
3722 - }  
3723 - }.  
3724 -  
3725 -define Printable_tree  
3726 - format  
3727 - (  
3728 - List(TextAreaOption) l  
3729 - ) =  
3730 - if member(l,wrap_lines)  
3731 - then format1(l)  
3732 - else [" wrap=\"off\" " . format1(l)].  
3733 -  
3734 -  
3735 - *** [5.7] Formating elements which may be put anywhere.  
3736 -  
3737 - The function below involves the parameter $T which is later instantiated as  
3738 - 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions  
3739 - for these two types, and because formating of tables requires recursive calls of such  
3740 - functions, it is necessary to provide the 'format' function to be called recursively as  
3741 - an argument. Putting naively a call to 'format' will not work, because the compiler  
3742 - will look for a function able to format data of type $T (which is at that time distinct  
3743 - from any other type, including our two types). Such a function does not exist. Hence  
3744 - the function to be called for formating elements must be passed as a functional  
3745 - argument (called 'format_element' below). Actually, what we pass is a function taking  
3746 - a unique argument of type $T. Other informations (like the name of the state) are  
3747 - already in the function by way of full functionality.  
3748 -  
3749 -  
3750 - Formating text options. They are formated in CSS syntax, to be used within a  
3751 - 'style=...'.  
3752 -  
3753 -define String  
3754 - format  
3755 - (  
3756 - List(Text_Option) l  
3757 - ) =  
3758 - if l is  
3759 - {  
3760 - [ ] then "",  
3761 - [h . t] then if h is  
3762 - {  
3763 - size(n) then "font-size:"+n+"pt",  
3764 - font(fn) then "font-family:"+fn,  
3765 - color(c) then if c is rgb(r,g,b) then  
3766 - "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")",  
3767 - italic then "font-style:italic",  
3768 - oblique then "font-style:oblique",  
3769 - small_capitals then "font-variant:small-caps",  
3770 - bold then "font-weight:bold",  
3771 - underlined then "text-decoration:underline",  
3772 - left_justified then "text-align:left",  
3773 - right_justified then "text-align:right",  
3774 - justified then "text-align:justify",  
3775 - line_through then "text-decoration:line-through",  
3776 - nowrap then "white-space:nowrap",  
3777 - class(class_name)then " class=\"" + class_name +"\"",  
3778 - id(id_name) then " id=\"" + id_name +"\"",  
3779 - style(style_string) then " style=\"" + style_string + "\"",  
3780 - title(s) then " title=\"" + s +"\""  
3781 - attr(n,v) then " " + n + "=\"" + v +"\""  
3782 - } + if t is [ ] then "" else ("; "+format(t))  
3783 - }.  
3784 -  
3785 -  
3786 -  
3787 - Formating table options.  
3788 -  
3789 -define String  
3790 - format  
3791 - (  
3792 - List(Table_Option) l,  
3793 - Bool border_seen  
3794 - ) =  
3795 - if l is  
3796 - {  
3797 - [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"",  
3798 - [h . t] then if h is  
3799 - {  
3800 - background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen),  
3801 - background_image(url) then " background="+url+format(t,border_seen),  
3802 - border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+  
3803 - //" bordercolor="+format(c)+  
3804 - format(t,true),  
3805 - width(w) then " width=\""+w+"\""+format(t,border_seen),  
3806 - percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen),  
3807 - attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen),  
3808 - class(name) then " class=\""+name+"\""  
3809 - }  
3810 - }.  
3811 -  
3812 -  
3813 -  
3814 -  
3815 -  
3816 -define Printable_tree  
3817 - format_scroller  
3818 - (  
3819 - String sn,  
3820 - Int width,  
3821 - Int height,  
3822 - Int content_width,  
3823 - Int content_height,  
3824 - Int idnum, // identifying the scroller  
3825 - $T content,  
3826 - $T -> Printable_tree format_element  
3827 - ) =  
3828 - [  
3829 - "<script type = \"text/javascript\" language=\"JavaScript\">",  
3830 - "function doscroll_",idnum,"(dx,dy) {\n",  
3831 - " if (document.layers) { var c_",idnum," = eval(document.cs_",idnum,"); } else\n",  
3832 - " if (document.getElementById) {var c_",idnum," = eval(\"document.getElementById('cs_",  
3833 - idnum,"').style\"); } else\n",  
3834 - " if (document.all) { var c_",idnum," = eval(document.all.cs_",idnum,".style); };\n",  
3835 - " var x_",idnum," = parseInt(c_",idnum,".left);\n",  
3836 - " var y_",idnum," = parseInt(c_",idnum,".top);\n",  
3837 - " if ((x_",idnum,"+dx <= 0) && (x_",idnum,"+dx > ",width-content_width,"))\n",  
3838 - " { x_",idnum," += dx; }\n",  
3839 - " if ((y_",idnum,"+dy <= 0) && (y_",idnum,"+dy > ",height-content_height,"))\n",  
3840 - " { y_",idnum," += dy; }\n",  
3841 - " c_",idnum,".left = x_",idnum,";\n",  
3842 - " c_",idnum,".top = y_",idnum,";\n",  
3843 - " }\n",  
3844 - "</script>\n",  
3845 - "<table>",  
3846 - "<tbody>",  
3847 - "<tr>",  
3848 - "<td align=left valign=top",  
3849 - " width=",width,  
3850 - " height=",height,  
3851 - ">",  
3852 - "<div id=\"ws_",idnum,"\" style=\"position:absolute; width:",width,"px; height:",height,"px;",  
3853 - " clip:rect(0px ",width,"px ",height,"px 0px)\">",  
3854 - "<div id=\"cs_",idnum,"\" style=\"position:absolute; left:0px; top:0px\">",  
3855 - format_element(content),  
3856 - "</div>",  
3857 - "</div>",  
3858 - "</td>",  
3859 - "<td valign=bottom>",  
3860 - "<table>",  
3861 - "<tbody>",  
3862 - "<tr><td><img alt=\"sroll up\" src=\"scrollup.gif\" onmousedown=\"doscroll_", idnum,"(0,20);\"></td></tr>",  
3863 - "<tr><td><img alt=\"scroll down\" src=\"scrolldown.gif\" onmousedown=\"doscroll_", idnum,"(0,-20);\"></td></tr>",  
3864 - "</tbody>",  
3865 - "</table>",  
3866 - "</td>",  
3867 - "</tr>",  
3868 - (if content_width > width then  
3869 - [  
3870 - "<tr>",  
3871 - "<td align=right>",  
3872 - "<table>",  
3873 - "<tbody>",  
3874 - "<tr>",  
3875 - "<td><img alt=\"scroll left\" src=\"scrollleft.gif\" onmousedown=\"doscroll_", idnum,"(20,0);\"></td>",  
3876 - "<td><img alt=\"scroll right\" src=\"scrollright.gif\" onmousedown=\"doscroll_", idnum,"(-20,0);\"></td>",  
3877 - "</tr>",  
3878 - "</tbody>",  
3879 - "</table>",  
3880 - "</td>",  
3881 - "</tr>",  
3882 - ] else [ ]),  
3883 - "</tbody>",  
3884 - "</table>"  
3885 - ].  
3886 -  
3887 -  
3888 -  
3889 -define Printable_tree  
3890 - format  
3891 - (  
3892 - Body_Option o  
3893 - ) =  
3894 - if o is  
3895 - {  
3896 - core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)],  
3897 - background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""],  
3898 - background_image(n) then [" background=", n],  
3899 - background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""]  
3900 -  
3901 - }.  
3902 -  
3903 -  
3904 -  
3905 -define Printable_tree  
3906 - format  
3907 - (  
3908 - List(Body_Option) l  
3909 - ) =  
3910 - if l is  
3911 - {  
3912 - [ ] then [ ],  
3913 - [h . t] then [format(h) . format(t)]  
3914 - }.  
3915 -  
3916 -define Printable_tree  
3917 - add_css_files  
3918 - (  
3919 - List(CSS_File) l  
3920 - ) =  
3921 - if l is  
3922 - {  
3923 - [ ] then [ ],  
3924 - [h . t] then  
3925 - [ ["<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file_name(h) + "\" />\n" ]  
3926 - . add_css_files(t)]  
3927 - }.  
3928 -  
3929 -define Printable_tree  
3930 - add_js_files_attributes  
3931 - (  
3932 - List(JS_Attribute) l  
3933 - ) =  
3934 - if l is  
3935 - {  
3936 - [ ] then [ ],  
3937 - [h . t] then  
3938 - if h is attr(name, value) then  
3939 - [ " " + name + "=\"" + value + "\""  
3940 - . add_js_files_attributes(t)]  
3941 - }.  
3942 -  
3943 -  
3944 -define Printable_tree  
3945 - add_js_files  
3946 - (  
3947 - List(JS_File) l  
3948 - ) =  
3949 - if l is  
3950 - {  
3951 - [ ] then [ ],  
3952 - [h . t] then  
3953 - [ ["<script src=\""+ file_name(h) +"\" type=\"text/javascript\""  
3954 - . add_js_files_attributes(attributes(h)) ]  
3955 - . ["></script>\n"  
3956 - . add_js_files(t)] ]  
3957 - }.  
3958 -  
3959 -define Printable_tree  
3960 - add_script  
3961 - (  
3962 - List(Script) l  
3963 - ) =  
3964 - if l is  
3965 - {  
3966 - [ ] then [ ],  
3967 - [h . t] then [ "<script type=\""+ script_type(h) +"\">\n"+ content(h) + "\n</script>\n" . add_script(t) ]  
3968 - }.  
3969 -  
3970 -define Printable_tree  
3971 - add_css_styles  
3972 - (  
3973 - List(CSS_Style) css_styles  
3974 - ) =  
3975 -  
3976 - if css_styles is  
3977 - {  
3978 - [] then [],  
3979 - [_ . _] then [ "<style type=\"text/css\"><!--\n",  
3980 - format_css_styles(css_styles),  
3981 - " --></style>\n"  
3982 - ]  
3983 - }.  
3984 -  
3985 -  
3986 - // The function below formats a datum of type 'HTML_Any($T)'.  
3987 -  
3988 -define Printable_tree  
3989 - format  
3990 - (  
3991 - CommonInfo cinfo,  
3992 - String sn, // state_name  
3993 - Var(Int) ic_v,  
3994 - HTML_Any($T) element,  
3995 - $T -> Printable_tree format_element, // able to format a datum of type $T  
3996 - Bool is_https,  
3997 - ) =  
3998 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
3999 - if element is  
4000 - {  
4001 - any_text(opts , t) then  
4002 - if opts is  
4003 - {  
4004 - [] then [t],  
4005 - [_ . _] then ["<span", format_text_options(opts), ">",t,"</span>"]  
4006 - },  
4007 - any_preformated(opts,s) then  
4008 - ["<span", format_text_options(opts), "><pre>",s,"</pre></span>"],  
4009 - //["<pre>",s,"</pre>"],  
4010 - any_paragraph(opts,e) then  
4011 - ["<p", format_text_options(opts), ">",format_element(e),"</p>\n"],  
4012 - any_image(opts, url, alt) then  
4013 - ["<img alt=\"",alt,"\" src=\"",url,"\" ", format_attrs(opts)," />"],  
4014 - any_image(opts, url, alt, w, h) then  
4015 - ["<img alt=\"",alt,"\" src=\"",url,"\" width=\"",w,"\" height=\"",h,"\" ", format_attrs(opts)," />"],  
4016 - any_table(opts,h_row, rows, f_row) then  
4017 - ["<table",format(reverse(opts),false),">",  
4018 - format(h_row, format_element),  
4019 - "<tbody>",format(rows,format_element),"</tbody>",  
4020 - format(f_row, format_element),  
4021 - "</table>\n"],  
4022 - any_center(e) then  
4023 - ["<center>",format_element(e),"</center>"],  
4024 - any_mail_to(email,elem) then  
4025 - ["<a href=\"mailto:",email,"\">",format_element(elem),"</a>"],  
4026 - any_scroller(w,h,cw,ch,c) then  
4027 - format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element),  
4028 - any_fixed_size(w,h,c) then  
4029 - with url = create_secondary_document(site_directory,secret,sn,format_element,c,w),  
4030 - ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",  
4031 - "secondary document",  
4032 - "</object>"],  
4033 - any_fixed_size_2(w,h,fn) then  
4034 - with url = fn+"?zauth="+make_authorization(site_directory,secret,  
4035 - fn),  
4036 - ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",  
4037 - "secondary document",  
4038 - "</object>"],  
4039 - any_actioner(c,t,a,an,eo,ja,fn) then  
4040 - format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https),  
4041 -  
4042 - any_foreign_link_new(target, aspect, url) then  
4043 - format_foreign_link(target, aspect, url, is_https),  
4044 -  
4045 - any_foreign_link(options,url) then  
4046 - ["<a href=\"",url,"\" ", format_text_options(options), "></a>"], // IE7 doesn't support the form <a href="..." />  
4047 - any_foreign_link(options,url,name) then  
4048 - ["<a href=\"",url,"\"><span ", format_text_options(options), ">",name,"</span></a>"],  
4049 - any_private_download(url,name,extra_ext,action) then  
4050 - format_private_download(cinfo,sn,url,name,extra_ext,action),  
4051 - any_div(options, e) then  
4052 - [format_div_option(options), format_element(e),"</div>\n"],  
4053 - any_div_empty(options) then  
4054 - [format_div_option(options), "</div>\n"],  
4055 - any_coreattrs(attributs) then  
4056 - [format_attrs(attributs)]  
4057 - }.  
4058 -  
4059 -  
4060 -  
4061 -  
4062 - // *** [5.8] Formating 'in form' elements.  
4063 -  
4064 -  
4065 -define Printable_tree  
4066 - maybe_label  
4067 - (  
4068 - String label_text,  
4069 - HtmlId id  
4070 - ) =  
4071 - if length(label_text) > 0 then ["<label for=\"",id,"\">",label_text,"</label>"]  
4072 - else [].  
4073 -  
4074 -  
4075 -define Printable_tree  
4076 - format  
4077 - (  
4078 - CommonInfo cinfo,  
4079 - String fn, // form_name  
4080 - String sn, // state_name  
4081 - Var(Int) ic_v, // idnum counter variable  
4082 - HTML_In_Form element,  
4083 - Bool is_https,  
4084 - ) =  
4085 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4086 - with format_element = (HTML_In_Form e) |-> format(cinfo,fn,sn,ic_v,e,is_https),  
4087 - if element is  
4088 - {  
4089 - literal_pt(t) then t,  
4090 - literal(t) then [t],  
4091 - sequence(l) then flat(map(format_element,l))  
4092 - text(opts,t) then  
4093 - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https),  
4094 - preformated(o,s) then  
4095 - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https),  
4096 - paragraph(opts,t) then  
4097 - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https),  
4098 - image(opts, url, alt) then  
4099 - format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https),  
4100 - image(opts, url, alt, w, h) then  
4101 - format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https),  
4102 - table(opts,header_row,rows,footer_row) then  
4103 - format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https),  
4104 - center(e) then  
4105 - format(cinfo,sn,ic_v,any_center(e),format_element,is_https),  
4106 - mail_to(a,e) then  
4107 - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https),  
4108 - scroller(w,h,cw,ch,c) then  
4109 - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https),  
4110 - actioner(c,t,a,an,eo,ja) then  
4111 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https),  
4112 -  
4113 - foreign_link_new(target, aspect, url) then  
4114 - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https),  
4115 -  
4116 - foreign_link(options,url) then  
4117 - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https),  
4118 - foreign_link(options,url,name) then  
4119 - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https),  
4120 - private_download(url,name,extra,action) then  
4121 - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https),  
4122 - text_input(options, label_text, id, name, i, w) then  
4123 - [ maybe_label(label_text, id),  
4124 - "<input type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4125 - text_input_ro(options, label_text, id, name,i,w) then  
4126 - [ maybe_label(label_text, id),  
4127 - "<input readonly=\"readonly\" type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4128 - password_input(options, label_text, id, name,i,w) then  
4129 - [ maybe_label(label_text, id),  
4130 - "<input type=\"password\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],  
4131 - text_area(opts,label_text, id, n,i,w,h) then  
4132 - [ maybe_label(label_text, id), "<textarea ",format(opts)," id=\"",id,"\" name=\"",n,"\" cols=\"",w,"\" rows=\"",h,"\">",i,"</textarea>"],  
4133 - file_upload(options, label, id, n, w) then  
4134 - [ maybe_label(label, id),  
4135 - "<input type=\"file\" id=\"",id,"\" size=\"",w,"\" name=\"",n,"\"",format_attrs(options)," />"],  
4136 - selector(opts, label, id, n,s,cs) then  
4137 - [ maybe_label(label, id),  
4138 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],  
4139 - selector(opts, label, id, n,s,cs,sd) then  
4140 - [ maybe_label(label, id),  
4141 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],  
4142 - selector_c(opts, label, id, n,s,cs) then  
4143 - [ maybe_label(label, id),  
4144 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],  
4145 - selector_c(opts, label, id, n,s,cs,sd) then  
4146 - [ maybe_label(label, id),  
4147 - "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],  
4148 -  
4149 - radio_button(options, label_text, id, n, v, c) then  
4150 - [ maybe_label(label_text, id),  
4151 - "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />"],  
4152 - radio_button_r(options, label_text, id, n, v, c) then  
4153 - [ "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />",  
4154 - maybe_label(label_text, id)],  
4155 - check_box(options, label_text, id, n, v, c) then  
4156 - [ maybe_label(label_text, id),  
4157 - "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />"]  
4158 - check_box_r(options, label_text, id, n, v, c) then  
4159 - [ "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />",  
4160 - maybe_label(label_text, id)]  
4161 - div(options, e) then  
4162 - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https),  
4163 - div_empty(options) then  
4164 - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https),  
4165 - hidden(id, name, value) then  
4166 - ["<input type=\"hidden\" id=\"",id,"\" name=\"",name,"\" value=\"",value,"\" />"],  
4167 -  
4168 - }.  
4169 -  
4170 -  
4171 -  
4172 -  
4173 -  
4174 -  
4175 - *** [5.9] Formating 'off form' elements.  
4176 -  
4177 - The encryption type 'multipart/form-data' is required for a form containing an upload.  
4178 -  
4179 -  
4180 -define Bool  
4181 - contains_an_upload  
4182 - (  
4183 - HTML_In_Form form_content  
4184 - ).  
4185 -  
4186 -define Bool  
4187 - contains_an_upload  
4188 - (  
4189 - HTML_Row(HTML_In_Form) row  
4190 - ) =  
4191 - mapor(contains_an_upload,  
4192 - map(content,cells(row))).  
4193 -  
4194 -define Bool  
4195 - contains_an_upload  
4196 - (  
4197 - HTML_Footer_Row(HTML_In_Form) row  
4198 - ) =  
4199 - if row is  
4200 - {  
4201 - empty then false,  
4202 - footer_row(_, cells) then  
4203 - mapor(contains_an_upload,  
4204 - map(content,cells))  
4205 - }.  
4206 -  
4207 -define Bool  
4208 - contains_an_upload  
4209 - (  
4210 - HTML_In_Form form_content  
4211 - ) =  
4212 - if form_content is  
4213 - {  
4214 - literal_pt(t) then false,  
4215 - literal(t) then false,  
4216 - sequence(l) then mapor(contains_an_upload,l)  
4217 - text(o,t) then false,  
4218 - preformated(o,s) then false,  
4219 - paragraph(o,t) then false,  
4220 - image(o,u,a) then false,  
4221 - image(o,u,a,w,h) then false,  
4222 - table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true  
4223 - else contains_an_upload(f_row),  
4224 - center(e) then contains_an_upload(e),  
4225 - mail_to(m,e) then false, // 'e' may but should not contain an upload  
4226 - scroller(w,h,cw,ch,e) then contains_an_upload(e),  
4227 - actioner(c,t,a,an,eo,ja) then false,  
4228 - foreign_link_new(_,_,_) then false,  
4229 - foreign_link(o,u) then false,  
4230 - foreign_link(o,u,n) then false,  
4231 - private_download(p,n,e,a) then false,  
4232 - text_input(o,lt,l,n,i,w) then false,  
4233 - text_input_ro(o,lt,l,n,i,w) then false,  
4234 - password_input(o,lt,l,n,i,w) then false,  
4235 - text_area(o,lt,id,n,i,w,h) then false,  
4236 - file_upload(o,l,i,n,w) then true,  
4237 - selector(o,l,i,n,s,c) then false,  
4238 - selector(o,l,i,n,s,c,p) then false,  
4239 - selector_c(o,l,i,n,s,c) then false,  
4240 - selector_c(o,l,i,n,s,c,p) then false,  
4241 - radio_button(o,_,_,n,v,c) then false,  
4242 - radio_button_r(o,_,_,n,v,c) then false,  
4243 - check_box(o,_,_,n,v,c) then false,  
4244 - check_box_r(o,_,_,n,v,c) then false,  
4245 - div(o,c) then contains_an_upload(c),  
4246 - div_empty(o) then false,  
4247 - hidden(_,_,_) then false  
4248 - }.  
4249 -  
4250 -define String  
4251 - enctype  
4252 - (  
4253 - HTML_In_Form form_content  
4254 - ) =  
4255 - if contains_an_upload(form_content)  
4256 - then " enctype=\"multipart/form-data\""  
4257 - else "".  
4258 -  
4259 -  
4260 -  
4261 -define Printable_tree  
4262 - format  
4263 - (  
4264 - CommonInfo cinfo,  
4265 - String sn, // state_name  
4266 - Var(Int) ic_v, // 'idnum' counter variable  
4267 - HTML_Off_Form element,  
4268 - Bool is_https,  
4269 - ) =  
4270 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4271 - with format_element = (HTML_Off_Form e) |-> format(cinfo,sn,ic_v,e,is_https),  
4272 - if element is  
4273 - {  
4274 - literal_pt(t) then t,  
4275 - literal(t) then [t],  
4276 - sequence(l) then flat(map(format_element,l)),  
4277 - text(opts,t) then  
4278 - format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https),  
4279 - preformated(o,s) then  
4280 - format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https),  
4281 - paragraph(opts,t) then  
4282 - format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https),  
4283 - image(opts,url,alt) then  
4284 - format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https),  
4285 - image(opts,url,alt,w,h) then  
4286 - format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https),  
4287 - table(opts,header_row, rows, footer_row) then  
4288 - format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https),  
4289 - center(e) then  
4290 - format(cinfo,sn,ic_v,any_center(e),format_element,is_https),  
4291 - mail_to(a,e) then  
4292 - format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https),  
4293 - scroller(w,h,cw,ch,c) then  
4294 - format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https),  
4295 - fixed_size(w,h,c) then  
4296 - format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https),  
4297 - fixed_size_2(w,h,fn) then  
4298 - format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https),  
4299 - actioner(c,t,a,an,eo,ja) then  
4300 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https),  
4301 - actioner(c,t,a,an,eo,ja,fn) then  
4302 - format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https),  
4303 - foreign_link_new(target, aspect, url) then  
4304 - format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https),  
4305 - foreign_link(options,url) then  
4306 - format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https),  
4307 - foreign_link(options,url,name) then  
4308 - format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https),  
4309 - private_download(url,name,extra,action) then  
4310 - format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https),  
4311 - label(n) then ["<a name=\"",n,"\">"],  
4312 - form(fn,attributs, c) then  
4313 - [  
4314 - "<form id=\"",fn,"\"",  
4315 - format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https),  
4316 - " method=\"post\"",  
4317 - enctype(c),  
4318 - " action=\"http",  
4319 - if is_https then "s" else "",  
4320 - "://",common_name,":",to_decimal(http_port),"/\">",  
4321 - // action is set dynamically by  
4322 - // the actioner using JavaScript  
4323 - if fn is htmlId(id) then  
4324 - format(cinfo,id,sn,ic_v,c,is_https),  
4325 - "</form>"  
4326 - ]  
4327 - form(fn,attributs, action_name, extra_ops, c) then  
4328 - with url = make_actioner_url(cinfo, same, same,  
4329 - sn, action_name, extra_ops, is_https),  
4330 - [  
4331 - "<form id=\"",fn,"\"",  
4332 - format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https),  
4333 - " method=\"post\"",  
4334 - enctype(c),  
4335 - " action=\"" + url + "\">",  
4336 -// " action=\"http",  
4337 -// if is_https then "s" else "",  
4338 -// "://",common_name,":",http_port,"/\">",  
4339 - // action is set dynamically by  
4340 - // the actioner using JavaScript  
4341 - if fn is htmlId(id) then  
4342 - format(cinfo,id,sn,ic_v,c,is_https),  
4343 - "</form>"  
4344 - ]  
4345 - div(options, e) then  
4346 - format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https),  
4347 - div_empty(options) then  
4348 - format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https),  
4349 - iframe(options, css_styles, css_files, js_files, body) then  
4350 - if body is body(body_options,element) then  
4351 - [ "<iframe", format_attrs(options), ">\n",  
4352 - "<html style=\"margin: 0pt; padding: 0pt;\">\n",  
4353 - "<head>\n",  
4354 - add_css_styles(css_styles),  
4355 - add_css_files(css_files),  
4356 - add_js_files(js_files),  
4357 - "</head>\n",  
4358 - "<body ", format(body_options), ">\n", // format body options  
4359 - format(cinfo,sn,ic_v,element,is_https),  
4360 - "</body>\n",  
4361 - "</html>\n",  
4362 - "</iframe>\n",  
4363 - ],  
4364 -  
4365 - }.  
4366 -  
4367 -  
4368 -  
4369 -  
4370 - *** [5.10] Formating meta-tags.  
4371 -  
4372 -define Printable_tree  
4373 - format_keywords  
4374 - (  
4375 - List(String) l  
4376 - ) =  
4377 - if l is  
4378 - {  
4379 - [] then [ ],  
4380 - [h . t] then if t is []  
4381 - then [h]  
4382 - else [h , ", " . format_keywords(t)]  
4383 - }.  
4384 -  
4385 -  
4386 -define Printable_tree  
4387 - format  
4388 - (  
4389 - CommonInfo cinfo,  
4390 - String state_name,  
4391 - HTML_Meta m,  
4392 - Bool is_https  
4393 - ) =  
4394 - if m is  
4395 - {  
4396 - keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],  
4397 - refresh(co,ta,an,delay) then  
4398 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",  
4399 - make_actioner_url(cinfo,co,ta,state_name,an,[],is_https),"\" />\n"],  
4400 - refresh(url,delay) then  
4401 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],  
4402 - meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],  
4403 - http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],  
4404 - generic_meta(l) then ["<meta ",  
4405 - flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],  
4406 - l)),  
4407 - " />\n"],  
4408 - literal(s) then [s]  
4409 - }.  
4410 -  
4411 -define Printable_tree // c'est le nôtre et c'est meilleur  
4412 - format  
4413 - (  
4414 - HTML_Meta m,  
4415 - ) =  
4416 - if m is  
4417 - {  
4418 - keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],  
4419 - refresh(co,ta,an,delay) then  
4420 - ["<!-- TODO refresh(co,ta,an,delay) --> "], // TODO  
4421 - refresh(url,delay) then  
4422 - ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],  
4423 - meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],  
4424 - http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],  
4425 - generic_meta(l) then ["<meta ",  
4426 - flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],  
4427 - l)),  
4428 - " />\n"],  
4429 - literal(s) then [s]  
4430 - }.  
4431 -  
4432 -  
4433 -define Printable_tree  
4434 - format  
4435 - (  
4436 - CommonInfo cinfo,  
4437 - String state_name,  
4438 - List(HTML_Meta) metas,  
4439 - Bool is_https,  
4440 - String charset  
4441 - ) =  
4442 - if metas is  
4443 - {  
4444 - [] then [format(cinfo,state_name,http_equiv("content-type",  
4445 - "text/html; charset="+charset),is_https)],  
4446 - [h . t] then [format(cinfo,state_name,h,is_https)  
4447 - . format(cinfo,state_name,t,is_https,charset)]  
4448 - }.  
4449 -  
4450 -define Printable_tree  
4451 - _format_html_head  
4452 - (  
4453 - List(HTML_Head_Tag) lwf,  
4454 - Printable_tree so_far  
4455 - )  
4456 - =  
4457 - if lwf is  
4458 - {  
4459 - [] then reverse(so_far),  
4460 - [ h . t] then  
4461 - if h is  
4462 - {  
4463 - meta(meta) then  
4464 - [format(meta) . _format_html_head(t, so_far)],  
4465 - title(title) then  
4466 - ["<title>"+title+"</title>\n" . _format_html_head(t, so_far)],  
4467 - js(jsf) then  
4468 - [add_js_files([jsf]) . _format_html_head(t, so_far)],  
4469 - js_inline(jsi) then  
4470 - ["<script>"+content(jsi)+"</script>\n" . _format_html_head(t, so_far)],  
4471 - css(cssf) then  
4472 - ["<link rel=\"stylesheet\" type=\"text/css\" href=\""+file_name(cssf)+"\" />\n" . _format_html_head(t, so_far)],  
4473 - css_inline(cssi) then  
4474 - ["<style>"+cssi+"</style>\n" . _format_html_head(t, so_far)]  
4475 - }  
4476 - }  
4477 - .  
4478 -  
4479 -public define Printable_tree  
4480 - format_html_head  
4481 - (  
4482 - List(HTML_Head_Tag) lwf,  
4483 - String charset  
4484 - )  
4485 - =  
4486 - with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf],  
4487 - if lwf is  
4488 - {  
4489 - [] then  
4490 - [],  
4491 - [ h . t] then  
4492 - _format_html_head(lwf, [])  
4493 - }  
4494 - .  
4495 -  
4496 -define Printable_tree  
4497 - format  
4498 - (  
4499 - CommonInfo cinfo,  
4500 - String state_name,  
4501 - List(HTTP_header) additional_headers,  
4502 - HTTP_Answer page,  
4503 - Bool is_https,  
4504 - String charset  
4505 - ) =  
4506 - if cinfo is info(common_name,http_port,https_port,site_directory,secret) then  
4507 - with ic_v = var((Int)0),  
4508 - if page is  
4509 - {  
4510 - html_page(status, head_tags, body) then  
4511 - if body is body(options,element) then  
4512 - if format(status) is (status_string, status_headers) then  
4513 - with answer_body =  
4514 - [doctype_w3c_header,  
4515 - html_header,  
4516 -  
4517 - "<head>\n", format_html_head(head_tags, charset),"</head>\n",  
4518 -  
4519 - "<body ", format(options), ">", // format body options  
4520 - format(cinfo,state_name,ic_v,element,is_https),  
4521 - "</body>\n",  
4522 -  
4523 - "</html>"],  
4524 - [ "HTTP/1.1 " + status_string, crlf,  
4525 - format_headers(standard_headers),  
4526 - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),  
4527 - format_headers(status_headers),  
4528 - format_headers(additional_headers),  
4529 - crlf  
4530 - . answer_body  
4531 - ]  
4532 -  
4533 - html_page(status, title, metas, css_styles, css_files, js_files, script, body) then  
4534 - if body is body(options,element) then  
4535 - if format(status) is (status_string, status_headers) then  
4536 - with answer_body =  
4537 - [ doctype_w3c_header,  
4538 - html_header,  
4539 - "<head>\n",  
4540 - add_css_styles(css_styles),  
4541 - add_css_files(css_files),  
4542 - add_js_files(js_files),  
4543 - add_script(script),  
4544 - "<link rel=\"shortcut icon\" href=\"favicon.ico\" />\n",  
4545 - "<script type = \"text/javascript\" language=\"JavaScript\">",  
4546 - " function show_local_popup(divname,stvname) {",  
4547 - " if (document.layers) { var d = eval(document.divname); } else\n",  
4548 - " if (document.getElementById) { var d = eval(\"document.getElementById(divname)\"); } else\n",  
4549 - " if (document.all) { var d = eval(document.all.divname.style)};\n",  
4550 - // " alert(typeof(eval(stvname))); ",  
4551 - " var s = eval(stvname); ",  
4552 - " if (s[0]==0) ",  
4553 - " { s[0]=1; d.style.visibility = 'visible'; d.zIndex = 100; } else\n",  
4554 - " { s[0]=0; d.style.visibility = 'hidden'; }; }",  
4555 - "</script>\n",  
4556 - "<title>",title,"</title>\n", // put title  
4557 - format(cinfo,state_name,metas,is_https,charset), // format the metas  
4558 - "</head>\n",  
4559 - "<body ", format(options), ">", // format body options  
4560 - //"<center>",  
4561 - format(cinfo,state_name,ic_v,element,is_https),  
4562 - //"</center>",  
4563 - "</body>\n",  
4564 - "</html>"  
4565 - ],  
4566 - [ "HTTP/1.1 " + status_string, crlf,  
4567 - format_headers(standard_headers),  
4568 - format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),  
4569 - format_headers(status_headers),  
4570 - format_headers(additional_headers),  
4571 - crlf  
4572 - . answer_body  
4573 - ],  
4574 -  
4575 - plain_text (HTTP_Status status, String text) then  
4576 - if format(status) is (status_string, status_headers) then  
4577 - [ "HTTP/1.1 " + status_string, crlf,  
4578 - format_headers(standard_headers),  
4579 - format_headers(standard_headers_for("text/plain", length(text), success(charset))),  
4580 - format_headers(status_headers),  
4581 - format_headers(additional_headers),  
4582 - crlf,  
4583 - text . (Printable_tree)[]  
4584 - ],  
4585 -  
4586 - custom_text(HTTP_Status status, String mime_type, String content) then  
4587 - if format(status) is (status_string, status_headers) then  
4588 - [ "HTTP/1.1 " + status_string, crlf,  
4589 - format_headers(standard_headers),  
4590 - format_headers(standard_headers_for(mime_type, length(content), success(charset))),  
4591 - format_headers(status_headers),  
4592 - format_headers(additional_headers),  
4593 - crlf,  
4594 - content . (Printable_tree)[]  
4595 - ],  
4596 - custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then  
4597 - if format(status) is (status_string, status_headers) then  
4598 - [ "HTTP/1.1 " + status_string, crlf,  
4599 - format_headers(status_headers),  
4600 - format_headers(standard_headers_for(mime_type, length(content), failure)),  
4601 - format_headers(status_headers),  
4602 - format_headers(other_headers),  
4603 - format_headers(additional_headers),  
4604 - crlf,  
4605 - content . (Printable_tree)[]  
4606 - ],  
4607 -  
4608 - custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then  
4609 - if format(status) is (status_string, status_headers) then  
4610 - [ "HTTP/1.1 " + status_string, crlf,  
4611 - format_headers(standard_headers),  
4612 - format_headers(standard_headers_for(mime_type, length(content), success(charset))),  
4613 - format_headers(status_headers),  
4614 - format_headers(additional_headers),  
4615 - crlf .  
4616 - content  
4617 - ],  
4618 -  
4619 - http_raw(Printable_tree content) then content,  
4620 -  
4621 - html_content(HTTP_Status status, HTML_Off_Form content_HTML) then  
4622 - if format(status) is (status_string, status_headers) then  
4623 - with content = format(cinfo, state_name, ic_v, content_HTML, is_https),  
4624 - [ "HTTP/1.1 " + status_string, crlf,  
4625 - format_headers(standard_headers),  
4626 - format_headers(standard_headers_for("text/html", length(content), success(charset))),  
4627 - format_headers(status_headers),  
4628 - format_headers(additional_headers),  
4629 - crlf .  
4630 - content  
4631 - ],  
4632 - }.  
4633 - 1 +
  2 +
  3 + *Project* Anubis
  4 +
  5 + *Title* Making interactive Web sites.
  6 +
  7 + *Copyright* Copyright (c) Alain Prouté 2004-2005.
  8 + Copyright (c) Calexium 2007.
  9 +
  10 +
  11 + *Authors* Alain Prouté
  12 + David René
  13 +
  14 + *Revised* May 2007
  15 +
  16 +
  17 + *Overview*
  18 +
  19 + In this file we propose simple tools for making well structured interactive and secured
  20 + web sites.
  21 +
  22 +
  23 + ----------------------------------- Table of Contents ---------------------------------
  24 +
  25 + * (1) Structure of a web site.
  26 + ** (1.1) Three sorts of data.
  27 + ** (1.2) How requests are handled.
  28 + ** (1.3) What web pages are made of.
  29 + ** (1.4) Actions.
  30 + ** (1.5) States.
  31 +
  32 + * (2) Carrying on.
  33 + ** (2.1) Describing your web sites.
  34 + ** (2.2) Directories on the server's disk.
  35 + ** (2.3) Starting your web sites.
  36 +
  37 + * (3) The HTML interface.
  38 + ** (3.1) Types used by the HTML interface.
  39 + ** (3.2) ``in form'' versus ``off form''.
  40 + ** (3.3) Defining your own style.
  41 + ** (3.4) Actioners and forms.
  42 + ** (3.5) Local popup.
  43 +
  44 + ---------------------------------------------------------------------------------------
  45 +
  46 +
  47 +read tools/basis.anubis
  48 +read tools/printable_tree.anubis
  49 +read system/string.anubis
  50 +read system/logger.anubis
  51 +read CXM_common.anubis
  52 +read CXM_multihost_http_server.anubis
  53 +read web/mime.anubis
  54 +read CXM_cookies.anubis
  55 +
  56 +
  57 + * (1) Structure of a web site.
  58 +
  59 + First of all we need to explain what a web site should be made of. Ideally, the
  60 + visitor (also called the 'client') should see the web site working as any other
  61 + interactive computer software. So, it should be clear that a 'session' (i.e. a visit
  62 + to the web site, including the consultation of several pages) is some kind of
  63 + conversation between the visitor and the web site, and that the web site should
  64 + maintain a 'current state' of this conversation. At each new request (click) from the
  65 + visitor, this state must be updated. This whole conversation is called a 'session' and
  66 + should not be confused with a single request.
  67 +
  68 +
  69 +
  70 + ** (1.1) Three sorts of data.
  71 +
  72 + All the data needed for putting a web site at work may be dispatched into three
  73 + categories:
  74 +
  75 + 1. Constant data (data that never change). These data may be hard coded into the
  76 + Anubis source files of the web site.
  77 +
  78 + 2. Permanent data (data which always exist independantly of the users connected to
  79 + the web site). These data are normally recorded into data bases.
  80 +
  81 + 3. Session data (data which depend on a particular visitor and which exist only
  82 + during the time he visits the web site). These data are stored into so-called
  83 + 'states'.
  84 +
  85 +
  86 + It is important to determine which data belongs to which category. This is part of your
  87 + design decisions.
  88 +
  89 +
  90 +
  91 + ** (1.2) How requests are handled.
  92 +
  93 + We want to separate the following two functionalities (which are used at each request
  94 + (click) during a single session):
  95 +
  96 + - computing the new state from the previous state and from the client request, and
  97 + updating the data base,
  98 +
  99 + - computing the page to be sent to the client from the new current state and from
  100 + the informations in the data base.
  101 +
  102 +
  103 + The next picture shows the structure we have in mind:
  104 +
  105 +
  106 + request +---------+ HTML page (with a hidden state name)
  107 + .-------------------| client |<--------------.
  108 + | .-----------------| | |
  109 + | | previous state +---------+ |
  110 + | | name (if any) |
  111 + | | | client side
  112 + ............................................................................
  113 + | | | server side
  114 + | | |
  115 + | | .-------------------. |
  116 + | | | previous state | |
  117 + V V V | |
  118 + +---------------+ +---------------+ +--------------+
  119 + | compute state | | server's disk | | compute page |
  120 + +---------------+ +---------------+ +--------------+
  121 + ^ | | ^ ^ ^ ^ ^
  122 + | | | | | | | |
  123 + | | `--------------------+--------------------' | |
  124 + | | new state | | |
  125 + read | `------------------------+--------------------' |
  126 + write | new state name |
  127 + update V |
  128 + +-----------+ |
  129 + | data base |--------------------------------------------'
  130 + +-----------+ read only
  131 +
  132 +
  133 + When the client begins a session, there is no previous state. In this case, a default
  134 + 'initial state' is used instead.
  135 +
  136 + The data base may be updated by 'compute state' box, but should not be update by the
  137 + 'compute page' box. The 'compute page' box should be allowed only to read the data
  138 + base.
  139 +
  140 + In this file, all the above stuff is defined, except the 'compute state' and 'compute
  141 + page' boxes. You just have to provide the function for computing a new state (compute
  142 + state) and the function for computing the page (compute page) from the new state. You
  143 + don't have to worry about state names, saving and retrieving states and the like.
  144 +
  145 +
  146 +
  147 +
  148 +
  149 + ** (1.3) What web pages are made of.
  150 +
  151 + What the client can see in his browser's window may be called a 'page'. Within a page,
  152 + we have several sorts of components:
  153 +
  154 + - 'local' components, i.e. all components which do not open a connection, like
  155 + texts, images, etc... possibly using JavaScript programmation,
  156 +
  157 + - 'actioners', which, when clicked upon, open a connection with our web site; they
  158 + may appear as links or buttons, etc...
  159 +
  160 + - 'foreign links', which when clicked upon, open a connection with another web site
  161 + (or ours eventually).
  162 +
  163 + Of course, what an actioner does is just ask our web site to perform an action. To that
  164 + end, the actioner essentially sends the name of the action to be performed. However, it
  165 + may be necessary to provide additional informations which may be seen as 'operands' of
  166 + the action. In order to attach operands to an action, HTML provides the notion of
  167 + 'form'. Indeed, a form contains essentially a set of input fields into which the client
  168 + may put values for the required operands of the action, and a submit button, which is
  169 + the actioner itself. Notice that a single form may contain several submit buttons,
  170 + which simply means that there are several distincts actions taking the same set of
  171 + operands.
  172 +
  173 + Restrictions must be put on the use of all theses gadgets. Indeed, for example,
  174 + putting a form within another form is officially meaningless in HTML, and the client's
  175 + browser may be seriously disturbed by this. In this file, we propose an interface to
  176 + the HTML language, which forbids such meaningless things, simply by imposing a strict
  177 + typing of HTML concepts.
  178 +
  179 + Each web site may be accessible through two communication channels:
  180 +
  181 + - a non secured channel (HTTP),
  182 + - a secured channel (HTTPS).
  183 +
  184 + Nevertheless, the whole thing should be considered as a single web site. For example,
  185 + you may have a secured page, obtained through HTTPS, containing public images obtained
  186 + through HTTP. An actioner in a non secured page may open a secured connection, and
  187 + conversely.
  188 +
  189 + Summarizing, a web page is made of local elements, foreign links and actioners.
  190 + Actioners receive operands from forms, and they also choose to communicate through the
  191 + non secured or through the secured channel.
  192 +
  193 +
  194 +
  195 + +-------------------+
  196 + | page |
  197 + | | +---------------+
  198 + | +--------------+ | | next page |
  199 + | | form | | | (non secured) |
  200 + | | +----------+ | | HTTP | |
  201 + | | | actioner |---------------------------->| |
  202 + | | +----------+ | | +---------------+
  203 + | | | |
  204 + | | +----------+ | | +---------------+
  205 + | | | actioner |---------------------------->| next page |
  206 + | | +----------+ | | HTTPS | (secured) |
  207 + | | | | | |
  208 + | +--------------+ | | |
  209 + | | +---------------+
  210 + | |
  211 + +-------------------+
  212 +
  213 +
  214 + Notice that actioners need no be necessarily put into forms. In that case, they work as
  215 + ordinary links, but they still may receive operands as we shall see.
  216 +
  217 +
  218 +
  219 +
  220 + ** (1.4) Actions.
  221 +
  222 + The client opens a new connection with our web site whenever he clicks on an
  223 + actioner. The result is that a request is sent, essentially made of a list of 'web
  224 + arguments'. Each web argument is a pair (name,value). One of these web arguments, the
  225 + 'action' web argument (whose name is "a"), determines the action to be performed. The
  226 + other web arguments (not including "s", used to identify the state) are the operands
  227 + for this action.
  228 +
  229 + Hence, the 'compute state' box in the picture above, splits naturally into as many
  230 + sub-boxes as there are actions. For this reason, we define the following type for
  231 + representing actions (where '$State' is the type representing session informations):
  232 +
  233 +public type Web_Action($State):
  234 + http_action (String name, // name of action
  235 + ($State) -> Bool allow, // true if action allowed
  236 + (HTTP_Info http_info,
  237 + List(Web_arg) web_args, // actually only 'operands' web arguments
  238 + $State state) -> $State do_it),
  239 + https_action (String name, // name of action
  240 + ($State) -> Bool allow, // true if action allowed
  241 + (HTTP_Info http_info,
  242 + List(Web_arg) web_args, // actually only 'operands' web arguments
  243 + $State state) -> $State do_it),
  244 + http_https_action (String name,
  245 + ($State) -> Bool allow,
  246 + (HTTP_Info http_info,
  247 + List(Web_arg) web_args,
  248 + $State state) -> $State do_it).
  249 +
  250 + 'http_action's are executed only under HTTP, and 'https_action's are executed only
  251 + under HTTPS. 'http_https_action's may be executed under both types of connections.
  252 +
  253 + Each action has a name, which is used to identify the action. Each action also has a
  254 + function 'allow' whose job is to verify that the action is allowed in the current
  255 + state, and a function 'do_it' for performing the action. The function 'do_it' receives
  256 + a lot of informations:
  257 +
  258 + - 'HTTP informations':
  259 + - the IP address of the client,
  260 + - the URI requested by the client (after redirection),
  261 + - the list of HTTP headers generated by the client's browser,
  262 + - the list of web arguments sent by the client (except "s" and "a"),
  263 + - the previous state (or the 'initial' or 'ticket expired' state if no previous
  264 + state can be found).
  265 +
  266 + In most cases, HTTP informations are not used. This is the reason why they are gathered
  267 + for simplicity into a unique datum of type 'HTTP_Info'.
  268 +
  269 +// For your convenience, we introduce the following simpler variants:
  270 +//
  271 +//public define Web_Action($State)
  272 +// http_action
  273 +// (
  274 +// String name,
  275 +// $State -> Bool allow,
  276 +// (List(Web_arg),$State) -> $State do_it
  277 +// ) =
  278 +// http_action(name,
  279 +// (Maybe($State) ms) |-> if ms is
  280 +// {
  281 +// failure then true,
  282 +// success(s) then allow(s)
  283 +// },
  284 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  285 +// {
  286 +// failure then (failure, []),
  287 +// success(s2) then (success(do_it(l,s2)), [])
  288 +// }).
  289 +//
  290 +//public define Web_Action($State)
  291 +// https_action
  292 +// (
  293 +// String name,
  294 +// $State -> Bool allow,
  295 +// (List(Web_arg),$State) -> $State do_it
  296 +// ) =
  297 +// https_action(name,
  298 +// (Maybe($State) ms) |-> if ms is
  299 +// {
  300 +// failure then true,
  301 +// success(s) then allow(s)
  302 +// },
  303 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  304 +// {
  305 +// failure then (failure, []),
  306 +// success(s2) then (success(do_it(l,s2)), [])
  307 +// }).
  308 +//
  309 +//public define Web_Action($State)
  310 +// http_https_action
  311 +// (
  312 +// String name,
  313 +// $State -> Bool allow,
  314 +// (List(Web_arg),$State) -> $State do_it
  315 +// ) =
  316 +// http_https_action(name,
  317 +// (Maybe($State) ms) |-> if ms is
  318 +// {
  319 +// failure then true,
  320 +// success(s) then allow(s)
  321 +// },
  322 +// (HTTP_Info h, List(Web_arg) l, Maybe($State) s) |-> if s is
  323 +// {
  324 +// failure then (failure, []),
  325 +// success(s2) then (success(do_it(l,s2)), [])
  326 +// }).
  327 +
  328 +
  329 +
  330 + When you define your web site, you must provide the list of all the actions of the
  331 + site. When a new state has been computed, a graphical representation of this state
  332 + must be sent to the client. To that end, you must provide a function (named below
  333 + 'compute_page') of type:
  334 +
  335 + $State -> HTTP_Answer
  336 +
  337 + where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML
  338 + pages.
  339 +
  340 +public type HTTP_Answer:...
  341 +
  342 + It should be clear that states and pages are deeply linked together. Indeed, we really
  343 + understand the page shown to the client as a representation of the current state of the
  344 + conversation between the client and the web site, but also containing informations
  345 + taken from the data bases.
  346 +
  347 +
  348 +
  349 +
  350 +
  351 + ** (1.5) States.
  352 +
  353 + Now, we explain how you can define the type (say 'State') to be used as an instance of
  354 + the type parameter '$State'. The following is just a suggestion.
  355 +
  356 + Each state determines a page (since 'compute_page' computes a page from a
  357 + state). However, some components of the state may be independant of the page. It may be
  358 + the case for example for the indication of the natural language used by the
  359 + client. Hence, a state should be made of (at least) two parts:
  360 +
  361 + - informations which are the same for all pages,
  362 + - informations which are particular to each page.
  363 +
  364 + For example, you could define:
  365 +
  366 + type Page: // one alternative per page, with particular informations
  367 + login(...), // in the components
  368 + main_page(...),
  369 + ...etc...
  370 +
  371 + Now, the type 'State' could be defined as follows:
  372 +
  373 + type State:
  374 + state(Language, // informations valid for all pages
  375 + ...,
  376 + Page). // informations particular to a page
  377 +
  378 + However, if you are making a secured web site within which clients should be identified
  379 + (by id and password), it may be a good idea to have two sorts of states, one for non
  380 + identified clients and one for identified clients. In this case, define the type
  381 + 'State' as follows (this is just a suggestion):
  382 +
  383 + type State:
  384 + non_identified(Language),
  385 + identified(String id,
  386 + Language,
  387 + Page).
  388 +
  389 + When a request arrives, check if the previous state is 'identified(...)' or
  390 + 'non_identified(...)', and don't provide access to certain pages to non identified
  391 + clients. This is required for security.
  392 +
  393 + Some more words on security. If your site needs to identify clients, define the
  394 + initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and
  395 + password of the client. If the id and password are correct, then change the state of
  396 + the client to 'identified(...)'. No other action should be able to do that. Now, be
  397 + confident that clients cannot forge states. The only information they have is the name
  398 + of a state, not the state itself which is never sent over the network, but only stored
  399 + on the server's disk. The name of the state is constructed using strong cryptographical
  400 + methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even
  401 + state names cannot be seen by a third party. So, if the system retrieves a previous
  402 + state of the form 'identified(...)', you can be confident that your client is well
  403 + identified, and you can send him confidential informations.
  404 +
  405 + States have a limited life time. It may happen that a client clicks on a button at a
  406 + time its state is out of date. In this case, this system considers that the new state
  407 + is a special state named 'ticket expired'. You must provide a function producing this
  408 + state when you describe your web site. The page corresponding to this state must just
  409 + inform the client that he/she waited a too long time before clicking on a button, and
  410 + has to restart (a new conversation) from the begining.
  411 +
  412 +
  413 +
  414 + * (2) Carrying on.
  415 +
  416 + ** (2.1) Describing your web sites.
  417 +
  418 + Before you may start your web site, you must describe it, i.e. produce a datum of the
  419 + opaque type 'Web_Site'.
  420 +
  421 +public type Web_Site:...
  422 +
  423 + Producing such a datum may be performed by:
  424 +
  425 +public define Web_Site
  426 + make_web_site_description
  427 + (
  428 + List(String) common_names, // for example: ["www.our-business.com",
  429 + // "192.168.0.1"]
  430 + // the second one is just for testing
  431 + String site_directory, // where 'public' and other directories are
  432 + // located (should NOT end with '/')
  433 + String state_directory,
  434 + One -> One init,
  435 + (HTTP_Info,
  436 + List(Web_arg),
  437 + Bool is_https) -> $State initial_state,
  438 + ($State expired,
  439 + Maybe(String),
  440 + HTTP_Info,
  441 + List(Web_arg),
  442 + Bool is_https) -> $State ticket_expired_state,
  443 + (Maybe(String),
  444 + HTTP_Info,
  445 + List(Web_arg),
  446 + Bool is_https) -> $State ticket_lost_state,
  447 + List(Web_Action($State)) actions,
  448 + $State -> HTTP_Answer compute_page,
  449 + $State -> List(HTTP_header) additional_headers,
  450 + Int timeout, // seconds (todo: minutes)
  451 + Redirections redirections,
  452 + String charset,
  453 + List(String) journal_extensions,
  454 + List(String) journal_headers,
  455 + String authorization_secret,
  456 + List(MIME) known_mime_types,
  457 + (String action_name,
  458 + List(Web_arg) args)-> One before_send_file
  459 + ).
  460 +
  461 +
  462 + Explanations:
  463 +
  464 + 'common_names' is the list of names of the site (the name the browser must send as the
  465 + value of the 'Host' HTTP header in order to access the site must be in that list). Such
  466 + a name generally looks like this:
  467 +
  468 + www.somewhere.com
  469 +
  470 + If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of
  471 + the site must be exactly the same as the name on the certificate (which is precisely
  472 + called the 'common name' in the X.509 jargon). If the two names do not match, the site
  473 + will still work, but the transaction will not be transparent to the client. His browser
  474 + will complain that the name of the certificate does not match the name of the site, and
  475 + he will have to accept the certificate manually.
  476 +
  477 + 'site_directory' is the absolute path to the directory where the files needed by the
  478 + site are located. Usually this directory looks like:
  479 +
  480 + my_anubis/web_sites/www.somewhere.com
  481 +
  482 + However, this information is not computed from 'common_name', so that you can change
  483 + the common name (for example temporarily, for networking reasons) without loosing
  484 + access to the files.
  485 +
  486 + 'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state
  487 + whose graphical representation is a page explaining to the user that its 'ticket' (or
  488 + 'session information') has expired, and that he/she must close all popup windows and
  489 + start a new session. The arguments of the function contain the previous (expired)
  490 + state and all current informations concerning the user. This arguments may be useful
  491 + for example for producing the expiration message in the language chosen by the user.
  492 + You can also (and this may be much smarter) send a 'ticket prolongation page'
  493 + (including a new login for example), and resume the same conversation, since you have
  494 + all the pertinent informations at hand. In the case the ticket is definitely lost, the
  495 + second fonction 'ticket_lost_state' is used.
  496 +
  497 + Notice that despite the fact that the parameter $State is involved in the arguments of
  498 + the above function, the type 'Web_Site' does not depend on this parameter. This allows
  499 + to produce lists of web site descriptions, where each description may be constructed
  500 + with a different instance of $State. This is required because distinct sites must have
  501 + distinct types of session informations. This is made possible by the fact that the
  502 + type is obscure, and the constructor replaced by a function which assembles
  503 + 'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single
  504 + entity not depending on $State. You should have a look to the private part of this file
  505 + if you want more precisions about this programming technique.
  506 +
  507 + 'charset' is a string which will determine the character encoding to be used by the
  508 + browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",
  509 + etc...
  510 +
  511 + 'before_send_file' is a function which is executed just before the HTTP server sends a
  512 + file. It gets an action name and the web arguments received with the request for that
  513 + file. Notice that this action name and these web arguments may be put into a
  514 + 'private_download' element, and will come back to the server at the time of the
  515 + download.
  516 +
  517 +
  518 +
  519 + ** (2.2) Directories on the server's disk.
  520 +
  521 + The description of your site contains the name of the directory within which the
  522 + required files are located. This may be for example:
  523 +
  524 + my_anubis/web_sites/www.our-business.com/
  525 +
  526 + This is called the 'site directory' (for the given site). Within the site directory,
  527 + the following directories are created by this program:
  528 +
  529 + states
  530 + public
  531 + journal
  532 + private_download
  533 + upload_temporary
  534 +
  535 + The directory 'states' is used for storing states (session informations). Out of date
  536 + states are automatically removed after some time.
  537 +
  538 + The tree rooted at 'public' contains files that the server is allowed to send to the
  539 + clients. For security reasons, the server never sends a file which is not within the
  540 + tree whose root is this 'public' directory (except for the 'private download' mecanism;
  541 + see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis')
  542 + must have been recognized before the file may be sent.
  543 +
  544 + The directory 'journal' contains the jounal files. The roles of the remaining
  545 + directories 'private_download' and 'upload_temporary' is explained in
  546 + 'multihost_http_server.anubis', where you will also find further informations on
  547 + 'public' and 'journal'.
  548 +
  549 +
  550 +
  551 +
  552 + ** (2.3) Web servers parameters.
  553 +
  554 + The web servers have several parameters useful for administration. They are described
  555 + as follows:
  556 +
  557 + public type WebServersParameters:
  558 + wsparms(Var(Bool) shutdown_required,
  559 +
  560 +
  561 +
  562 +
  563 + ** (2.4) Starting your web sites.
  564 +
  565 + When you have described all your web sites (you may want to have several web sites, and
  566 + they are distinguished by their 'common name'), you may start them all together using
  567 + 'start_web_sites' below. This function returns a result of the following type:
  568 +
  569 +public type Start_Web_Sites_Result:
  570 + cannot_bind_to_port(Word32),
  571 + cannot_bind_to_port(Word32,Word32),
  572 + ok(Server http_server,
  573 + Server https_server).
  574 +
  575 + Indeed, it may happen that the system cannot bind (begin to listen) to one of the two
  576 + ports (or to both). The main reason is that another server is already listening on that
  577 + port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that
  578 + the 's' bit has not been set for 'user' and 'group' (there is not such problem under
  579 + Windows). Also notice that the Linux kernel may need a rather long time (up to several
  580 + minutes) before liberating a listening port. Now, if the system can bind to the two
  581 + ports, the pair of the two servers is returned. Two tools are useful for manipulating
  582 + servers:
  583 +
  584 + shutdown of type Server -> One
  585 + is_down of type Server -> Bool
  586 +
  587 + They are defined in 'predefined.anubis' (together with the type 'Server').
  588 +
  589 +
  590 +public define Start_Web_Sites_Result
  591 + start_web_sites
  592 + (
  593 + Word32 ip_address, // the IP address shared by the web sites
  594 + Word32 http_port, // usually: 80
  595 + Word32 https_port, // usually: 443
  596 + String ssl_certificate_common_name,
  597 + List(Web_Site) web_sites, // web sites to be started
  598 + (One) -> Bool shutdown_required
  599 + ).
  600 +
  601 + 'ip_address' is the IP address on which the two servers listen. If you put 0, the
  602 + servers listen on all the IP addresses of the machine. This may be useful if the
  603 + machine has several network interfaces.
  604 +
  605 + 'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec'
  606 + loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server
  607 + certificate. This is due to a problem of conception of SSL itself. See the book 'SSL
  608 + and TLS' by Eric Rescorla (at Addison Wesley) for more explanations.
  609 +
  610 + Notice that the number of servers is always 2, regardless of the number of web sites
  611 + you are starting.
  612 +
  613 + The dynamic variable 'shutdown_required' may be used to control the shutdown of the two
  614 + servers from within the web site (typically the administration part). The servers will
  615 + shutdown as soon as this variable contains 'true'. So you must provide a variable
  616 + containing 'false' otherwise your servers will not run. You may also use the primitive
  617 + 'must_restart' (see 'predefined.anubis') to control the restarting of your servers.
  618 +
  619 +
  620 +
  621 +
  622 +
  623 +
  624 + * (3) The HTML interface.
  625 +
  626 + We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination
  627 + of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more
  628 + reactive and attractive on the client side.
  629 +
  630 +
  631 + ** (3.1) Types used by the HTML interface.
  632 +
  633 + For easy reference, we gather below the definitions of all the types used by the HTML
  634 + interface, and we comment them immediately.
  635 +
  636 +
  637 +public type HTML_Size:
  638 + absolute(Int), // in pixels
  639 + percentage(Int).
  640 +
  641 +
  642 +public type Text_Option:
  643 + size(Int), // size of character font to use
  644 + font(String), // name of character font to use (such as "helvetica",...)
  645 + color(RGB), // color to be used for characters
  646 + italic,
  647 + oblique,
  648 + small_capitals,
  649 + bold,
  650 + underlined,
  651 + left_justified,
  652 + right_justified,
  653 + justified, // justified on both sides
  654 + line_through,
  655 + nowrap,
  656 + class(String), //CSS class
  657 + id(String),
  658 + style(String),
  659 + title(String),
  660 + attr(String, String).
  661 +
  662 +public define Text_Option
  663 + tooltip(String s) = title(s).
  664 +
  665 + A list of 'Text_Option' must be given with each text you want to put in your page.
  666 +
  667 + This indicate the way of reading text.
  668 +public type Reading_Way:
  669 + ltr, //the text is readable from "Left To Right" like english
  670 + rtl. //the text is readable from "Right To Left" like arabic
  671 +
  672 +
  673 +// Following types are define to prohib any arguments order error
  674 +
  675 +/**
  676 + * String value for 'id' attribut
  677 + */
  678 +public type HtmlId:
  679 + htmlId(String id).
  680 +
  681 +/**
  682 + * String value for 'class' attribut
  683 + */
  684 +public type HtmlClass:
  685 + htmlClass(String class).
  686 +
  687 +/**
  688 + * Name used in arguments list when form is submitted.
  689 + */
  690 +public type WebArgName:
  691 + wan(String name).
  692 +
  693 +/**
  694 + * Value passed to arguments list when form is submitted (for RadioButton and CheckBox).
  695 + */
  696 +public type WebArgValue:
  697 + wav(String value).
  698 +
  699 +/**
  700 + * Initial value of an input field.
  701 + */
  702 +public type InitialValue:
  703 + init(String value).
  704 +
  705 +public define Printable_tree [HtmlId x . Printable_tree y] = str_pt(x.id, y).
  706 +public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y).
  707 +public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y).
  708 +public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y).
  709 +public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y).
  710 +
  711 +
  712 +public type HtmlEvents:
  713 + // Form element events
  714 + onchange,
  715 + onsubmit,
  716 + onreset,
  717 + onselect,
  718 + onblur,
  719 + onfocus,
  720 + // Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
  721 + onkeydown,
  722 + onkeypress,
  723 + onkeyup,
  724 + // Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
  725 + onclick,
  726 + ondblclick,
  727 + onmousedown,
  728 + onmousemove,
  729 + onmouseout,
  730 + onmouseover,
  731 + onmouseup.
  732 +
  733 +public type CoreAttrs:
  734 + id (String),
  735 + class (String),
  736 + style (String),
  737 + title (String),
  738 + lang (String),
  739 + dir (Reading_Way),
  740 + accesskey (Word8),
  741 + tabindex (Int),
  742 + attr (String, String),
  743 + event (HtmlEvents, String).
  744 +
  745 +public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
  746 +
  747 +public type InputAttrs:
  748 + class (String),
  749 + style (String),
  750 + title (String),
  751 + lang (String),
  752 + dir (Reading_Way),
  753 + accesskey (Word8),
  754 + tabindex (Int),
  755 + attr (String, String),
  756 + event (HtmlEvents, String).
  757 +
  758 +public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
  759 +
  760 +public define CoreAttrs
  761 + tooltip(String s) = title(s).
  762 +public define InputAttrs
  763 + tooltip(String s) = title(s).
  764 +
  765 +public type I18n:
  766 + lang (String),
  767 + dir (Reading_Way).
  768 +
  769 +//public type DIV_Option:
  770 +// id (String),
  771 +// class (String),
  772 +// style (String),
  773 +// tooltip (String),
  774 +// lang (String),
  775 +// dir (Reading_Way),
  776 +// attr (String, String),
  777 +// event (HtmlEvents, String).
  778 +//
  779 +
  780 + A list of 'DIV_Option' must be given with each DIV you want to put in your page.
  781 +
  782 +define String event_name
  783 + (
  784 + HtmlEvents e
  785 + ) =
  786 + if e is
  787 + {
  788 + // Form element events
  789 + onchange then "onchange",
  790 + onsubmit then "onsubmit",
  791 + onreset then "onreset",
  792 + onselect then "onselect",
  793 + onblur then "onblur",
  794 + onfocus then "onfocus",
  795 + // Keyboard events
  796 + onkeydown then "onkeydown",
  797 + onkeypress then "onkeypress",
  798 + onkeyup then "onkeyup",
  799 + // Mouse events
  800 + onclick then "onclick",
  801 + ondblclick then "ondblclick",
  802 + onmousedown then "onmousedown",
  803 + onmousemove then "onmousemove",
  804 + onmouseout then "onmouseout",
  805 + onmouseover then "onmouseover",
  806 + onmouseup then "onmouseup"
  807 + }.
  808 +
  809 +public type Table_Option:
  810 + background_color(RGB), // applied to all cells in the table
  811 + background_image(String url),
  812 + border(Int width_of_outer_edge, // if not present, all values are 0
  813 + Int width_of_top_of_relief,
  814 + Int width_of_inner_edge,
  815 + RGB border_color),
  816 + width(Int), // sets a minimal width for the table
  817 + percentage_width(Int),
  818 + attr(String name, String value),
  819 + class(String class_name).
  820 +
  821 +
  822 +public define Table_Option nude = border(0,0,0,rgb(0,0,0)).
  823 +
  824 +
  825 + A list of 'Table_Option' must be given with each table.
  826 +
  827 +
  828 +public type BackgroundOption:
  829 + repeat, // repeat the background in both directions
  830 + repeat_horizontal, // repeat the background only horizontally
  831 + repeat_vertical, // repeat the background only verticall
  832 + no_repeat, // don't repeat the background
  833 + center.
  834 +
  835 +
  836 +public type Cell_Option:
  837 + core_attrs(List(CoreAttrs)),
  838 + left, // put the content of the cell on the left
  839 + h_center, // center the content of the cell horizontally
  840 + right, // put the content of the cell on the right
  841 + top, // put the content of the cell upwards
  842 + v_center, // center the content of tye cell vertically,
  843 + bottom, // put the content of the cell downwards
  844 + base_line, // align the content vertically according to base lines
  845 + background_color(RGB),
  846 + background_image(String url, BackgroundOption),
  847 + width(Int), // sets a minimal width for the cell
  848 + percentage_width(Int),
  849 + height(Int), // sets a minimal height for the cell
  850 + columns(Int), // lets the cell span over several columns
  851 + rows(Int), // lets the cell span over several rows
  852 + nowrap, // do not allow text wrapping within the cell
  853 + class(String class_name).
  854 +
  855 + A list of 'Cell_Option' must be given with each cell and each row in a table. Options
  856 + given with a row apply to all the cells in the row, but are superseded by options given
  857 + with cells, which apply only to the cell they are given with.
  858 +
  859 +
  860 +public type HTML_Cell($T):
  861 + cell(List(Cell_Option) options, $T content).
  862 +
  863 +public type HTML_Header_Cell($T):
  864 + header_cell(List(Cell_Option) options, $T content).
  865 +
  866 + The parameter $T is later instantiated either to 'HTML_In_Form' or to 'HTML_Off_Form',
  867 + depending on where you put your table (within a form or not within a form). For your
  868 + convenience, we define the following particular case:
  869 +
  870 +public define HTML_Cell($T)
  871 + cell
  872 + (
  873 + $T content
  874 + ) =
  875 + cell([],content).
  876 +
  877 +public define HTML_Header_Cell($T)
  878 + header_cell
  879 + (
  880 + $T content
  881 + ) =
  882 + header_cell([],content).
  883 +
  884 +
  885 +public type HTML_Row($T):
  886 + row(List(Cell_Option) options, List(HTML_Cell($T)) cells).
  887 +
  888 +public type HTML_Header_Row($T):
  889 + empty,
  890 + header_row(List(Cell_Option) options, List(HTML_Header_Cell($T)) cells).
  891 +
  892 +public type HTML_Footer_Row($T):
  893 + empty,
  894 + footer_row(List(Cell_Option) options, List(HTML_Cell($T)) cells).
  895 +
  896 + Same remark as for 'HTML_Cell($T)'. We define several convenience functions:
  897 +
  898 +public define HTML_Row($T)
  899 + row
  900 + (
  901 + List(HTML_Cell($T)) cells
  902 + ) =
  903 + row([],cells).
  904 +
  905 +public define HTML_Row($T)
  906 + row
  907 + (
  908 + HTML_Cell($T) cell
  909 + ) =
  910 + row([],[cell]).
  911 +
  912 +public define HTML_Header_Row($T)
  913 + header_row
  914 + (
  915 + List(HTML_Header_Cell($T)) cells
  916 + ) =
  917 + header_row([],cells).
  918 +
  919 +public define HTML_Header_Row($T)
  920 + header_row
  921 + (
  922 + HTML_Header_Cell($T) cell
  923 + ) =
  924 + header_row([],[cell]).
  925 +
  926 +public type Actioner_Connection:
  927 + same, // use same type of connection as current page
  928 + http, // use non secured connection
  929 + https. // use secured connection
  930 +
  931 +public type Other_Window_Option:
  932 + resizable, // the new window may be resized by the client
  933 + scrollbars, // the new window has scrollbars
  934 + width(Int), // the new window has the specified width
  935 + height(Int). // the new window has the specified height
  936 +
  937 +public type Actioner_Target:
  938 + same,
  939 + same (String label),
  940 + other(String window_name, List(Other_Window_Option)).
  941 +
  942 +public type Actioner_Aspect:
  943 + link (List(Text_Option), String text, Maybe(String) name),// hypertext link
  944 + img_link (String img_url, String alt_text),
  945 + push_button (List(CoreAttrs),String text),
  946 + button (String url_off, String url_on), // rollover button
  947 + button (String url_off, String url_on, Int w, Int h), // idem with size
  948 + submit (List(CoreAttrs),String text),
  949 + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices),
  950 + immediate_selector (List(CoreAttrs),WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected).
  951 +
  952 +
  953 +
  954 +public type Actioner_Local_Action:
  955 + close_window.
  956 +
  957 +
  958 +public define Actioner_Aspect
  959 + link
  960 + (
  961 + List(Text_Option) options,
  962 + String text
  963 + ) =
  964 + link(options, text, failure).
  965 +
  966 +public define Actioner_Aspect
  967 + link
  968 + (
  969 + String text
  970 + ) =
  971 + link([], text, failure).
  972 +
  973 +
  974 +public define Actioner_Aspect
  975 + link
  976 + (
  977 + List(Text_Option) options,
  978 + Int i
  979 + ) =
  980 + link(options,to_decimal(i), failure).
  981 +
  982 +public define Actioner_Aspect
  983 + link
  984 + (
  985 + Int i
  986 + ) =
  987 + link([], i).
  988 +
  989 +public define Actioner_Aspect
  990 + button
  991 + (
  992 + String url_img
  993 + ) =
  994 + button(url_img,url_img).
  995 +
  996 + Actioners are explained in details below.
  997 +
  998 +
  999 +public type TextAreaOption:
  1000 + input_attrs(List(InputAttrs)),
  1001 + disabled,
  1002 + read_only,
  1003 + wrap_lines.
  1004 +
  1005 +public type CSS_Style:
  1006 + text_options(List(Text_Option)).
  1007 +
  1008 +public type CSS_File:
  1009 + css_file(String file_name).
  1010 +
  1011 +public type JS_Attribute:
  1012 + attr (String, String).
  1013 +
  1014 +public type JS_File:
  1015 + js_file(String file_name,
  1016 + List(JS_Attribute) attributes).
  1017 +
  1018 +public type Script:
  1019 + script( String script_type,
  1020 + String content).
  1021 +
  1022 +public define JS_File
  1023 + js_file
  1024 + (
  1025 + String file_name
  1026 + ) =
  1027 + js_file(file_name, []).
  1028 +
  1029 +public type HTML_Meta:...
  1030 +
  1031 +public type HTML_Off_Form:...
  1032 +
  1033 +public type HTML_Head_Tag:
  1034 + meta(HTML_Meta),
  1035 + title(String),
  1036 + js(JS_File),
  1037 + js_inline(Script),
  1038 + css(CSS_File),
  1039 + css_inline(String css_styles) /* Note: <style> and </style> tags are not necessaries */
  1040 + .
  1041 +
  1042 + /* It contains
  1043 + * - a List of HTML_Head_Tag representing necessaries head tags for the content. ex: jquery js files, js script, css specific styles, ...
  1044 + * - a HTML_Off_Form representing the HTML code for the part of the page we want to display
  1045 + */
  1046 +public type HTML_Partial_Content:
  1047 + partial_content
  1048 + (
  1049 + List(HTML_Head_Tag),
  1050 + HTML_Off_Form
  1051 + )
  1052 + .
  1053 +
  1054 +public define HTML_Partial_Content
  1055 + partial_content
  1056 + (
  1057 + HTML_Off_Form content
  1058 + )=
  1059 + partial_content([], content).
  1060 +
  1061 +public define List(HTML_Head_Tag)
  1062 + to_HTML_Head_Tag
  1063 + (
  1064 + List(CSS_File) css_file_list
  1065 + )=
  1066 + map((CSS_File css_f) |-> css(css_f), css_file_list).
  1067 +
  1068 +public define List(HTML_Head_Tag)
  1069 + to_HTML_Head_Tag
  1070 + (
  1071 + List(JS_File) js_file_list
  1072 + )=
  1073 + map((JS_File js_f) |-> js(js_f), js_file_list).
  1074 +
  1075 +public type HTML_In_Form:
  1076 + literal_pt (Printable_tree),
  1077 + literal (String),
  1078 + sequence (List(HTML_In_Form) items),
  1079 + text (List(Text_Option), String the_text),
  1080 + preformated (List(Text_Option), String),
  1081 + paragraph (List(Text_Option), HTML_In_Form content),
  1082 + image (List(CoreAttrs), String url, String alternate),
  1083 + image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  1084 + table (List(Table_Option), HTML_Header_Row(HTML_In_Form), List(HTML_Row(HTML_In_Form)), HTML_Footer_Row(HTML_In_Form)),
  1085 + center (HTML_In_Form),
  1086 + mail_to (String email, HTML_In_Form element),
  1087 + scroller (Int width, Int height,
  1088 + Int content_width, Int content_height,
  1089 + HTML_In_Form content),
  1090 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1091 + String action_name, List((String,String)) extra_ops,
  1092 + List(Actioner_Local_Action)),
  1093 + foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  1094 + foreign_link (List(Text_Option), String url),
  1095 + foreign_link (List(Text_Option), String url, String name),
  1096 + private_download (String abs_path, String name, String extra_ext,
  1097 + Maybe((String,List((String,String)))) action),
  1098 + text_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1099 + text_input_ro (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1100 + password_input (List(InputAttrs), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width),
  1101 + text_area (List(TextAreaOption), String label_text, HtmlId id, WebArgName name, InitialValue init, Int width, Int height),
  1102 + file_upload (List(InputAttrs), String label, HtmlId id, WebArgName name, Int width),
  1103 + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices),
  1104 + selector (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List(String) choices, InitialValue selected),
  1105 + // List((String,String)) = List((code,name)) where :
  1106 + // code is the web-arg value
  1107 + // name appears in selector
  1108 + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices),
  1109 + selector_c (List(InputAttrs), String label_text, HtmlId id, WebArgName name, Int size, List((WebArgValue,String)) choices, InitialValue selected),
  1110 + radio_button (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1111 + radio_button_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1112 + check_box (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1113 + check_box_r (List(InputAttrs), String label_text, HtmlId id, WebArgName name, WebArgValue value, Bool checked),
  1114 + div (List(CoreAttrs), HTML_In_Form content),
  1115 + div_empty (List(CoreAttrs)),
  1116 + hidden (HtmlId id, WebArgName name, InitialValue init).
  1117 +
  1118 +
  1119 + 'HTML_In_Form' defines all the elements you may put within a form. We define a
  1120 + convenience function:
  1121 +
  1122 +public define HTML_In_Form literal(Printable_tree t) = literal_pt(t).
  1123 +
  1124 +public define HTML_In_Form image(String url) = image([], url, url).
  1125 +
  1126 +public define HTML_In_Form image(String url, Int width, Int height) = image([], url, url, width, height).
  1127 +
  1128 +public define HTML_In_Form
  1129 + foreign_link
  1130 + (
  1131 + Int tsize,
  1132 + String url,
  1133 + String name
  1134 + ) =
  1135 + foreign_link([size(tsize)],url,name).
  1136 +
  1137 +public define HTML_In_Form
  1138 + actioner
  1139 + (
  1140 + Actioner_Connection conn,
  1141 + Actioner_Target targ,
  1142 + Actioner_Aspect asp,
  1143 + String action_name,
  1144 + List((String,String)) extra_ops
  1145 + ) =
  1146 + actioner(conn,targ,asp,action_name,extra_ops,[]).
  1147 +
  1148 +public define HTML_In_Form
  1149 + actioner
  1150 + (
  1151 + Actioner_Connection conn,
  1152 + Actioner_Target targ,
  1153 + Actioner_Aspect asp,
  1154 + ) =
  1155 + actioner(conn, targ, asp, "", [], []).
  1156 +
  1157 +
  1158 +public define HTML_In_Form
  1159 + text_area
  1160 + (
  1161 + WebArgName name,
  1162 + InitialValue init,
  1163 + Int width,
  1164 + Int height
  1165 + ) =
  1166 + text_area([], "", htmlId(""), name,init,width,height).
  1167 +
  1168 +public define HTML_In_Form
  1169 + text_area
  1170 + (
  1171 + List(TextAreaOption) options,
  1172 + WebArgName name,
  1173 + InitialValue init,
  1174 + Int width,
  1175 + Int height
  1176 + ) =
  1177 + text_area(options, "", htmlId(""), name,init,width,height).
  1178 +
  1179 +public define HTML_In_Form
  1180 + table
  1181 + (
  1182 + List(HTML_Row(HTML_In_Form)) rows
  1183 + ) =
  1184 + table([],empty,rows,empty).
  1185 +
  1186 +public define HTML_In_Form
  1187 + table
  1188 + (
  1189 + List(Table_Option) options,
  1190 + List(HTML_Row(HTML_In_Form)) rows
  1191 + ) =
  1192 + table(options,empty,rows,empty).
  1193 +
  1194 +public define HTML_In_Form
  1195 + table
  1196 + (
  1197 + HTML_Header_Row(HTML_In_Form) h_row,
  1198 + List(HTML_Row(HTML_In_Form)) rows
  1199 + ) =
  1200 + table([],h_row,rows,empty).
  1201 +
  1202 +public define HTML_In_Form
  1203 + table
  1204 + (
  1205 + List(Table_Option) options,
  1206 + HTML_Header_Row(HTML_In_Form) h_row,
  1207 + List(HTML_Row(HTML_In_Form)) rows
  1208 + ) =
  1209 + table(options,h_row,rows,empty).
  1210 +
  1211 +public define HTML_In_Form
  1212 + private_download
  1213 + (
  1214 + String abs_path,
  1215 + String name,
  1216 + String extra_ext
  1217 + ) =
  1218 + private_download(abs_path,name,extra_ext,failure).
  1219 +
  1220 +public define HTML_In_Form
  1221 + private_download
  1222 + (
  1223 + String abs_path,
  1224 + String name,
  1225 + String extra_ext,
  1226 + String action_name,
  1227 + List((String,String)) args
  1228 + ) =
  1229 + private_download(abs_path,name,extra_ext,success((action_name,args))).
  1230 +
  1231 +public define HTML_In_Form
  1232 + text
  1233 + (
  1234 + String s
  1235 + ) =
  1236 + text([],s).
  1237 +
  1238 +public define HTML_In_Form
  1239 + radio_button (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1240 + = radio_button (options, label_text, htmlId(n.name), n, value, checked).
  1241 +
  1242 +public define HTML_In_Form
  1243 + radio_button_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1244 + = radio_button_r (options, label_text, htmlId(n.name), n, value, checked).
  1245 +
  1246 +public define HTML_In_Form
  1247 + check_box (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1248 + = check_box (options, label_text, htmlId(n.name), n, value, checked).
  1249 +
  1250 +public define HTML_In_Form
  1251 + check_box_r (List(InputAttrs) options, String label_text, WebArgName n, WebArgValue value, Bool checked)
  1252 + = check_box_r (options, label_text, htmlId(n.name), n, value, checked).
  1253 +
  1254 +public define HTML_In_Form
  1255 + file_upload (WebArgName name, Int width)
  1256 + = file_upload([], "", htmlId(""), name, width).
  1257 +
  1258 +public define HTML_In_Form
  1259 + hidden (WebArgName name, InitialValue init)
  1260 + = if name is wan(web_name) then
  1261 + hidden(htmlId(web_name), name, init).
  1262 +
  1263 +public type HTML_Body:...
  1264 +
  1265 +public type HTML_Off_Form:
  1266 + literal_pt (Printable_tree),
  1267 + literal (String),
  1268 + sequence (List(HTML_Off_Form) items),
  1269 + text (List(Text_Option), String the_text),
  1270 + preformated (List(Text_Option), String),
  1271 + paragraph (List(Text_Option), HTML_Off_Form content),
  1272 + image (List(CoreAttrs), String url, String alternate),
  1273 + image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  1274 + table (List(Table_Option), HTML_Header_Row(HTML_Off_Form), List(HTML_Row(HTML_Off_Form)), HTML_Footer_Row(HTML_Off_Form)),
  1275 + center (HTML_Off_Form),
  1276 + mail_to (String email, HTML_Off_Form element),
  1277 + scroller (Int width, Int height,
  1278 + Int content_width, Int content_height,
  1279 + HTML_Off_Form content),
  1280 + fixed_size (HTML_Size width, HTML_Size height, HTML_Off_Form content),
  1281 + fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),
  1282 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1283 + String action_name, List((String,String)) extra_ops,
  1284 + List(Actioner_Local_Action)),
  1285 + actioner (Actioner_Connection, Actioner_Target, Actioner_Aspect,
  1286 + String action_name, List((String,String)) extra_ops,
  1287 + List(Actioner_Local_Action), String form_name),
  1288 + foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  1289 + foreign_link (List(Text_Option), String url),
  1290 + foreign_link (List(Text_Option), String url, String name),
  1291 + private_download (String abs_path, String name, String extra_ext,
  1292 + Maybe((String,List((String,String)))) action),
  1293 + label (String name),
  1294 + form (HtmlId form_id, List(CoreAttrs), HTML_In_Form content),
  1295 + form (HtmlId form_id, List(CoreAttrs),
  1296 + String action_name, List((String,String)) extra_ops,
  1297 + HTML_In_Form content),
  1298 + div (List(CoreAttrs), HTML_Off_Form content),
  1299 + div_empty (List(CoreAttrs)),
  1300 + iframe (List(CoreAttrs),
  1301 + List(CSS_Style) /*styles*/,
  1302 + List(CSS_File) /*css_files*/,
  1303 + List(JS_File) /*js_files*/,
  1304 + HTML_Body /*body*/).
  1305 +
  1306 + 'HTML_Off_Form' defines all the elements you may put outside any form.
  1307 +
  1308 +
  1309 +public define HTML_Off_Form image(String url) = image([], url, url).
  1310 +
  1311 +public define HTML_Off_Form image(String url, Int width, Int height) = image([], url, url, width, height).
  1312 +
  1313 +public define HTML_Off_Form
  1314 + form
  1315 + (
  1316 + String form_name,
  1317 + List(CoreAttrs) options,
  1318 + HTML_In_Form content
  1319 + ) =
  1320 + form(htmlId(form_name), options, content).
  1321 +
  1322 +public define HTML_Off_Form
  1323 + form
  1324 + (
  1325 + String form_name,
  1326 + List(CoreAttrs) options,
  1327 + String action_name,
  1328 + List((String,String)) extra_ops,
  1329 + HTML_In_Form content
  1330 + ) =
  1331 + form(htmlId(form_name), options, action_name, extra_ops, content).
  1332 +
  1333 +
  1334 +public define HTML_Off_Form literal(Printable_tree t) = literal_pt(t).
  1335 +public define HTML_Off_Form fixed_size(HTML_Size width, HTML_Size height, String name_of_HTML_file)
  1336 + = fixed_size_2(width,height,name_of_HTML_file).
  1337 +
  1338 +
  1339 +public define HTML_Off_Form
  1340 + foreign_link
  1341 + (
  1342 + Int tsize,
  1343 + String url,
  1344 + String name
  1345 + ) =
  1346 + foreign_link([size(tsize)],url,name).
  1347 +
  1348 +
  1349 +public define HTML_Off_Form
  1350 + actioner
  1351 + (
  1352 + Actioner_Connection conn,
  1353 + Actioner_Target targ,
  1354 + Actioner_Aspect asp,
  1355 + String action_name,
  1356 + List((String,String)) extra_ops
  1357 + ) =
  1358 + actioner(conn,targ,asp,action_name,extra_ops,[]).
  1359 +
  1360 +public define HTML_Off_Form
  1361 + table
  1362 + (
  1363 + List(HTML_Row(HTML_Off_Form)) rows
  1364 + ) =
  1365 + table([],empty,rows,empty).
  1366 +
  1367 +public define HTML_Off_Form
  1368 + table
  1369 + (
  1370 + List(Table_Option) options,
  1371 + List(HTML_Row(HTML_Off_Form)) rows
  1372 + ) =
  1373 + table(options,empty,rows,empty).
  1374 +
  1375 +public define HTML_Off_Form
  1376 + table
  1377 + (
  1378 + HTML_Header_Row(HTML_Off_Form) h_row,
  1379 + List(HTML_Row(HTML_Off_Form)) rows
  1380 + ) =
  1381 + table([],h_row,rows,empty).
  1382 +
  1383 +public define HTML_Off_Form
  1384 + table
  1385 + (
  1386 + List(Table_Option) options,
  1387 + HTML_Header_Row(HTML_Off_Form) h_row,
  1388 + List(HTML_Row(HTML_Off_Form)) rows
  1389 + ) =
  1390 + table(options,h_row,rows,empty).
  1391 +
  1392 + We add two convenience functions for 'row'. The reason why we add two functions, one
  1393 + for 'HTML_In_Form' and one for 'HTML_Off_Form', is that adding a schema with an
  1394 + arbitrary '$T' creates too many ambiguities. This is due to the fact that, if we do so,
  1395 + the arguments of the function do not refer to any of the types defined here.
  1396 +
  1397 +public define HTML_Row(HTML_In_Form)
  1398 + row
  1399 + (
  1400 + HTML_In_Form content
  1401 + ) =
  1402 + row([],[cell([],content)]).
  1403 +
  1404 +public define HTML_Row(HTML_Off_Form)
  1405 + row
  1406 + (
  1407 + HTML_Off_Form content
  1408 + ) =
  1409 + row([],[cell([],content)]).
  1410 +
  1411 +
  1412 +public define HTML_Off_Form
  1413 + private_download
  1414 + (
  1415 + String abs_path,
  1416 + String name,
  1417 + String extra_ext
  1418 + ) =
  1419 + private_download(abs_path,name,extra_ext,failure).
  1420 +
  1421 +
  1422 +public define HTML_Off_Form
  1423 + private_download
  1424 + (
  1425 + String abs_path,
  1426 + String name,
  1427 + String extra_ext,
  1428 + String action_name,
  1429 + List((String,String)) args
  1430 + ) =
  1431 + private_download(abs_path,name,extra_ext,success((action_name,args))).
  1432 +
  1433 +public define HTML_Off_Form
  1434 + text
  1435 + (
  1436 + List(Text_Option) lto,
  1437 + Int i
  1438 + ) =
  1439 + text(lto,to_decimal(i)).
  1440 +
  1441 +
  1442 +public define HTML_Off_Form
  1443 + text
  1444 + (
  1445 + Int i
  1446 + ) =
  1447 + text([],i).
  1448 +
  1449 +public define HTML_Off_Form
  1450 + text
  1451 + (
  1452 + String s
  1453 + ) =
  1454 + text([],s).
  1455 +
  1456 + - Cell a gap between two other cells :
  1457 +
  1458 +public define HTML_Cell(HTML_Off_Form)
  1459 + width_gap
  1460 + (
  1461 + Int w
  1462 + ) =
  1463 + cell([width(w)],text([],"")).
  1464 +
  1465 +public define HTML_Cell(HTML_In_Form)
  1466 + width_gap
  1467 + (
  1468 + Int w
  1469 + ) =
  1470 + cell([width(w)],text([],"")).
  1471 +
  1472 +
  1473 + - Row a gap between two other rows :
  1474 +
  1475 +public define HTML_Row(HTML_Off_Form)
  1476 + height_gap
  1477 + (
  1478 + Int h
  1479 + ) =
  1480 + row([],[cell([height(h)],text([],""))]).
  1481 +
  1482 +public define HTML_Row(HTML_In_Form)
  1483 + height_gap
  1484 + (
  1485 + Int h
  1486 + ) =
  1487 + row([],[cell([height(h)],text([],""))]).
  1488 +
  1489 +
  1490 + Notice that the two types have alternatives in common (same name, same arguments types,
  1491 + up to the value of the parameter $T), which correspond to elements which may be put
  1492 + anywhere in the page.
  1493 +
  1494 +
  1495 +
  1496 +
  1497 +define String
  1498 + format
  1499 + (
  1500 + List(Text_Option) l
  1501 + ).
  1502 +
  1503 +
  1504 +
  1505 +
  1506 +define Printable_tree
  1507 + format_css_styles
  1508 + (
  1509 + List(CSS_Style) l
  1510 + ) =
  1511 + if l is
  1512 + {
  1513 + [ ] then [ ],
  1514 + [h . t] then
  1515 + [ if h is
  1516 + {
  1517 + text_options(tos) then
  1518 + [" body, span, p { ", format(tos), " }\n" ]
  1519 + }
  1520 + . format_css_styles(t)]
  1521 + }.
  1522 +
  1523 +
  1524 +
  1525 +public type HTML_Meta:
  1526 + keywords (List(String)),
  1527 + refresh (Actioner_Connection connection,
  1528 + Actioner_Target target,
  1529 + String action_name,
  1530 + Int delay), // in seconds
  1531 + refresh (String url, Int delay), // in seconds
  1532 + meta (String name, String content),
  1533 + http_equiv (String name, String content),
  1534 + generic_meta (List((String,String))),
  1535 + literal (String).
  1536 +
  1537 + Meta tags are put in the 'head' of the HTML page.
  1538 +
  1539 +
  1540 +public type Body_Option:
  1541 + core_attrs(List(CoreAttrs)),
  1542 + background_color (RGB),
  1543 + background_image (String url),
  1544 + background_image (String url, List(BackgroundOption)).
  1545 +
  1546 +public type HTML_Body:
  1547 + body(List(Body_Option) options, HTML_Off_Form content).
  1548 +
  1549 +
  1550 +public type HTTP_Answer:
  1551 + html_page (HTTP_Status /*http_status*/,
  1552 + List(HTML_Head_Tag) /*html <head> tags*/,
  1553 + HTML_Body /*body*/),
  1554 + html_page (HTTP_Status /*http_status*/,
  1555 + String /*title*/,
  1556 + List(HTML_Meta) /*meta_tags*/,
  1557 + List(CSS_Style) /*styles*/,
  1558 + List(CSS_File) /*css_files*/,
  1559 + List(JS_File) /*js_files*/,
  1560 + List(Script) /*script*/,
  1561 + HTML_Body /*body*/),
  1562 + plain_text (HTTP_Status /*http_status*/,
  1563 + String /*text*/),
  1564 + custom_text (HTTP_Status /*http_status*/,
  1565 + String /*mime_type*/,
  1566 + String /*content*/),
  1567 + custom_binary(HTTP_Status /*http_status*/,
  1568 + String /*mime_type*/,
  1569 + ByteArray /*content*/,
  1570 + List(HTTP_header)/*other headers*/),
  1571 + custom_tree (HTTP_Status /*http_status*/,
  1572 + String /*mime_type*/,
  1573 + Printable_tree /*content*/),
  1574 + http_raw (Printable_tree),
  1575 + html_content (HTTP_Status /*http_status*/,
  1576 + HTML_Off_Form).
  1577 +
  1578 +
  1579 +public define HTTP_Answer
  1580 + html_page
  1581 + (
  1582 + String title,
  1583 + List(HTML_Meta) metas,
  1584 + HTML_Body body
  1585 + ) =
  1586 + html_page(http_ok, title,metas,[],[],[],[],body).
  1587 +
  1588 +public define HTTP_Answer
  1589 + html_page
  1590 + (
  1591 + String title,
  1592 + List(HTML_Meta) metas,
  1593 + List(CSS_Style) styles,
  1594 + HTML_Body body
  1595 + ) =
  1596 + html_page(http_ok, title, metas, styles, [], [], [], body).
  1597 +
  1598 + 'HTTP_Answer' represents the final product of the construction of a web page.
  1599 +
  1600 +
  1601 +
  1602 +
  1603 + *** (3.2) ``in form'' versus ``off form''.
  1604 +
  1605 + There is a variety of HTML elements: texts, buttons, links, forms, inputs, etc... Some
  1606 + of them may have a content, which is yet another HTML element (or several). Hence, it
  1607 + is meaningful to say that an element is 'within' another one. Now, putting any element
  1608 + within any other one may be meaningless. For example, an input element must be put
  1609 + within a form (otherwise, it is useless), and a from within another form has no precise
  1610 + meaning (and is forbidden by the HTML specification).
  1611 +
  1612 + Actually, the main criterium is ``within a form or not within a form''. So, HTML
  1613 + elements in a given page are separated into two categories: those who are within a
  1614 + form, and the others. Nevertheless, there are elements which may belong to both
  1615 + categories, like images and texts. We want to make use of the strong typing mecanism of
  1616 + Anubis in order to forbid non meaningful placement of elements.
  1617 +
  1618 + The type 'HTML_In_Form' defines elements to be put within forms. Similarly,
  1619 + 'HTML_Off_Form' defines elements not to be put within forms. Both types are recursive,
  1620 + and 'HTML_Off_Form' refers to 'HTML_In_Form' (via the 'form' alternative, of course),
  1621 + but the two types are not cross recursive. This is the reason why it is impossible to
  1622 + put a form within a form. In order to construct a web page, you essentially have to
  1623 + produce a datum of type 'HTML_Off_Form' (maybe containing data of type 'HTML_In_Form').
  1624 +
  1625 + In practice, you don't have to worry so much about these two types, because elements
  1626 + which may be put anywhere are constructed for both types by functions with the same
  1627 + name and the same arguments. Hence, for both types, you just write the same thing. You
  1628 + are warned by the compiler only when you try to put an element at a place it is not
  1629 + allowed.
  1630 +
  1631 +
  1632 +
  1633 + *** (3.3) Defining your own style.
  1634 +
  1635 + We provide generic tools for constructing HTML elements. However, your web site needs
  1636 + to have a ``style''.
  1637 +
  1638 + To that end, you need to write down a set of ``styling functions'', using the tools
  1639 + defined here. These styling functions allow the introduction of your colors and other
  1640 + visual characteristics into the constructed elements once and for all. For example, you
  1641 + may want all your texts to be rendered in the ``Helvetica'' font, in size 14 and using
  1642 + some 'text_color'. You may write something like this:
  1643 +
  1644 + define RGB text_color = rgb(10,40,40).
  1645 +
  1646 + define HTML_Off_Form
  1647 + text
  1648 + (
  1649 + String the_text
  1650 + ) =
  1651 + text([font("helvetica"),size(14),color(text_color)],
  1652 + the_text).
  1653 +
  1654 + (and the same one for type 'HTML_In_Form') so that in order to put a piece of text in a
  1655 + page, you just write:
  1656 +
  1657 + text("... some text ...")
  1658 +
  1659 + and you don't have to provide the font, size and color for each text. If you want to
  1660 + have several styles of text presentation, you just write several sets of such
  1661 + convenience functions. This also suggests a trick. You may want for example different
  1662 + colors for 'in form' texts and 'off form' texts. This may be achieved automatically by
  1663 + defining two functions as above, with the same name and same argument type, but
  1664 + returning either a 'HTML_In_Form' or a 'HTML_Off_Form'.
  1665 +
  1666 + If this preliminary work is well done, you will not waste your time later when you
  1667 + concentrate on the actual informational content of your pages.
  1668 +
  1669 + This general principle should be applied to all sorts of elements. This is the best
  1670 + thing to do in order to separate the functions defining the visual style from the
  1671 + functions defining the informational content itself, so that changing the style without
  1672 + changing the content becomes easy. This is also the best way for having a clean and
  1673 + easily readable source for your web site.
  1674 +
  1675 +
  1676 +
  1677 +
  1678 +
  1679 + *** (3.4) Actioners and forms.
  1680 +
  1681 + We have gathered several notions from HTML into that of an 'actioner'. An actioner is
  1682 + an HTML element which opens a connection to our server when clicked upon. Actioners may
  1683 + have different visual aspects. They may look like hypertext links or like buttons
  1684 + (rollovers), or even like selectors (with immediate action). In any case, their
  1685 + behavior is the same: they open a connection to our server, and send a set of 'web
  1686 + arguments', i.e. pairs 'name=value'. Among these web arguments, one of them denotes
  1687 + the action to be performed, and the others should be considered as operands for this
  1688 + action. Actually, the precise behavior of the actioner has several variants.
  1689 +
  1690 + The connection with the server may be secured (HTTPS) or non secured (HTTP). See the
  1691 + type 'Actioner_Connection' above.
  1692 +
  1693 + You must also choose where the answer must be rendered. This may be in the same window
  1694 + or in another window (or frame). If it is in another window, the name of that window
  1695 + must be given. If the window does not exist, the browser will create it. Optionally,
  1696 + you may give the dimensions of the new window and other characteristics. See the type
  1697 + 'Actioner_Target' above.
  1698 +
  1699 + The actioner also has a visual aspect. See the type 'Actioner_Aspect' above. In the
  1700 + case of a rollover button, you provide the URLs of two images (of the same size)
  1701 + representing the button:
  1702 +
  1703 + url_off: to be used when the mouse is not over the button,
  1704 + url_on: to be used when the mouse is over the button.
  1705 +
  1706 + You can also create rollover buttons without creating images. Just use the second
  1707 + alternative named 'button'. The server creates the images automatically.
  1708 +
  1709 + The purpose of forms is just to give operands to actioners. If the actioner is placed
  1710 + within a form, all the input elements which are within this form provide operands to
  1711 + the actioner (except sometimes when they are not set by the client). If it is not put
  1712 + within a form, the actioner gets no operand, except if the name of a form is explicitly
  1713 + given, in which case the actioner gets all the inputs from that form as
  1714 + operands. Furthermore, you may want to give extra operands to the actioner. This may be
  1715 + useful for separating families of actioners with the same action name. Extra operands
  1716 + 'name=value' must be given in the form of pairs '(name,value)'.
  1717 +
  1718 + Notice that the name of a form may be used by an actioner which is off the form, so as
  1719 + to get the operands provided by this form. Also notice that several actioners may refer
  1720 + to the same form, being either in the form, or referring to the form from the
  1721 + outside. These actioners simply get the same set of operands, even if they correspond
  1722 + to distinct actions.
  1723 +
  1724 + Input elements may be put only within a form.
  1725 +
  1726 +
  1727 +
  1728 + *** (3.5) Local popup.
  1729 +
  1730 + This element looks like a link or a rollover button. When this button is clicked upon,
  1731 + a 'popup window' appears. Actually, this popup window is just a layer in the same HTML
  1732 + page, which becomes suddenly visible. It is realized with a '<div>' HTML tag. In
  1733 + particular, clicking on the button does not open any connection. This is why it is
  1734 + called 'local'. The arguments have the following roles:
  1735 +
  1736 + Actioner_Aspect aspect of the button (same semantics as for actioners)
  1737 + content content of the popup window
  1738 + x, y, position of the popup window on the HTML page (not relative
  1739 + to the button but to the page itself)
  1740 + title title of the popup window
  1741 + color color of the title bar and close button in the popup window.
  1742 + A lightened version of this color is used for the background
  1743 + of the popup window.
  1744 + width width of the title bar
  1745 +
  1746 +
  1747 +
  1748 +
  1749 +
  1750 + --- That's all for the public part ! --------------------------------------------------
  1751 +
  1752 +
  1753 +
  1754 +
  1755 +
  1756 + ----------------------------------- Table of Contents ---------------------------------
  1757 +
  1758 + *** [1] States.
  1759 + *** [1.1] Saving and retrieving states.
  1760 + *** [1.2] Deleting out of date states.
  1761 +
  1762 + *** [2] Tools.
  1763 + *** [2.1] Directories.
  1764 + *** [2.2] Secondary documents.
  1765 +
  1766 + *** [3] Managing web arguments.
  1767 + *** [3.1] Prefixing web arguments names.
  1768 + *** [3.2] Separating web arguments.
  1769 + *** [3.3] Applying an action.
  1770 +
  1771 + *** [4] Web site descriptions and the 'awp handlers'.
  1772 + *** [4.1] The type 'Web_Site'.
  1773 + *** [4.2] Making a web site description.
  1774 + *** [4.3] Starting the servers.
  1775 +
  1776 + *** [5] HTML Formating.
  1777 + *** [5.1] The type 'HTML_Any($T)'.
  1778 + *** [5.2] Formating a color.
  1779 + *** [5.3] Creating buttons.
  1780 + *** [5.4] Formating an actioner.
  1781 + *** [5.5] Formating a private download link.
  1782 + *** [5.6] Formating rows and cells in a table.
  1783 + *** [5.7] Formating elements which may be put anywhere.
  1784 + *** [5.8] Formating 'in form' elements.
  1785 + *** [5.9] Formating 'off form' elements.
  1786 + *** [5.10] Formating meta-tags.
  1787 +
  1788 + ---------------------------------------------------------------------------------------
  1789 +
  1790 +
  1791 +
  1792 +
  1793 +public define String
  1794 + doctype_w3c_header
  1795 + =
  1796 + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "+
  1797 + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".
  1798 +
  1799 +public define String
  1800 + html_header
  1801 + =
  1802 + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n".
  1803 +
  1804 +
  1805 + *** [1] States.
  1806 +
  1807 + We have to define functions for saving a state, retrieving a state, deleting out of
  1808 + date states. We need one such function per web site. The types of the first two
  1809 + functions depend on the parameter $State. This is not the case of the third one. The
  1810 + fact that the instance of $State is variable from one web sites to the other implies
  1811 + rather subtle manipulations using full functionality.
  1812 +
  1813 +
  1814 + *** [1.1] Saving and retrieving states.
  1815 +
  1816 + Each state is saved into a file on the server's disk (in the directory represented by
  1817 + the symbol 'state_directory', which is 'my_anubis/web_sites/common_name/states'). The
  1818 + state is saved together with a time stamp whose value is obtained by adding the current
  1819 + time to the given timeout for states. The state receives a name obtained by hashing
  1820 + (using sha1) the content of the file itself, and then encoding the hash with
  1821 + 'web_arg_encode'. The name of the file into which the state is saved is the
  1822 + concatenation of "s" and the name of the state.
  1823 +
  1824 +read CXM_web_arg_encode.anubis
  1825 +
  1826 + The tool below constructs the function which is able to save a state on the server's
  1827 + disk.
  1828 +
  1829 +define ($State s) -> String // the function constructed returns the name of the state
  1830 + make_save_state_function
  1831 + (
  1832 + Int timeout,
  1833 + String state_directory
  1834 + ) =
  1835 + ($State s) |->
  1836 + with time_stamp = now+timeout,
  1837 + to_be_saved = (time_stamp,s),
  1838 + state_name = web_arg_encode(sha1(s)),
  1839 + if save(to_be_saved,state_directory+"/s"+state_name) is ok
  1840 + then state_name
  1841 + else (print("Cannot create state file in '"+state_directory+"'.\n"); "").
  1842 +
  1843 +
  1844 + When a request arrives, we need to retrieve the previous state from the server's
  1845 + disk. We receive the name of that state. If the state is out of date, the state file is
  1846 + kept 3 days, and then deleted.
  1847 +
  1848 +type PreviousState($State):
  1849 + not_found, // cannot retrieve the previous state
  1850 + out_of_date($State), // the previous state is out of date
  1851 + still_valid($State). // the previous state is still valid
  1852 +
  1853 +define (String state_name) -> PreviousState($State)
  1854 + make_retrieve_state_function
  1855 + (
  1856 + String state_directory
  1857 + ) =
  1858 + (String state_name) |->
  1859 + with file_path = state_directory+"/s"+state_name,
  1860 + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)
  1861 + then (
  1862 + if d is (time_stamp,s) then
  1863 + if time_stamp < now
  1864 + then (
  1865 + forget(remove(file_path));
  1866 + out_of_date(s)
  1867 + )
  1868 + else still_valid(s) // state has been successfully retrieved
  1869 + )
  1870 + else not_found.
  1871 +
  1872 +
  1873 +
  1874 + *** [1.2] Deleting out of date states.
  1875 +
  1876 + We also need to delete states which are out of date and which will never be deleted by
  1877 + the above method. This may be performed by a machine doing this periodically (say once
  1878 + per states life time period).
  1879 +
  1880 +define (List(String) file_names) -> One
  1881 + make_delete_out_of_date_states_function
  1882 + (
  1883 + Maybe($State) dummy,
  1884 + String state_directory
  1885 + ) =
  1886 + (List(String) file_names) |-df->
  1887 + if file_names is
  1888 + {
  1889 + [ ] then unique,
  1890 + [h . t] then
  1891 + with file_path = state_directory+"/"+h,
  1892 + if (RetrieveResult((Int,$State)))retrieve(file_path) is ok(d)
  1893 + then (
  1894 + if d is (time_stamp,data) then
  1895 + if time_stamp < now
  1896 + then (forget(remove(file_path)); df(t))
  1897 + else df(t)
  1898 + )
  1899 + else (forget(remove(file_path)); df(t))
  1900 + }.
  1901 +
  1902 +
  1903 + The 'labelled arrow' |-df-> is documented in 'documentation/en/anubis_doc.txt'.
  1904 +
  1905 + Note: The argument 'dummy' (of type Maybe($State)) is not used in the body of the
  1906 + function (hence its name). Nevertheless, it is required. Indeed, the Anubis compiler
  1907 + does not accept a parameter in the body of a function (here the parameter is required
  1908 + by the use of 'retrieve') if this parameter does not appear in the type of the
  1909 + function. This is because this would create ambiguities that no explicit typing may
  1910 + ever resolve. If you put a double slash in front of the declaration of 'dummy' above,
  1911 + and if you compile this file, you will get a message like this one:
  1912 +
  1913 + Error in 'making_a_web_site.anubis', line 1300, column 7:
  1914 + A definition may not contain parameters which are not present
  1915 + in the declaration part (hidden parameters):
  1916 + $State
  1917 +
  1918 + The type of the function constructed by 'make_delete_out_of_date_states_function' is
  1919 + independant of the parameter $State. This is important because this allows to create
  1920 + the list of such functions for all web sites. From this list, it is possible to call
  1921 + the functions one after the other, so deleting out of date states for all web
  1922 + sites. Actually, the next function receives a list of pairs (state_directory,function),
  1923 + one for each web site.
  1924 +
  1925 +define One
  1926 + delete_out_of_date_states // for all web sites
  1927 + (
  1928 + List((String, List(String) -> One)) directories_and_functions
  1929 + ) =
  1930 + if directories_and_functions is
  1931 + {
  1932 + [ ] then unique,
  1933 + [h . t] then if h is (state_directory,function) then
  1934 + function(directory_list(state_directory,"s*"));
  1935 + delete_out_of_date_states(t)
  1936 + }.
  1937 +
  1938 +
  1939 + The above function must be called periodically in a separate virtual machine. The
  1940 + period we have choosen is (rather logically) the life time of states itself. This may
  1941 + be achieved by an 'infinite' loop, using a 'sleep(timeout)'. However, the loop must not
  1942 + be really infinite, because the servers may be shutdown. Hence, our loop must test
  1943 + (rather frequently; say every second) if the servers are down. If they are, the loop
  1944 + must be exited.
  1945 +
  1946 +define One
  1947 + delete_states_loop
  1948 + (
  1949 + List((String,List(String) -> One)) directories_and_functions,
  1950 + Int timeout,
  1951 + Int next_time,
  1952 + Server http_server,
  1953 + Server https_server,
  1954 + (One) -> Bool shutdown_required
  1955 + ) =
  1956 + if shutdown_required(unique)
  1957 + then (shutdown(http_server); shutdown(https_server))
  1958 + else unique;
  1959 + if (is_down(http_server) & is_down(https_server))
  1960 + then unique
  1961 + else if now > next_time
  1962 + then
  1963 + (
  1964 + delete_out_of_date_states(directories_and_functions);
  1965 + delete_states_loop(directories_and_functions,
  1966 + timeout,
  1967 + now+timeout,
  1968 + http_server,
  1969 + https_server,
  1970 + shutdown_required)
  1971 + )
  1972 + else
  1973 + (
  1974 + sleep(1000); // sleep just one second and try again
  1975 + delete_states_loop(directories_and_functions,
  1976 + timeout,
  1977 + next_time,
  1978 + http_server,
  1979 + https_server,
  1980 + shutdown_required)
  1981 + ).
  1982 +
  1983 + The above loop must be run in a separate virtual machine. This will be done just after
  1984 + the two servers are started.
  1985 +
  1986 +
  1987 +
  1988 +
  1989 +
  1990 + *** [2] Tools.
  1991 +
  1992 + *** [2.1] Directories.
  1993 +
  1994 + We need a tool for creating directories (if needed).
  1995 +
  1996 + (This tool has been moved to 'tools/basis.anubis').
  1997 +
  1998 +
  1999 +
  2000 +
  2001 + *** [2.2] Secondary documents.
  2002 +
  2003 + Some HTML elements (like '<object>', '<frame>') cannot receive their content directly
  2004 + from the current document, but only through an URL. For this reason, we implement a
  2005 + mecanism for creating secondary documents on the fly. To that end we use the 'private
  2006 + download' mecanism.
  2007 +
  2008 + A secondary document is formated by the same functions as the main document itself. The
  2009 + next function takes an 'off form' element, creates the file containing the secondary
  2010 + document in HTML format, and returns the URL at which the document will be available.
  2011 +
  2012 +define String
  2013 + create_secondary_document
  2014 + (
  2015 + String sd, // site directory
  2016 + String as, // authorization_secret
  2017 + String sn, // state name
  2018 + $T -> Printable_tree format_element,
  2019 + $T content,
  2020 + HTML_Size width
  2021 + ) =
  2022 + with private_download_directory = sd+"/private_download",
  2023 + hash = web_arg_encode(sha1(content)),
  2024 + file_content = (Printable_tree)
  2025 + [doctype_w3c_header,
  2026 + "<html><body><table ",
  2027 + if width is
  2028 + {
  2029 + absolute(w) then ["width=\"",w-25],
  2030 + percentage(w) then ["width=\"95%\""]
  2031 + },"\"><tbody><tr><td align=right>",
  2032 + format_element(content),
  2033 + "</td></tr></tbody></table></body></html>"
  2034 + ],
  2035 + file_name = "sd"+hash+".html",
  2036 + file_path = private_download_directory+"/"+file_name,
  2037 + if write_to_file(file_path,file_content) is
  2038 + {
  2039 + cannot_open_file then print("Cannot open file '"+file_path+"'.\n"); "",
  2040 + write_error(n) then print("Error writing file '"+file_path+"'.\n"); "",
  2041 + ok then file_name+"?zauth="+
  2042 + make_authorization(sd,as,private_download_directory+"/"+file_name)
  2043 + }.
  2044 +
  2045 +
  2046 +
  2047 +
  2048 + *** [2.3] Generating unique ids.
  2049 +
  2050 + In order to uniquely name object for JavaScript we generate unique ids from a counter.
  2051 +
  2052 +define Int
  2053 + new_idnum
  2054 + (
  2055 + Var(Int) ic_v // 'idnum' counter variable
  2056 + ) =
  2057 + protect
  2058 + with result = *ic_v+1,
  2059 + ic_v <- result;
  2060 + result.
  2061 +
  2062 +
  2063 +
  2064 +
  2065 +
  2066 +
  2067 + *** [3] Managing web arguments.
  2068 +
  2069 + Web arguments are those pairs 'name=value' which are transmitted through the HTTP
  2070 + protocol. We need precise naming conventions for these web arguments.
  2071 +
  2072 +
  2073 +
  2074 + *** [3.1] Prefixing web arguments names.
  2075 +
  2076 + CR 2008-07-08 Prefixing Removed
  2077 +
  2078 +
  2079 +
  2080 + *** [3.2] Separating web arguments.
  2081 +
  2082 + When a new request arrives, we need to separate the web arguments, that is to say:
  2083 +
  2084 + - find the value of "s", and recover the corresponding state,
  2085 + - find the value of "a", which is the name of the action to be performed,
  2086 + - get the list of all the remaining web arguments (operands of the action).
  2087 +
  2088 + We must also determine if the previous state may be recovered. If it is not the case
  2089 + (either because the previous state name is invalid, or the previous state is out of
  2090 + date), we must check if there is an action name. Indeed, the presence of an action name
  2091 + indicates that the user has clicked on one of our buttons or links. If on the contrary
  2092 + there is no action name the user has just entered our address in his browser. In this
  2093 + last case, we must send the first page of our site (maybe a 'login' page), but if there
  2094 + is an action, we must send a page just saying that the session ticket has expired. If
  2095 + the previous state is recovered and there is no action, the new state is the same as
  2096 + the previous state.
  2097 +
  2098 + The result of the separation of the web arguments is of type:
  2099 +
  2100 +type Separated_Web_Args($State):
  2101 + swa(PreviousState($State) previous_state,
  2102 + Maybe(String) action_name,
  2103 + List(Web_arg) operands).
  2104 +
  2105 +
  2106 +
  2107 + The next function constructs the function which separates the web arguments.
  2108 +
  2109 +define (List(Web_arg) lwa, HTTP_Info info) -> Separated_Web_Args($State)
  2110 + make_separate_web_args_function
  2111 + (
  2112 + String state_directory,
  2113 + String -> PreviousState($State) retrieve_state,
  2114 + String website_name
  2115 + ) =
  2116 + (List(Web_arg) lwa, HTTP_Info info) |-swaf->
  2117 + if lwa is
  2118 + {
  2119 + [ ] then
  2120 + //
  2121 + // no web arg found => no previous state and no action
  2122 + //
  2123 + if find_cookie("state_"+website_name, server_get_cookies(http_headers(info))) is
  2124 + {
  2125 + failure then swa(not_found,failure,[]),
  2126 + success(cookie) then swa(retrieve_state(value(cookie)),failure,[])
  2127 + },
  2128 +
  2129 + //swa(failure,failure,[]),
  2130 +
  2131 + [wa_1 . wa_others] then
  2132 + //
  2133 + // at least one web arg =>
  2134 + // separate other web args, and insert the first one as needed
  2135 + //
  2136 + if (Separated_Web_Args($State))swaf(wa_others, info) is
  2137 + {
  2138 + swa(ps1, // possible previous state
  2139 + an1, // maybe an action name
  2140 + op1) // operands so far
  2141 + then
  2142 + if wa_1 is
  2143 + {
  2144 + web_arg(n, value) then
  2145 + with name = if substr(n,0,4) = "amp;" then substr(n, 4, length(n) - 4) else n,
  2146 + if name = "a" then
  2147 + swa(ps1,success(value),op1)
  2148 + else if name = "t" then
  2149 + swa(ps1,an1,[web_arg("target",value) . op1])
  2150 + else
  2151 + swa(ps1,an1,[web_arg(name,value) . op1]),
  2152 +
  2153 + upload(n,v,t) then
  2154 + swa(ps1,an1,[wa_1 . op1])
  2155 + }
  2156 + }
  2157 + }.
  2158 +
  2159 +
  2160 +
  2161 +
  2162 +
  2163 +
  2164 + *** [3.3] Applying an action.
  2165 +
  2166 + When the web arguments are separated (and their names cleaned up from prefixes), we may
  2167 + apply the action to the operands and the current state. We search for the action to be
  2168 + applied in the list of actions. If no action is found, the new state is the same as
  2169 + the previous state. Also, we deny the application of an HTTP action if the request
  2170 + arrives through the HTTPS channel and conversely.
  2171 +
  2172 +
  2173 +define ($State previous,
  2174 + String action_name,
  2175 + HTTP_Info http_info,
  2176 + List(Web_arg) lwa,
  2177 + Bool is_https) -> $State
  2178 + make_apply_action_function
  2179 + (
  2180 + List(Web_Action($State)) actions_list
  2181 + ) =
  2182 + with f =
  2183 + ($State previous,
  2184 + String action_name,
  2185 + HTTP_Info http_info,
  2186 + List(Web_arg) lwa,
  2187 + Bool is_https,
  2188 + List(Web_Action($State)) actions) |-f->
  2189 + //println("Looking for action ["+action_name+"]");
  2190 + if actions is
  2191 + {
  2192 + [ ] then print("action '"+action_name+
  2193 + "' not found.\n"); previous,
  2194 + [ac1 . others] then if ac1 is
  2195 + {
  2196 + http_action(an,allow,do_it) then
  2197 + if an = action_name
  2198 + then if is_https
  2199 + then (print("HTTP action '"+an+
  2200 + "' called through HTTPS (denied).\n");
  2201 + previous)
  2202 + else if allow(previous)
  2203 + then do_it(http_info,lwa,previous)
  2204 + else previous
  2205 + else f(previous,action_name,http_info,lwa,is_https,others),
  2206 +
  2207 + https_action(an,allow,do_it) then
  2208 + if an = action_name
  2209 + then if is_https
  2210 + then if allow(previous)
  2211 + then do_it(http_info,lwa,previous)
  2212 + else previous
  2213 + else (print("HTTPS action '"+an+
  2214 + "' called through HTTP (denied).\n");
  2215 + previous)
  2216 + else f(previous,action_name,http_info,lwa,is_https,others),
  2217 +
  2218 + http_https_action(an,allow,do_it) then
  2219 + if an = action_name
  2220 + then
  2221 + //println("Action ["+action_name+"] found");
  2222 + if allow(previous)
  2223 + then do_it(http_info,lwa,previous)
  2224 + else previous
  2225 + else f(previous,action_name,http_info,lwa,is_https,others),
  2226 +
  2227 + }
  2228 + },
  2229 + ($State previous,
  2230 + String action_name,
  2231 + HTTP_Info http_info,
  2232 + List(Web_arg) lwa,
  2233 + Bool is_https) |->
  2234 + f(previous, action_name, http_info, lwa, is_https, actions_list).
  2235 +
  2236 +
  2237 +
  2238 +
  2239 +
  2240 +
  2241 +
  2242 +
  2243 + *** [4] Web site descriptions and the 'awp handlers'.
  2244 +
  2245 + *** [4.1] The type 'Web_Site'.
  2246 +
  2247 + The type 'Web_Site_Description' is defined in 'web/multihost_http_server.anubis'. We
  2248 + need another one, because, we have some extra informations to record for each site.
  2249 +
  2250 +public type Web_Site:
  2251 + web_site((Word32,Word32) -> Web_Site_Description description,
  2252 + List(String) -> One delete_out_of_date).
  2253 +
  2254 +
  2255 +
  2256 +
  2257 + *** [4.2] Making a web site description.
  2258 +
  2259 + Below is the function which creates a web site description. It first creates (if
  2260 + needed) the directories for the site, then constructs the tool functions for the site,
  2261 + and the site handler. Finally, it constructs the web site description.
  2262 +
  2263 + We gather common (constant) informations in the following type:
  2264 +
  2265 +public type CommonInfo:
  2266 + info(String common_name,
  2267 + Word32 http_port,
  2268 + Word32 https_port,
  2269 + String site_directory,
  2270 + String authorization_secret
  2271 + ).
  2272 +
  2273 + We need a forward declaration.
  2274 +
  2275 +public define Printable_tree
  2276 + format
  2277 + (
  2278 + CommonInfo cinfo,
  2279 + String state_name,
  2280 + List(HTTP_header) headers,
  2281 + HTTP_Answer page,
  2282 + Bool is_https,
  2283 + String charset
  2284 + ).
  2285 +
  2286 +
  2287 +define Printable_tree
  2288 + format
  2289 + (
  2290 + HTML_Size s
  2291 + ) =
  2292 + if s is
  2293 + {
  2294 + absolute(x) then ["\"",x,"\""],
  2295 + percentage(x) then ["\"",x,"%\""]
  2296 + }.
  2297 +
  2298 +define List(HTTP_header)
  2299 + make_state_cookie_headers
  2300 + (
  2301 + String website_name,
  2302 + String state_name
  2303 + )
  2304 + =
  2305 + [
  2306 + http_header("Set-Cookie", "state_"+website_name+"="+state_name)
  2307 + ]
  2308 + .
  2309 +
  2310 + public define Web_Site
  2311 + make_web_site_description
  2312 + (
  2313 + List(String) common_names, // for example: ["www.our-business.com",
  2314 + // "192.168.0.1"]
  2315 + // the second one is just for testing
  2316 + String site_directory, // where 'public' and other directories are
  2317 + // located (should NOT end with '/')
  2318 + One -> One init,
  2319 + (HTTP_Info,
  2320 + List(Web_arg),
  2321 + Bool is_https) -> $State initial_state,
  2322 + ($State expired,
  2323 + HTTP_Info,
  2324 + List(Web_arg),
  2325 + Bool is_https) -> $State ticket_expired_state,
  2326 + (HTTP_Info,
  2327 + List(Web_arg),
  2328 + Bool is_https) -> $State ticket_lost_state,
  2329 + List(Web_Action($State)) actions,
  2330 + $State -> HTTP_Answer compute_page,
  2331 + $State -> List(HTTP_header) additional_headers,
  2332 + Int timeout, // seconds (todo: minutes)
  2333 + Redirections redirections,
  2334 + String charset,
  2335 + List(String) journal_extensions,
  2336 + List(String) journal_headers,
  2337 + String authorization_secret,
  2338 + List(MIME) known_mime_types,
  2339 + (String action_name,
  2340 + List(Web_arg) args)-> One before_send_file
  2341 + ).
  2342 +
  2343 +
  2344 +public define Web_Site
  2345 + make_web_site_description
  2346 + (
  2347 + String website_name,
  2348 + List(String) common_names, // for example: ["www.our-business.com"]
  2349 + String site_directory,
  2350 + String state_directory,
  2351 + One -> One init,
  2352 + (HTTP_Info,
  2353 + List(Web_arg),
  2354 + Bool is_https) -> $State initial_state,
  2355 + ($State expired,
  2356 + Maybe(String),
  2357 + HTTP_Info,
  2358 + List(Web_arg),
  2359 + Bool is_https) -> $State ticket_expired_state,
  2360 + (Maybe(String),
  2361 + HTTP_Info,
  2362 + List(Web_arg),
  2363 + Bool is_https) -> $State ticket_lost_state,
  2364 + List(Web_Action($State)) actions,
  2365 + $State -> HTTP_Answer compute_page,
  2366 + $State -> List(HTTP_header) additional_headers,
  2367 + Int timeout,
  2368 + Redirections redirections,
  2369 + String charset,
  2370 + List(String) journal_extensions,
  2371 + List(String) journal_headers,
  2372 + String secret,
  2373 + List(MIME) known_mime_types,
  2374 + (String action_name,
  2375 + List(Web_arg) args) -> One before_send_file
  2376 + //Bool using_state_cookies
  2377 + ) =
  2378 + init(unique);
  2379 +
  2380 +
  2381 + //
  2382 + // make required directories (if needed)
  2383 + //
  2384 + with //web_sites_directory = (String) make_directory(my_anubis_directory+"/web_sites"),
  2385 + base_directory = (String) make_directory(site_directory),
  2386 + // state_directory = make_directory(site_directory+"/states"),
  2387 + forget((String)make_directory(site_directory+"/public"));
  2388 + //
  2389 + // construct tool functions
  2390 + // TODO 'make_separate_web_args_function' must retrieve state_cookies before parsing web_args if using_state_cookies is true
  2391 + with save_state = make_save_state_function(timeout, state_directory),
  2392 + retrieve_state = make_retrieve_state_function(state_directory),
  2393 + separate_web_args = make_separate_web_args_function(state_directory, retrieve_state, website_name),
  2394 + apply_action = make_apply_action_function(actions),
  2395 + //
  2396 + // construct the site handler
  2397 + //
  2398 + site_handler = (Word32 http_port, Word32 https_port) |->
  2399 + ((String host_name,
  2400 + HTTP_Info http_info,
  2401 + List(Web_arg) lwa,
  2402 + Bool is_https) |->
  2403 + //(Printable_tree)
  2404 + if separate_web_args(lwa, http_info) is
  2405 + {
  2406 + swa(mb_previous_state, mb_action_name, operands) then
  2407 + with new_state = if mb_previous_state is
  2408 + {
  2409 + not_found then
  2410 + //println("previous state not found");
  2411 + if mb_action_name is
  2412 + {
  2413 + failure then initial_state(http_info, operands, is_https),
  2414 + success(_) then
  2415 + ticket_lost_state(mb_action_name, http_info,operands,is_https)
  2416 + },
  2417 +
  2418 + out_of_date(state) then
  2419 + ticket_expired_state(state, mb_action_name, http_info,operands,is_https),
  2420 +
  2421 + still_valid(state) then
  2422 + if mb_action_name is
  2423 + {
  2424 + failure then state,
  2425 + success(action_name) then
  2426 + apply_action(state,action_name,http_info,operands,is_https)
  2427 + }
  2428 + },
  2429 + //if state_and_headers is (session_ticket, mb_new_state, headers) then
  2430 + with state_name = save_state(new_state),
  2431 + //println("Cookie new STATE NAME "+state_name);
  2432 + with cookie_headers = if mb_action_name is
  2433 + {
  2434 + failure then [],
  2435 + success(action_name) then
  2436 + if substr(action_name, 0, 5)="ajax_" then
  2437 + []
  2438 + else
  2439 + make_state_cookie_headers(website_name, state_name)
  2440 + },
  2441 +
  2442 + format(info(host_name, http_port, https_port, site_directory, secret),
  2443 + state_name,
  2444 + additional_headers(new_state) + cookie_headers,
  2445 + compute_page(new_state),
  2446 + is_https,
  2447 + charset)
  2448 + }),
  2449 + //
  2450 + // make the delete_out_of_date function
  2451 + //
  2452 + delete_out_of_date =
  2453 + make_delete_out_of_date_states_function((Maybe($State))failure,
  2454 + site_directory+"/states"),
  2455 + //
  2456 + // construct the web site description
  2457 + //
  2458 + web_site((Word32 http_port, Word32 https_port) |->
  2459 + web_site_description(common_names,
  2460 + site_directory,
  2461 + redirections,
  2462 + charset,
  2463 + journal_extensions,
  2464 + journal_headers,
  2465 + secret,
  2466 + known_mime_types,
  2467 + site_handler(http_port,https_port),
  2468 + (HTTP_Info http_info, List(Web_arg) lwa) |-> if separate_web_args(lwa, http_info ) is
  2469 + swa(mb_previous_state,mb_action_name,operands) then
  2470 + if mb_action_name is
  2471 + {
  2472 + failure then unique
  2473 + success(an) then before_send_file(an,operands)
  2474 + }
  2475 + //using_state_cookies
  2476 + ),
  2477 + delete_out_of_date).
  2478 +
  2479 +// Compatibility function for older websites
  2480 +public define Web_Site
  2481 + make_web_site_description
  2482 + (
  2483 + List(String) common_names, // for example: ["www.our-business.com"]
  2484 + String site_directory,
  2485 + String state_directory,
  2486 + One -> One init,
  2487 + (HTTP_Info,
  2488 + List(Web_arg),
  2489 + Bool is_https) -> $State initial_state,
  2490 + ($State expired,
  2491 + Maybe(String),
  2492 + HTTP_Info,
  2493 + List(Web_arg),
  2494 + Bool is_https) -> $State ticket_expired_state,
  2495 + (Maybe(String),
  2496 + HTTP_Info,
  2497 + List(Web_arg),
  2498 + Bool is_https) -> $State ticket_lost_state,
  2499 + List(Web_Action($State)) actions,
  2500 + $State -> HTTP_Answer compute_page,
  2501 + $State -> List(HTTP_header) additional_headers,
  2502 + Int timeout,
  2503 + Redirections redirections,
  2504 + String charset,
  2505 + List(String) journal_extensions,
  2506 + List(String) journal_headers,
  2507 + String secret,
  2508 + List(MIME) known_mime_types,
  2509 + (String action_name,
  2510 + List(Web_arg) args) -> One before_send_file
  2511 + //Bool using_state_cookies
  2512 + )
  2513 + =
  2514 + make_web_site_description("", common_names, site_directory, state_directory, init, initial_state, ticket_expired_state, ticket_lost_state, actions, compute_page, additional_headers, timeout, redirections, charset, journal_extensions, journal_headers, secret, known_mime_types, before_send_file)
  2515 + .
  2516 +
  2517 +
  2518 +
  2519 + *** [4.3] Starting the servers.
  2520 +
  2521 +public define Start_Web_Sites_Result
  2522 + start_web_sites
  2523 + (
  2524 + Word32 ip_address, // the IP address shared by the web sites
  2525 + Word32 http_port, // usually: 80
  2526 + Word32 https_port, // usually: 443
  2527 + String ssl_certificate_common_name,
  2528 + List(Web_Site) web_sites, // web sites to be started
  2529 + (One) -> Bool shutdown_required
  2530 + ) =
  2531 + with get_description = (Web_Site ws) |-> description(ws)(http_port,https_port),
  2532 + with http_server_r =
  2533 + start_http_server(ip_address,http_port,
  2534 + map(get_description,web_sites),
  2535 + load_denial_of_service_info),
  2536 + with https_server_r =
  2537 + start_https_server(ip_address,https_port,
  2538 + ssl_certificate_common_name,
  2539 + map(get_description,web_sites),
  2540 + load_denial_of_service_info),
  2541 + if http_server_r is ok(http_server)
  2542 + then
  2543 + (
  2544 + if https_server_r is ok(https_server)
  2545 + then
  2546 + (
  2547 + start_http_servers_tasks(map(get_description,web_sites),
  2548 + [http_server,https_server],
  2549 + 600); // period of 10 minutes
  2550 + delegate
  2551 + delete_states_loop(
  2552 + map((Web_Site ws) |->
  2553 + (site_directory(description(ws)(http_port,https_port))+
  2554 + "/states",delete_out_of_date(ws)),
  2555 + web_sites),
  2556 + 3600*24*3, // keep out of date states 3 days
  2557 + now,
  2558 + http_server,
  2559 + https_server,
  2560 + shutdown_required),
  2561 + ok(http_server,https_server)
  2562 + )
  2563 + else cannot_bind_to_port(https_port)
  2564 + )
  2565 + else
  2566 + (
  2567 + if https_server_r is ok(https_server)
  2568 + then cannot_bind_to_port(http_port)
  2569 + else cannot_bind_to_port(http_port,https_port)
  2570 + ).
  2571 +
  2572 +
  2573 +public define One
  2574 + start_web_sites
  2575 + (
  2576 + Word32 ip_address, // the IP address shared by the web sites
  2577 + Word32 http_port, // usually: 80
  2578 + Word32 https_port, // usually: 443
  2579 + String ssl_certificate_common_name,
  2580 + List(Web_Site) web_sites, // web sites to be started
  2581 + (One) -> Bool shutdown_required,
  2582 + Logger log
  2583 + ) =
  2584 + if (Start_Web_Sites_Result)start_web_sites(ip_address,
  2585 + http_port,
  2586 + https_port,
  2587 + ssl_certificate_common_name,
  2588 + web_sites,
  2589 + shutdown_required) is
  2590 + {
  2591 + cannot_bind_to_port(n) then logError(log, "Cannot bind to port: "+n),
  2592 + cannot_bind_to_port(n,m) then logError(log, "Cannot bind to ports: "+n+", "+m),
  2593 + ok(s1,s2) then logInfo(log, "Servers started on ports "+http_port+" (HTTP) and "+https_port+" (HTTPS).")
  2594 + }.
  2595 +
  2596 +
  2597 +
  2598 +
  2599 +
  2600 + *** [5] HTML Formating.
  2601 +
  2602 + We need to translate HTML elements as defined above into actual HTML text.
  2603 +
  2604 + Actioners require special informations, which must be transmitted when needed by the
  2605 + 'format' functions:
  2606 +
  2607 + - the 'common name', which is used for URLs,
  2608 + - the HTTP/HTTPS port number,
  2609 + - the 'state name', which must be transmitted when the actioner is clicked upon,
  2610 + - the 'form name' (if any) to which the actioner refers.
  2611 +
  2612 + If the actioner is off form, and if it refers to a form, the name of that form is
  2613 + already known by the actioner. On the contrary, if the actioner is 'in form', it refers
  2614 + implicitly to the form containing it. The name of that form is transmitted to the
  2615 + 'format' functions called from within the formating of that form.
  2616 +
  2617 +
  2618 +
  2619 +
  2620 + *** [5.1] The type 'HTML_Any($T)'.
  2621 +
  2622 + The type 'HTML_Any($T)' gathers elements which may be put anywhere in the page. The
  2623 + parameter $T becomes either 'HTML_Off_Form' or 'HTML_In_Form'.
  2624 +
  2625 +type HTML_Any($T):
  2626 + any_text (List(Text_Option), String the_text),
  2627 + any_preformated (List(Text_Option), String),
  2628 + any_paragraph (List(Text_Option), $T content),
  2629 + any_image (List(CoreAttrs), String url, String alternate),
  2630 + any_image (List(CoreAttrs), String url, String alternate, Int width, Int height),
  2631 + any_table (List(Table_Option), HTML_Header_Row($T), List(HTML_Row($T)), HTML_Footer_Row($T)),
  2632 + any_center ($T),
  2633 + any_mail_to (String email, $T element),
  2634 + any_scroller (Int width, Int height,
  2635 + Int content_width, Int content_height,
  2636 + $T content),
  2637 + any_fixed_size (HTML_Size width, HTML_Size height, $T content),
  2638 + any_fixed_size_2 (HTML_Size width, HTML_Size height, String name_of_HTML_file),
  2639 + any_actioner (Actioner_Connection,
  2640 + Actioner_Target,
  2641 + Actioner_Aspect,
  2642 + String action_name,
  2643 + List((String,String)) extra_ops,
  2644 + List(Actioner_Local_Action),
  2645 + Maybe(String) form_name),
  2646 + any_foreign_link_new (Actioner_Target, Actioner_Aspect, String url),
  2647 + any_foreign_link (List(Text_Option), String url),
  2648 + any_foreign_link (List(Text_Option), String url, String name),
  2649 + any_private_download (String abs_path, String name, String extra_ext,
  2650 + Maybe((String,List((String,String))))),
  2651 + any_div (List(CoreAttrs), $T element),
  2652 + any_div_empty (List(CoreAttrs)),
  2653 + any_coreattrs (List(CoreAttrs)).
  2654 +
  2655 +
  2656 +
  2657 + *** [5.2] Formating a color.
  2658 +
  2659 + RGB colors are formatted as '#rrggbb' where rr, gg and bb are two characters
  2660 + hexadecimal values.
  2661 +
  2662 +define String
  2663 + html_format
  2664 + (
  2665 + RGB color
  2666 + ) =
  2667 + if color is rgb(r,g,b) then
  2668 + "#" + to_hexa(r)
  2669 + + to_hexa(g)
  2670 + + to_hexa(b).
  2671 +
  2672 +
  2673 + The following is a very arbitrary definition of the opposite color. The thing which is
  2674 + important is that it is far from the original, so that characters in 'opposite' color
  2675 + are clearly visible over the original.
  2676 +
  2677 +define RGB
  2678 + opposite
  2679 + (
  2680 + RGB color
  2681 + ) =
  2682 + if color is rgb(r,g,b) then
  2683 + rgb(255-r,
  2684 + 255-g,
  2685 + 255-b).
  2686 +
  2687 +
  2688 +
  2689 +
  2690 + *** [5.3] Creating buttons.
  2691 +
  2692 + We want to be able to create buttons in the form of a pair of images (rollovers)
  2693 + automatically. We use the JPEG interface, because for the time being Anubis cannot
  2694 + handle other kinds of images.
  2695 +
  2696 +
  2697 + Computing printed text length.
  2698 +
  2699 + define Int
  2700 + printed_text_width
  2701 + (
  2702 + Word8 -> Int char_size,
  2703 + List(Word8) l
  2704 + ) =
  2705 + if l is
  2706 + {
  2707 + [] then (Int) 0,
  2708 + [h . t] then char_size(h) + 1+ printed_text_width(char_size,t)
  2709 + }.
  2710 +
  2711 + define Int
  2712 + printed_text_width
  2713 + (
  2714 + SystemFont font,
  2715 + String s
  2716 + ) =
  2717 + printed_text_width((Word8 c) |-> word8_to_int32(width(get_char_info(font,c))),
  2718 + explode(s)).
  2719 +
  2720 +
  2721 +
  2722 + Converting RGB to RGBA.
  2723 +
  2724 +define RGBA
  2725 + to_rgba
  2726 + (
  2727 + RGB color
  2728 + ) =
  2729 + if color is rgb(r,g,b) then rgba(r,g,b,255).
  2730 +
  2731 +
  2732 + Drawing a 'relief'.
  2733 +
  2734 + define One
  2735 + draw_relief
  2736 + (
  2737 + RGBAImage dest,
  2738 + RGBA color,
  2739 + Int contrast,
  2740 + Int x,
  2741 + Int y,
  2742 + Int width,
  2743 + Int height
  2744 + ) =
  2745 + with l = lighten(color,contrast),
  2746 + d = darken(color,contrast),
  2747 + draw_rectangle(dest,rect(x,y,x+width,y+1),l);
  2748 + draw_rectangle(dest,rect(x,y+1,x+1,y+height),l);
  2749 + draw_rectangle(dest,rect(x+width-1,y+1,x+width,y+height),d);
  2750 + draw_rectangle(dest,rect(x+1,y+height-1,x+width-1,y+height),d).
  2751 +
  2752 +
  2753 + Creating a button background.
  2754 +
  2755 + define RGBAImage
  2756 + create_button_background
  2757 + (
  2758 + RGBA color,
  2759 + Int width,
  2760 + Int height
  2761 + ) =
  2762 + with result = create_rgba_image(width,height,color),
  2763 + draw_relief(result,color,100,0,0,width,height);
  2764 + draw_relief(result,color,70,1,1,width-2,height-2);
  2765 + draw_relief(result,color,55,2,2,width-4,height-4);
  2766 + draw_relief(result,color,35,3,3,width-6,height-6);
  2767 + draw_relief(result,color,20,4,4,width-8,height-8);
  2768 + draw_relief(result,color,10,5,5,width-10,height-10);
  2769 + draw_relief(result,color,5,6,6,width-12,height-12);
  2770 + result.
  2771 +
  2772 +
  2773 + Drawing the text over the background.
  2774 +
  2775 + define One
  2776 + draw_button_text
  2777 + (
  2778 + RGBAImage image,
  2779 + String text,
  2780 + Int text_index,
  2781 + Int pixel_x,
  2782 + Int y,
  2783 + Rectangle clip,
  2784 + RGBA color,
  2785 + SystemFont font,
  2786 + ) =
  2787 + if nth(text_index,text) is
  2788 + {
  2789 + failure then unique,
  2790 + success(c) then
  2791 + with cw = draw_system_character(image,clip,pixel_x,y,font,word8_to_int32(c),color),
  2792 + draw_button_text(image,text,text_index+1,pixel_x+cw+1,y,clip,color,font)
  2793 + }.
  2794 +
  2795 + define One
  2796 + draw_button_text
  2797 + (
  2798 + RGBAImage image,
  2799 + String text,
  2800 + Int text_width,
  2801 + RGBA light_color,
  2802 + RGBA dark_color,
  2803 + SystemFont font
  2804 + ) =
  2805 + with image_width = width(image),
  2806 + image_height = height(image),
  2807 + x_pos = (image_width-text_width)>>1,
  2808 + clip = rect(0,0,image_width,image_height),
  2809 + new_light_color = lighten(light_color,150),
  2810 + new_dark_color = darken(dark_color,40),
  2811 + draw_button_text(image, text, 0, x_pos+2, 16, clip, new_dark_color, font);
  2812 + draw_button_text(image, text, 0, x_pos, 14, clip, new_light_color, font).
  2813 +
  2814 +
  2815 + The next function creates the two images for a button. The information given is the
  2816 + main color of the button, the text of the button and the minimal width (in pixels) of
  2817 + the button. The function does not create the button if the images already exist. The
  2818 + two images are stored in the directory 'site_directory/buttons'. The names of the files
  2819 + are of the form:
  2820 +
  2821 + bxxxx_off.jpg
  2822 + bxxxx_on.jpg
  2823 +
  2824 + where the prefix 'b' is to avoid leading '-' which may perturb UNIX commands (like
  2825 + 'rm'), and where 'xxxx' is created from the given informations by the formula:
  2826 +
  2827 + xxxx = web_arg_encode(sha1((color,text,width)))
  2828 +
  2829 + Hence, distinct informations give distinct file names.
  2830 +
  2831 +
  2832 + define String // returns xxxx
  2833 + create_button_images
  2834 + (
  2835 + String site_directory,
  2836 + RGBA color,
  2837 + String text,
  2838 + Int width,
  2839 + SystemFont font
  2840 + ) =
  2841 + with xxxx = web_arg_encode(sha1((color,text,width))),
  2842 + buttons_dir = site_directory+"/public/buttons",
  2843 + off_filepath = buttons_dir+"/b"+xxxx+"_off.jpg",
  2844 + on_filepath = buttons_dir+"/b"+xxxx+"_on.jpg",
  2845 + if file_exists(on_filepath)
  2846 + then xxxx
  2847 + else with
  2848 + text_width = printed_text_width(font,text),
  2849 + button_width = max(width,text_width+12),
  2850 + button_height = (Int)20,
  2851 + light_color = lighten(color,60),
  2852 + very_light_color = lighten(light_color,30),
  2853 + dark_color = darken(color,40),
  2854 + background_off =
  2855 + create_button_background(color,button_width,button_height),
  2856 + background_on =
  2857 + create_button_background(light_color,button_width,button_height),
  2858 +
  2859 + draw_button_text(background_off,text,text_width,very_light_color,dark_color,font);
  2860 + draw_button_text(background_on, text,text_width,very_light_color,dark_color,font);
  2861 + forget(write_image_to_JPEG_file(to_JPEG(background_off),
  2862 + off_filepath,
  2863 + 100));
  2864 + forget(write_image_to_JPEG_file(to_JPEG(background_on),
  2865 + on_filepath,
  2866 + 100));
  2867 + xxxx.
  2868 +
  2869 +
  2870 +
  2871 +
  2872 +
  2873 + *** [5.4] Formating an actioner.
  2874 +
  2875 + An actioner works as follows. Assume first that it refers to a form. When it is clicked
  2876 + upon, the actioner puts (via 'onMouseDown') the URL into the 'action' attribute of the
  2877 + form, and submits the form, using the JavaScript command 'form_name.submit()'. If the
  2878 + actioner does not refer to a form, it fires the URL directly via 'href', because in
  2879 + that case, the actioner is always an <a> tag.
  2880 +
  2881 + The URL itself is composed using the connection sort (same, http or https), the common
  2882 + name and port number (if needed), the state name, the action name, and the extra
  2883 + operands, which are put into a query string. It may look like this:
  2884 +
  2885 + http://common_name:port/?s=state_name&a=action_name&oname=value...
  2886 +
  2887 + Each extra operand is a pair of strings: (name,value). It is formated as:
  2888 +
  2889 + &oname=value
  2890 +
  2891 +
  2892 +define String
  2893 + format_extra_operands
  2894 + (
  2895 + List((String,String)) l
  2896 + ) =
  2897 + if l is
  2898 + {
  2899 + [ ] then "",
  2900 + [h . t] then if h is (n,v) then
  2901 + "&amp;"+n+"="+v+format_extra_operands(t)
  2902 + }.
  2903 +
  2904 +
  2905 + It seams that the standard requires "&amp;" instead of "&" !
  2906 +
  2907 + In case the target is another window, we need to format the options for this window.
  2908 +
  2909 +define String
  2910 + format
  2911 + (
  2912 + List(Other_Window_Option) l
  2913 + ) =
  2914 + if l is
  2915 + {
  2916 + [ ] then "",
  2917 + [h . t] then if h is
  2918 + {
  2919 + resizable then "resizable",
  2920 + scrollbars then "scrollbars",
  2921 + width(w) then "width="+w,
  2922 + height(h2) then "height="+h2
  2923 + } + if t is [ ] then "" else (","+format(t))
  2924 + }.
  2925 +
  2926 +
  2927 +
  2928 + Formating choices for a <select> tag.
  2929 +
  2930 +public define Printable_tree
  2931 + format_choices
  2932 + (
  2933 + List(String) l
  2934 + ) =
  2935 + if l is
  2936 + {
  2937 + [ ] then [ ],
  2938 + [h . t] then ["<option>", h, "</option>\n" . format_choices(t)]
  2939 + }.
  2940 +
  2941 +
  2942 +public define Printable_tree
  2943 + format_choices
  2944 + (
  2945 + List(String) l,
  2946 + InitialValue selected
  2947 + ) =
  2948 + if l is
  2949 + {
  2950 + [ ] then [ ],
  2951 + [h . t] then if h = selected.value
  2952 + then ["<option selected=\"selected\">", h, "</option>\n" . format_choices(t)]
  2953 + else ["<option>", h, "</option>\n" . format_choices(t,selected)]
  2954 + }.
  2955 +
  2956 +
  2957 +public define Printable_tree
  2958 + format_choices
  2959 + (
  2960 + List((WebArgValue,String)) l
  2961 + ) =
  2962 + if l is
  2963 + {
  2964 + [ ] then [ ],
  2965 + [h . t] then
  2966 + if h is (val,item)
  2967 + then ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t)]
  2968 + }.
  2969 +
  2970 +public define Printable_tree
  2971 + format_choices
  2972 + (
  2973 + List((WebArgValue,String)) l,
  2974 + InitialValue selected
  2975 + ) =
  2976 + if l is
  2977 + {
  2978 + [ ] then [ ],
  2979 + [h . t] then
  2980 + if h is (val,item) then
  2981 + if val.value = selected.value
  2982 + then ["<option value=\""+val.value+"\" selected=\"selected\">", item, "</option>\n" . format_choices(t)]
  2983 + else ["<option value=\""+val.value+"\">", item, "</option>\n" . format_choices(t,selected)]
  2984 + }.
  2985 +
  2986 +
  2987 +
  2988 +variable Int count = 0.
  2989 +
  2990 + Note: this counter is private to the virtual machine, hence there is one counter by
  2991 + client and by page : it seems that a new VM (simply a delegate) is started for each request.
  2992 +
  2993 +define Int
  2994 + new_count
  2995 + =
  2996 + count <- *count+1;
  2997 + *count.
  2998 +
  2999 +
  3000 + The next function composes the URL. It is a JavaScript URL when the target is another
  3001 + window.
  3002 +
  3003 +define String
  3004 + make_actioner_url
  3005 + (
  3006 + CommonInfo cinfo,
  3007 + Actioner_Connection connection,
  3008 + Actioner_Target target,
  3009 + String state_name,
  3010 + String action_name,
  3011 + List((String,String)) extra_ops,
  3012 + Bool is_https
  3013 + ) =
  3014 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  3015 + with strict_url =
  3016 + if connection is
  3017 + {
  3018 + same then "/",
  3019 + http then "http://"+common_name+":"+http_port+"/",
  3020 + https then "https://"+common_name+":"+https_port+"/",
  3021 + } +
  3022 + "?a=" + action_name +
  3023 + format_extra_operands(extra_ops),
  3024 + if target is
  3025 + {
  3026 + same then strict_url,
  3027 + same(label) then strict_url+"#"+label,
  3028 + other(wn,ops) then
  3029 +
  3030 + "javascript:void window.open('"+strict_url+"&amp;t="+wn+"','"+
  3031 + "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"
  3032 + }.
  3033 +
  3034 +define String
  3035 + make_foreign_link_url
  3036 + (
  3037 + Actioner_Target target,
  3038 + String url
  3039 + ) =
  3040 + if target is
  3041 + {
  3042 + same then "/",
  3043 + same(label) then "/#"+label,
  3044 + other(wn,ops) then
  3045 +
  3046 + "javascript:void window.open('"+url+"','"+
  3047 + "w"+to_ascii(sha1(wn))+"','"+format(ops)+"')"
  3048 + }.
  3049 +
  3050 +
  3051 + Depending on the fact that the actioner refers to a form or not, the URL is used in two
  3052 + different ways. If the actioner does not refer to a form, it is realized by a '<a>'
  3053 + tag, with a 'href' attribute. If it refers to a form, it is still realized by a '<a>'
  3054 + tag, but with no href attribute. In this case, we use the 'onMouseDown' or 'onChange'
  3055 + event handler. The handler calls a JavaScript function which puts the URL as the value
  3056 + of the 'action' attribute of the form, and submits the form.
  3057 +
  3058 +type URL_or_JavaScript:
  3059 + url (String),
  3060 + javascript (Printable_tree script, Printable_tree handler).
  3061 +
  3062 +
  3063 + It was as shown below, in order to allow submission of a form from outside the form,
  3064 + but this makes problems:
  3065 +
  3066 +define URL_or_JavaScript
  3067 + format_action
  3068 + (
  3069 + String the_url,
  3070 + Actioner_Aspect aspect,
  3071 + Maybe(String) mb_id,
  3072 + Maybe(String) mb_form_name
  3073 + ) =
  3074 + if mb_form_name is
  3075 + {
  3076 + failure then
  3077 + url(the_url),
  3078 + success(form_name) then
  3079 + with n = new_count,
  3080 + fn_name = "pfu_" + if mb_id is
  3081 + {
  3082 + failure then form_name + "_" + n,
  3083 + success(id) then id,
  3084 + },
  3085 + javascript(
  3086 + [
  3087 + "<script type=\"text/javascript\" language =\"JavaScript\">\n",
  3088 + "function ", fn_name, "() {\n",
  3089 + " var fa = document.forms.",form_name,";\n",
  3090 + " var u = \"",the_url,"\";\n",
  3091 + " fa.action = u;",
  3092 + if aspect is submit(_, _) then " }\n"
  3093 + else "\n fa.submit(); }\n",
  3094 + "</script>\n"
  3095 + ],
  3096 + [fn_name,"();"]
  3097 + )
  3098 + }.
  3099 +
  3100 +
  3101 +
  3102 + Now, we format the actioner according to its aspect.
  3103 +
  3104 +define List(Text_Option)
  3105 + get_text_options
  3106 + (
  3107 + List(Text_Option) l
  3108 + )
  3109 + =
  3110 + if l is
  3111 + {
  3112 + [] then [],
  3113 + [h . t ] then
  3114 + if h is class(_) then
  3115 + get_text_options(t)
  3116 + else if h is id(_) then
  3117 + get_text_options(t)
  3118 + else if h is style(_) then
  3119 + get_text_options(t)
  3120 + else if h is title(_) then
  3121 + get_text_options(t)
  3122 + else
  3123 + [ h . get_text_options(t) ]
  3124 +
  3125 + }.
  3126 +
  3127 + /**
  3128 + * Extract the CSS class list from the list of Text_Option
  3129 + */
  3130 +define List(CoreAttrs)
  3131 + get_css_class
  3132 + (
  3133 + List(Text_Option) l
  3134 + )
  3135 + =
  3136 + if l is
  3137 + {
  3138 + [] then [],
  3139 + [h . t ] then
  3140 +
  3141 +
  3142 + if h is class(name) then
  3143 + [ class(name) . get_css_class(t) ]
  3144 + else if h is id(name) then
  3145 + [ id(name) . get_css_class(t) ]
  3146 + else if h is style(the_style) then
  3147 + [ style(the_style) . get_css_class(t) ]
  3148 + else if h is title(name) then
  3149 + [ tooltip(name) . get_css_class(t) ]
  3150 + else if h is attr(name, value) then
  3151 + [ attr(name, value) . get_css_class(t) ]
  3152 + else
  3153 + get_css_class(t)
  3154 + }
  3155 + .
  3156 +
  3157 +define Printable_tree
  3158 + format
  3159 + (
  3160 + List(Actioner_Local_Action) l
  3161 + ) =
  3162 + if l is
  3163 + {
  3164 + [ ] then [ ],
  3165 + [h . t] then [if h is
  3166 + {
  3167 + close_window then [" window.close(); "]
  3168 + }
  3169 + . format(t)]
  3170 + }.
  3171 +
  3172 +public define String
  3173 + format_attrs
  3174 + (
  3175 + List(CoreAttrs) attributs
  3176 + )=
  3177 + if attributs is
  3178 + {
  3179 + [] then "",
  3180 + [h . t] then
  3181 + with current = if h is
  3182 + {
  3183 + id(id_name) then
  3184 + " id=\"" + id_name + "\"",
  3185 + class(class_name) then
  3186 + " class=\"" + class_name + "\"",
  3187 + style(style_string) then
  3188 + " style=\"" + style_string + "\"",
  3189 +
  3190 + title(title_string) then
  3191 + " title=\"" + title_string + "\"",
  3192 +
  3193 + lang(lang) then
  3194 + " xml:lang=" + lang,
  3195 + dir(reading_Way) then
  3196 + if reading_Way is
  3197 + {
  3198 + ltr then " dir=ltr",
  3199 + rtl then " dir=rtl"
  3200 + },
  3201 +
  3202 + accesskey(key) then
  3203 + " accesskey=\"" + key + "\"",
  3204 + tabindex(index) then
  3205 + " tabindex=\"" + index + "\"",
  3206 +
  3207 + attr(name, value) then
  3208 + " " + name + "=\"" + value + "\"",
  3209 +
  3210 + event(e, value) then
  3211 + " " + event_name(e) + "=\"" + value + "\"",
  3212 + },
  3213 + current + format_attrs(t)
  3214 + }.
  3215 +
  3216 +define String
  3217 + format_attrs
  3218 + (
  3219 + List(InputAttrs) attributs
  3220 + )=
  3221 + if attributs is
  3222 + {
  3223 + [] then "",
  3224 + [h . t] then
  3225 + with current = if h is
  3226 + {
  3227 + class(class_name) then
  3228 + " class=\"" + class_name + "\"",
  3229 + style(style_string) then
  3230 + " style=\"" + style_string + "\"",
  3231 +
  3232 + title(title_string) then
  3233 + " title=\"" + title_string + "\"",
  3234 +
  3235 + lang(lang) then
  3236 + " xml:lang=" + lang,
  3237 + dir(reading_Way) then
  3238 + if reading_Way is
  3239 + {
  3240 + ltr then " dir=ltr",
  3241 + rtl then " dir=rtl"
  3242 + },
  3243 +
  3244 + accesskey(key) then
  3245 + " accesskey=\"" + key + "\"",
  3246 + tabindex(index) then
  3247 + " tabindex=\"" + index + "\"",
  3248 +
  3249 + attr(name, value) then
  3250 + " " + name + "=\"" + value + "\"",
  3251 +
  3252 + event(e, value) then
  3253 + " " + event_name(e) + "=\"" + value + "\"",
  3254 + },
  3255 + current + format_attrs(t)
  3256 + }.
  3257 +
  3258 +define String
  3259 + format_text_options
  3260 + (
  3261 + List(Text_Option) l
  3262 + )
  3263 + =
  3264 + with text_options = get_text_options(l),
  3265 + css_classes = get_css_class(l),
  3266 + if text_options is
  3267 + {
  3268 + [] then "",
  3269 + [_ . _] then " style=\"" + format(text_options) + "\" "
  3270 + }
  3271 + +
  3272 + if css_classes is
  3273 + {
  3274 + [] then "",
  3275 + [_ . _] then format_attrs(css_classes)
  3276 + }.
  3277 +
  3278 +//define String
  3279 +// _format
  3280 +// (
  3281 +// List(CoreAttrs) opt
  3282 +// )=
  3283 +// if opt is
  3284 +// {
  3285 +// [] then "",
  3286 +// [h .t] then
  3287 +// with current = if h is
  3288 +// {
  3289 +// id(id_name) then
  3290 +// " id=\"" + id_name + "\"",
  3291 +// class(class_name) then
  3292 +// " class=\"" + class_name + "\"",
  3293 +// style(style_string) then
  3294 +// " style=\"" + style_string + "\"",
  3295 +//
  3296 +// title(title_string) then
  3297 +// " title=\"" + title_string + "\"",
  3298 +// lang(lang) then
  3299 +// " xml:lang=" + lang,
  3300 +// dir(reading_Way) then
  3301 +// if reading_Way is
  3302 +// {
  3303 +// ltr then " dir=ltr",
  3304 +// rtl then " dir=rtl"
  3305 +// },
  3306 +// attr(name, value) then
  3307 +// " " + name + "=\"" + value + "\"",
  3308 +// event(e, value) then
  3309 +// " " + event_name(e) + "=\"" + value + "\""
  3310 +// },
  3311 +// current + _format(t)
  3312 +// }
  3313 +// .
  3314 +
  3315 +define Printable_tree
  3316 + format_div_option
  3317 + (
  3318 + List(CoreAttrs) options
  3319 + )=
  3320 + ["<div" + format_attrs(options) + ">"] .
  3321 +
  3322 +
  3323 +define Maybe(String)
  3324 + extract_id
  3325 + (
  3326 + List(CoreAttrs) attrbs
  3327 + ) =
  3328 + if attrbs is
  3329 + {
  3330 + [] then failure,
  3331 + [h . t] then
  3332 + if h is id(value) then success(value)
  3333 + else extract_id(t)
  3334 + }.
  3335 +
  3336 +define Maybe(String)
  3337 + extract_id
  3338 + (
  3339 + Actioner_Aspect aspect
  3340 + ) =
  3341 + if aspect is
  3342 + {
  3343 + link(_,_,_) then failure,
  3344 + img_link(_,_) then failure,
  3345 + push_button(opts,_) then extract_id(opts),
  3346 + button(_,_) then failure,
  3347 + button(_,_,_,_) then failure,
  3348 + submit(opts,_) then extract_id(opts),
  3349 + immediate_selector(_,_,_,_) then failure,
  3350 + immediate_selector(_,_,_,_,_) then failure,
  3351 + }.
  3352 +
  3353 +to do Complete format_foreign_link
  3354 +//TODO Complete format_foreign_link
  3355 +define Printable_tree
  3356 + format_foreign_link
  3357 + (
  3358 +// CommonInfo cinfo,
  3359 + Actioner_Target target,
  3360 + Actioner_Aspect aspect,
  3361 + String url,
  3362 + Bool is_https,
  3363 + ) =
  3364 + //if cinfo is info(common_name,http_port,https_port,site_dir,secret) then
  3365 + with full_url = make_foreign_link_url(target,url),
  3366 +// with action = format_action(full_url, aspect, extract_id(aspect), mb_form_name),
  3367 + if aspect is
  3368 + {
  3369 +
  3370 + link(opt, text, mb_name) then
  3371 + with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",
  3372 + [
  3373 + "<a href=\"", full_url, "\"", format_text_options(opt), name_tag, ">",
  3374 + text,
  3375 + "</a>"
  3376 + ],
  3377 + img_link(img,alt_text) then
  3378 + [
  3379 + "<a href=\"", full_url ,"\"><img src=\"", img,
  3380 + "\" alt=\"" + alt_text + "\" border=\"0\"></a>"
  3381 + ],
  3382 + push_button(options, text) then
  3383 + ["<a href=\"",full_url,"\"", format_attrs(options), ">",
  3384 + text, "</a>"
  3385 + ],
  3386 + button(url_off,url_on) then
  3387 + [ ],
  3388 +
  3389 + button(url_off,url_on,w,h) then
  3390 + [ ],
  3391 +
  3392 + submit(options, text) then
  3393 + [ ],
  3394 +
  3395 + immediate_selector(opt,name,size,choices) then
  3396 + [ ],
  3397 + immediate_selector(opt,name,size,choices,selected) then
  3398 + [ ],
  3399 + }.
  3400 +
  3401 +define Printable_tree
  3402 + format_actioner
  3403 + (
  3404 + CommonInfo cinfo,
  3405 + String state_name,
  3406 + Actioner_Connection connection,
  3407 + Actioner_Target target,
  3408 + Actioner_Aspect aspect,
  3409 + String action_name,
  3410 + List((String,String)) extra_ops,
  3411 + List(Actioner_Local_Action) local_actions,
  3412 + Maybe(String) mb_form_name,
  3413 + Bool is_https,
  3414 + ) =
  3415 + if cinfo is info(common_name,http_port,https_port,site_dir,secret) then
  3416 + with url = make_actioner_url(cinfo,connection,target,
  3417 + state_name,action_name,extra_ops,is_https),
  3418 + with action = format_action(url, aspect, extract_id(aspect), mb_form_name),
  3419 + if aspect is
  3420 + {
  3421 +
  3422 + link(opt, text, mb_name) then
  3423 + with name_tag = if mb_name is success(n) then " name=\"" + n + "\"" else "",
  3424 + [
  3425 + "<a href=\"", url, "\"", format_text_options(opt), name_tag, ">",
  3426 + text,
  3427 + "</a>"
  3428 + ],
  3429 + img_link(img, alt_text) then
  3430 + [
  3431 + "<a href=\"", url ,"\"><img src=\"", img,
  3432 + "\" alt=\"" + alt_text + "\" border=\"0\"></a>"
  3433 + ],
  3434 + push_button(options, text) then
  3435 + [
  3436 + if action is
  3437 + {
  3438 + url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",
  3439 + text, "</a>"
  3440 + ],
  3441 + javascript(s,h) then
  3442 + if action_name = "" then
  3443 + ["<input type=\"button\" value=\"",text,"\"", format_attrs(options), " />"]
  3444 + else
  3445 + [s,"<input type=\"button\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]
  3446 + }
  3447 + ],
  3448 + button(url_off,url_on) then
  3449 + [ if action is
  3450 + {
  3451 + url(u) then ["<a href=\"",u],
  3452 + javascript(s,h) then [s,"<a onMouseDown=\"",h]
  3453 + },
  3454 + "\" style=\"text-decoration:none\">",
  3455 + "<img alt=\"",url_off,"\" src=\"",url_off,"\" border=0",
  3456 + " onMouseOver=\"this.src='",url_on,"'\" ",
  3457 + " onMouseOut=\"this.src='",url_off,"'\">",
  3458 + "</a>"
  3459 + ],
  3460 +
  3461 + button(url_off,url_on,w,h) then
  3462 + [ if action is
  3463 + {
  3464 + url(u) then ["<a href=\"",u],
  3465 + javascript(s,h2) then [s,"<a onMouseDown=\"",h2]
  3466 + },
  3467 + "\" style=\"text-decoration:none\">",
  3468 + "<img width=",w," height=",h," alt=\"",url_off,"\" src=\"",url_off,"\" border=0",
  3469 + " onMouseOver=\"this.src='",url_on,"'\" ",
  3470 + " onMouseOut=\"this.src='",url_off,"'\">",
  3471 + "</a>"
  3472 + ],
  3473 +
  3474 + submit(options, text) then
  3475 + [
  3476 + if action is
  3477 + {
  3478 + url(u) then ["<a href=\"",u,"\"", format_attrs(options), ">",
  3479 + text, "</a>"
  3480 + ],
  3481 + javascript(s,h) then
  3482 + if action_name = "" then // special case where URL (so the action_name) is provided by the form itself
  3483 + // so javascript isn't needed. This is the standard HMTL way.
  3484 + ["<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " />"]
  3485 + else
  3486 + [s,"<input type=\"submit\" value=\"",text,"\"", format_attrs(options), " onclick=\"",h,"\" />"]
  3487 + }
  3488 + ],
  3489 +
  3490 + immediate_selector(options,name,size,choices) then
  3491 + [ if action is
  3492 + {
  3493 + url(u) then ["<select href=\"",u]
  3494 + javascript(s,h) then [s,"<select onchange=\"",h]
  3495 + },
  3496 + "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",
  3497 + format_choices(choices),"</select>"
  3498 + ],
  3499 + immediate_selector(options,name,size,choices,selected) then
  3500 + [ if action is
  3501 + {
  3502 + url(u) then ["<select href=\"",u]
  3503 + javascript(s,h) then [s,"<select onchange=\"",h]
  3504 + },
  3505 + "\" name=\"",name,"\" size=\"",size,"\"", format_attrs(options), ">",
  3506 + format_choices(choices, selected),"</select>"
  3507 + ],
  3508 + }.
  3509 +
  3510 +
  3511 +
  3512 +
  3513 +
  3514 +
  3515 + *** [5.5] Formating a private download link.
  3516 +
  3517 + We get the absolute path of the file to be downloaded, and the name under which it
  3518 + should appear to the client. The function 'format_private_download' creates an
  3519 + hypertext link for downloading the file. The secured mecanism of private download is
  3520 + used. This function is called by the function which formats HTML_Any($T) elements.
  3521 +
  3522 +
  3523 +define Printable_tree
  3524 + format_private_download
  3525 + (
  3526 + CommonInfo cinfo,
  3527 + String sn, // state name
  3528 + String abs_path, // absolute file path on server
  3529 + String name, // name of file as it appears in the browser
  3530 + String extra, // extra extension
  3531 + Maybe((String,List((String,String)))) action
  3532 +
  3533 + ) =
  3534 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  3535 + with private_download_directory = site_directory+"/private_download",
  3536 + with auth = make_authorization(site_directory,secret,abs_path),
  3537 + [
  3538 + "<a href=\"",name,extra,"?zauth=",auth,
  3539 + if action is
  3540 + {
  3541 + failure then [ ]
  3542 + success(a) then if a is (an,args) then
  3543 + ["&amp;a=",an,format_extra_operands(args)]
  3544 + },
  3545 + "\">",
  3546 + name,
  3547 + "</a>"
  3548 + ].
  3549 +
  3550 +
  3551 +
  3552 +
  3553 + *** [5.6] Formating rows and cells in a table.
  3554 +
  3555 +define Int
  3556 + percent
  3557 + (
  3558 + Int p
  3559 + ) =
  3560 + if p < 0 then 0 else if p > 100 then 100 else p.
  3561 +
  3562 +
  3563 +
  3564 +
  3565 + Formating cell options.
  3566 +
  3567 +
  3568 +
  3569 +define String
  3570 + format
  3571 + (
  3572 + BackgroundOption o
  3573 + ) =
  3574 + if o is
  3575 + {
  3576 + repeat then "",
  3577 + repeat_horizontal then "; background-repeat: repeat-x",
  3578 + repeat_vertical then "; background-repeat: repeat-y",
  3579 + no_repeat then "; background-repeat: no-repeat",
  3580 + center then "; background-position: center top"
  3581 + }.
  3582 +
  3583 +define String
  3584 + format
  3585 + (
  3586 + List(BackgroundOption) l
  3587 + ) =
  3588 + if l is
  3589 + {
  3590 + [ ] then "",
  3591 + [h . t] then format(h)+format(t)
  3592 + }.
  3593 +
  3594 +
  3595 +define String
  3596 + format
  3597 + (
  3598 + List(Cell_Option) options
  3599 + ) =
  3600 + if options is
  3601 + {
  3602 + [ ] then "",
  3603 + [h . t] then
  3604 + if h is
  3605 + {
  3606 + core_attrs(core_attr_list) then format_attrs(core_attr_list),
  3607 + left then " align=\"left\"",
  3608 + h_center then " align=\"center\"",
  3609 + right then " align=\"right\"",
  3610 + top then " valign=\"top\"",
  3611 + v_center then " valign=\"middle\"",
  3612 + bottom then " valign=\"bottom\"",
  3613 + base_line then " valign=\"baseline\"",
  3614 + background_color(c) then " bgcolor=\""+html_format(c)+"\"",
  3615 + background_image(n,o) then " style=\"background: url("+n+")"+format(o)+"\"",
  3616 + width(w) then " width=\""+w+"\"",
  3617 + percentage_width(n) then " width=\""+percent(n)+"%\"",
  3618 + height(h2) then " height=\""+h2+"\"",
  3619 + columns(n) then " colspan=\""+n+"\"",
  3620 + rows(n) then " rowspan=\""+n+"\"",
  3621 + nowrap then " nowrap",
  3622 + class(class_name) then " class=\""+class_name+"\""
  3623 + }
  3624 + + format(t)
  3625 + }.
  3626 +
  3627 +
  3628 + Normalizing a list of cell options (horizontal position must be specified; the default
  3629 + is 'left').
  3630 +
  3631 + Formating cells in a row.
  3632 +
  3633 +define Printable_tree
  3634 + format
  3635 + (
  3636 + List(HTML_Cell($T)) cells,
  3637 + $T -> Printable_tree format_element
  3638 + ) =
  3639 + if cells is
  3640 + {
  3641 + [ ] then [ ],
  3642 + [h . t] then if h is cell(options,element) then
  3643 + ["<td",format(reverse(options)),">",
  3644 + format_element(element),
  3645 + "</td>"
  3646 + . format(t,format_element)]
  3647 + }.
  3648 +
  3649 +define Printable_tree
  3650 + format
  3651 + (
  3652 + List(HTML_Header_Cell($T)) cells,
  3653 + $T -> Printable_tree format_element
  3654 + ) =
  3655 + if cells is
  3656 + {
  3657 + [ ] then [ ],
  3658 + [h . t] then if h is header_cell(options,element) then
  3659 + ["<th ",format(reverse(options)),">",
  3660 + format_element(element),
  3661 + "</th>"
  3662 + . format(t,format_element)]
  3663 + }.
  3664 +
  3665 + Formating the rows in a table.
  3666 +
  3667 +define Printable_tree
  3668 + format
  3669 + (
  3670 + List(HTML_Row($T)) rows,
  3671 + $T -> Printable_tree format_element,
  3672 + ) =
  3673 + if rows is
  3674 + {
  3675 + [ ] then [ ],
  3676 + [h . t] then if h is row(options,cells) then
  3677 + ["<tr",format(reverse(options)),">",
  3678 + format(cells,format_element),
  3679 + "</tr>\n"
  3680 + . format(t,format_element)]
  3681 + }.
  3682 +
  3683 +define Printable_tree
  3684 + format
  3685 + (
  3686 + HTML_Header_Row($T) row,
  3687 + $T -> Printable_tree format_element
  3688 + ) =
  3689 + if row is
  3690 + {
  3691 + empty then [ ],
  3692 + header_row(options,cells) then
  3693 + ["<thead> <tr",format(reverse(options)),">",
  3694 + format(cells,format_element),
  3695 + "</tr> </thead>\n"
  3696 + ]
  3697 + }.
  3698 +
  3699 +define Printable_tree
  3700 + format
  3701 + (
  3702 + HTML_Footer_Row($T) row,
  3703 + $T -> Printable_tree format_element
  3704 + ) =
  3705 + if row is
  3706 + {
  3707 + empty then [ ],
  3708 + footer_row(options,cells) then
  3709 + ["<tfoot> <tr",format(reverse(options)),">",
  3710 + format(cells,format_element),
  3711 + "</tr> </tfoot>\n"
  3712 + ]
  3713 + }.
  3714 +
  3715 +define Printable_tree
  3716 + format1
  3717 + (
  3718 + List(TextAreaOption) l
  3719 + ) =
  3720 + if l is
  3721 + {
  3722 + [] then [],
  3723 + [h . t] then if h is
  3724 + {
  3725 + input_attrs(input_attr_list) then [format_attrs(input_attr_list) . format1(t)],
  3726 + disabled then [" disabled=\"disabled\" " . format1(t)]
  3727 + read_only then [" readonly=\"readonly\" " . format1(t)]
  3728 + wrap_lines then [" wrap=\"wrap\" " . format1(t)]
  3729 + }
  3730 + }.
  3731 +
  3732 +define Printable_tree
  3733 + format
  3734 + (
  3735 + List(TextAreaOption) l
  3736 + ) =
  3737 + if member(l,wrap_lines)
  3738 + then format1(l)
  3739 + else [" wrap=\"off\" " . format1(l)].
  3740 +
  3741 +
  3742 + *** [5.7] Formating elements which may be put anywhere.
  3743 +
  3744 + The function below involves the parameter $T which is later instantiated as
  3745 + 'HTML_In_Form' or as 'HTML_Off_Form'. Now, since there are dictinct 'format' functions
  3746 + for these two types, and because formating of tables requires recursive calls of such
  3747 + functions, it is necessary to provide the 'format' function to be called recursively as
  3748 + an argument. Putting naively a call to 'format' will not work, because the compiler
  3749 + will look for a function able to format data of type $T (which is at that time distinct
  3750 + from any other type, including our two types). Such a function does not exist. Hence
  3751 + the function to be called for formating elements must be passed as a functional
  3752 + argument (called 'format_element' below). Actually, what we pass is a function taking
  3753 + a unique argument of type $T. Other informations (like the name of the state) are
  3754 + already in the function by way of full functionality.
  3755 +
  3756 +
  3757 + Formating text options. They are formated in CSS syntax, to be used within a
  3758 + 'style=...'.
  3759 +
  3760 +define String
  3761 + format
  3762 + (
  3763 + List(Text_Option) l
  3764 + ) =
  3765 + if l is
  3766 + {
  3767 + [ ] then "",
  3768 + [h . t] then if h is
  3769 + {
  3770 + size(n) then "font-size:"+n+"pt",
  3771 + font(fn) then "font-family:"+fn,
  3772 + color(c) then if c is rgb(r,g,b) then
  3773 + "color:rgb("+to_decimal(r)+","+to_decimal(g)+","+to_decimal(b)+")",
  3774 + italic then "font-style:italic",
  3775 + oblique then "font-style:oblique",
  3776 + small_capitals then "font-variant:small-caps",
  3777 + bold then "font-weight:bold",
  3778 + underlined then "text-decoration:underline",
  3779 + left_justified then "text-align:left",
  3780 + right_justified then "text-align:right",
  3781 + justified then "text-align:justify",
  3782 + line_through then "text-decoration:line-through",
  3783 + nowrap then "white-space:nowrap",
  3784 + class(class_name)then " class=\"" + class_name +"\"",
  3785 + id(id_name) then " id=\"" + id_name +"\"",
  3786 + style(style_string) then " style=\"" + style_string + "\"",
  3787 + title(s) then " title=\"" + s +"\""
  3788 + attr(n,v) then " " + n + "=\"" + v +"\""
  3789 + } + if t is [ ] then "" else ("; "+format(t))
  3790 + }.
  3791 +
  3792 +
  3793 +
  3794 + Formating table options.
  3795 +
  3796 +define String
  3797 + format
  3798 + (
  3799 + List(Table_Option) l,
  3800 + Bool border_seen
  3801 + ) =
  3802 + if l is
  3803 + {
  3804 + [ ] then if border_seen then "" else " border=\"0\" cellspacing=\"0\" cellpadding=\"0\"",
  3805 + [h . t] then if h is
  3806 + {
  3807 + background_color(c) then " bgcolor=\""+html_format(c)+"\""+format(t,border_seen),
  3808 + background_image(url) then " background="+url+format(t,border_seen),
  3809 + border(o,top,i,c) then " border=\""+o+"\" cellspacing=\""+top+"\" cellpadding=\""+i+"\""+
  3810 + //" bordercolor="+format(c)+
  3811 + format(t,true),
  3812 + width(w) then " width=\""+w+"\""+format(t,border_seen),
  3813 + percentage_width(p) then " width=\""+percent(p)+"%\""+format(t,border_seen),
  3814 + attr(name, value) then " " + name + "=\"" + value + "\"" +format(t,border_seen),
  3815 + class(name) then " class=\""+name+"\""
  3816 + }
  3817 + }.
  3818 +
  3819 +
  3820 +
  3821 +
  3822 +
  3823 +define Printable_tree
  3824 + format_scroller
  3825 + (
  3826 + String sn,
  3827 + Int width,
  3828 + Int height,
  3829 + Int content_width,
  3830 + Int content_height,
  3831 + Int idnum, // identifying the scroller
  3832 + $T content,
  3833 + $T -> Printable_tree format_element
  3834 + ) =
  3835 + [
  3836 + "<script type = \"text/javascript\" language=\"JavaScript\">",
  3837 + "function doscroll_",idnum,"(dx,dy) {\n",
  3838 + " if (document.layers) { var c_",idnum," = eval(document.cs_",idnum,"); } else\n",
  3839 + " if (document.getElementById) {var c_",idnum," = eval(\"document.getElementById('cs_",
  3840 + idnum,"').style\"); } else\n",
  3841 + " if (document.all) { var c_",idnum," = eval(document.all.cs_",idnum,".style); };\n",
  3842 + " var x_",idnum," = parseInt(c_",idnum,".left);\n",
  3843 + " var y_",idnum," = parseInt(c_",idnum,".top);\n",
  3844 + " if ((x_",idnum,"+dx <= 0) && (x_",idnum,"+dx > ",width-content_width,"))\n",
  3845 + " { x_",idnum," += dx; }\n",
  3846 + " if ((y_",idnum,"+dy <= 0) && (y_",idnum,"+dy > ",height-content_height,"))\n",
  3847 + " { y_",idnum," += dy; }\n",
  3848 + " c_",idnum,".left = x_",idnum,";\n",
  3849 + " c_",idnum,".top = y_",idnum,";\n",
  3850 + " }\n",
  3851 + "</script>\n",
  3852 + "<table>",
  3853 + "<tbody>",
  3854 + "<tr>",
  3855 + "<td align=left valign=top",
  3856 + " width=",width,
  3857 + " height=",height,
  3858 + ">",
  3859 + "<div id=\"ws_",idnum,"\" style=\"position:absolute; width:",width,"px; height:",height,"px;",
  3860 + " clip:rect(0px ",width,"px ",height,"px 0px)\">",
  3861 + "<div id=\"cs_",idnum,"\" style=\"position:absolute; left:0px; top:0px\">",
  3862 + format_element(content),
  3863 + "</div>",
  3864 + "</div>",
  3865 + "</td>",
  3866 + "<td valign=bottom>",
  3867 + "<table>",
  3868 + "<tbody>",
  3869 + "<tr><td><img alt=\"sroll up\" src=\"scrollup.gif\" onmousedown=\"doscroll_", idnum,"(0,20);\"></td></tr>",
  3870 + "<tr><td><img alt=\"scroll down\" src=\"scrolldown.gif\" onmousedown=\"doscroll_", idnum,"(0,-20);\"></td></tr>",
  3871 + "</tbody>",
  3872 + "</table>",
  3873 + "</td>",
  3874 + "</tr>",
  3875 + (if content_width > width then
  3876 + [
  3877 + "<tr>",
  3878 + "<td align=right>",
  3879 + "<table>",
  3880 + "<tbody>",
  3881 + "<tr>",
  3882 + "<td><img alt=\"scroll left\" src=\"scrollleft.gif\" onmousedown=\"doscroll_", idnum,"(20,0);\"></td>",
  3883 + "<td><img alt=\"scroll right\" src=\"scrollright.gif\" onmousedown=\"doscroll_", idnum,"(-20,0);\"></td>",
  3884 + "</tr>",
  3885 + "</tbody>",
  3886 + "</table>",
  3887 + "</td>",
  3888 + "</tr>",
  3889 + ] else [ ]),
  3890 + "</tbody>",
  3891 + "</table>"
  3892 + ].
  3893 +
  3894 +
  3895 +
  3896 +define Printable_tree
  3897 + format
  3898 + (
  3899 + Body_Option o
  3900 + ) =
  3901 + if o is
  3902 + {
  3903 + core_attrs(core_attr_list) then [" " + format_attrs(core_attr_list)],
  3904 + background_color(c) then [" bgcolor=\"" , (String)html_format(c), "\""],
  3905 + background_image(n) then [" background=", n],
  3906 + background_image(n,o2) then [" style=\"background: url(",n,")",format(o2),"\""]
  3907 +
  3908 + }.
  3909 +
  3910 +
  3911 +
  3912 +define Printable_tree
  3913 + format
  3914 + (
  3915 + List(Body_Option) l
  3916 + ) =
  3917 + if l is
  3918 + {
  3919 + [ ] then [ ],
  3920 + [h . t] then [format(h) . format(t)]
  3921 + }.
  3922 +
  3923 +define Printable_tree
  3924 + add_css_files
  3925 + (
  3926 + List(CSS_File) l
  3927 + ) =
  3928 + if l is
  3929 + {
  3930 + [ ] then [ ],
  3931 + [h . t] then
  3932 + [ ["<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file_name(h) + "\" />\n" ]
  3933 + . add_css_files(t)]
  3934 + }.
  3935 +
  3936 +define Printable_tree
  3937 + add_js_files_attributes
  3938 + (
  3939 + List(JS_Attribute) l
  3940 + ) =
  3941 + if l is
  3942 + {
  3943 + [ ] then [ ],
  3944 + [h . t] then
  3945 + if h is attr(name, value) then
  3946 + [ " " + name + "=\"" + value + "\""
  3947 + . add_js_files_attributes(t)]
  3948 + }.
  3949 +
  3950 +
  3951 +define Printable_tree
  3952 + add_js_files
  3953 + (
  3954 + List(JS_File) l
  3955 + ) =
  3956 + if l is
  3957 + {
  3958 + [ ] then [ ],
  3959 + [h . t] then
  3960 + [ ["<script src=\""+ file_name(h) +"\" type=\"text/javascript\""
  3961 + . add_js_files_attributes(attributes(h)) ]
  3962 + . ["></script>\n"
  3963 + . add_js_files(t)] ]
  3964 + }.
  3965 +
  3966 +define Printable_tree
  3967 + add_script
  3968 + (
  3969 + List(Script) l
  3970 + ) =
  3971 + if l is
  3972 + {
  3973 + [ ] then [ ],
  3974 + [h . t] then [ "<script type=\""+ script_type(h) +"\">\n"+ content(h) + "\n</script>\n" . add_script(t) ]
  3975 + }.
  3976 +
  3977 +define Printable_tree
  3978 + add_css_styles
  3979 + (
  3980 + List(CSS_Style) css_styles
  3981 + ) =
  3982 +
  3983 + if css_styles is
  3984 + {
  3985 + [] then [],
  3986 + [_ . _] then [ "<style type=\"text/css\"><!--\n",
  3987 + format_css_styles(css_styles),
  3988 + " --></style>\n"
  3989 + ]
  3990 + }.
  3991 +
  3992 +
  3993 + // The function below formats a datum of type 'HTML_Any($T)'.
  3994 +
  3995 +define Printable_tree
  3996 + format
  3997 + (
  3998 + CommonInfo cinfo,
  3999 + String sn, // state_name
  4000 + Var(Int) ic_v,
  4001 + HTML_Any($T) element,
  4002 + $T -> Printable_tree format_element, // able to format a datum of type $T
  4003 + Bool is_https,
  4004 + ) =
  4005 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4006 + if element is
  4007 + {
  4008 + any_text(opts , t) then
  4009 + if opts is
  4010 + {
  4011 + [] then [t],
  4012 + [_ . _] then ["<span", format_text_options(opts), ">",t,"</span>"]
  4013 + },
  4014 + any_preformated(opts,s) then
  4015 + ["<span", format_text_options(opts), "><pre>",s,"</pre></span>"],
  4016 + //["<pre>",s,"</pre>"],
  4017 + any_paragraph(opts,e) then
  4018 + ["<p", format_text_options(opts), ">",format_element(e),"</p>\n"],
  4019 + any_image(opts, url, alt) then
  4020 + ["<img alt=\"",alt,"\" src=\"",url,"\" ", format_attrs(opts)," />"],
  4021 + any_image(opts, url, alt, w, h) then
  4022 + ["<img alt=\"",alt,"\" src=\"",url,"\" width=\"",w,"\" height=\"",h,"\" ", format_attrs(opts)," />"],
  4023 + any_table(opts,h_row, rows, f_row) then
  4024 + ["<table",format(reverse(opts),false),">",
  4025 + format(h_row, format_element),
  4026 + "<tbody>",format(rows,format_element),"</tbody>",
  4027 + format(f_row, format_element),
  4028 + "</table>\n"],
  4029 + any_center(e) then
  4030 + ["<center>",format_element(e),"</center>"],
  4031 + any_mail_to(email,elem) then
  4032 + ["<a href=\"mailto:",email,"\">",format_element(elem),"</a>"],
  4033 + any_scroller(w,h,cw,ch,c) then
  4034 + format_scroller(sn,w,h,cw,ch,new_idnum(ic_v),c,format_element),
  4035 + any_fixed_size(w,h,c) then
  4036 + with url = create_secondary_document(site_directory,secret,sn,format_element,c,w),
  4037 + ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",
  4038 + "secondary document",
  4039 + "</object>"],
  4040 + any_fixed_size_2(w,h,fn) then
  4041 + with url = fn+"?zauth="+make_authorization(site_directory,secret,
  4042 + fn),
  4043 + ["<object data=\"",url,"\" type=\"text/html\" width=\"",format(w),"\" height=\"",format(h),"\" >",
  4044 + "secondary document",
  4045 + "</object>"],
  4046 + any_actioner(c,t,a,an,eo,ja,fn) then
  4047 + format_actioner(cinfo,sn,c,t,a,an,eo,ja,fn,is_https),
  4048 +
  4049 + any_foreign_link_new(target, aspect, url) then
  4050 + format_foreign_link(target, aspect, url, is_https),
  4051 +
  4052 + any_foreign_link(options,url) then
  4053 + ["<a href=\"",url,"\" ", format_text_options(options), "></a>"], // IE7 doesn't support the form <a href="..." />
  4054 + any_foreign_link(options,url,name) then
  4055 + ["<a href=\"",url,"\"><span ", format_text_options(options), ">",name,"</span></a>"],
  4056 + any_private_download(url,name,extra_ext,action) then
  4057 + format_private_download(cinfo,sn,url,name,extra_ext,action),
  4058 + any_div(options, e) then
  4059 + [format_div_option(options), format_element(e),"</div>\n"],
  4060 + any_div_empty(options) then
  4061 + [format_div_option(options), "</div>\n"],
  4062 + any_coreattrs(attributs) then
  4063 + [format_attrs(attributs)]
  4064 + }.
  4065 +
  4066 +
  4067 +
  4068 +
  4069 + // *** [5.8] Formating 'in form' elements.
  4070 +
  4071 +
  4072 +define Printable_tree
  4073 + maybe_label
  4074 + (
  4075 + String label_text,
  4076 + HtmlId id
  4077 + ) =
  4078 + if length(label_text) > 0 then ["<label for=\"",id,"\">",label_text,"</label>"]
  4079 + else [].
  4080 +
  4081 +
  4082 +define Printable_tree
  4083 + format
  4084 + (
  4085 + CommonInfo cinfo,
  4086 + String fn, // form_name
  4087 + String sn, // state_name
  4088 + Var(Int) ic_v, // idnum counter variable
  4089 + HTML_In_Form element,
  4090 + Bool is_https,
  4091 + ) =
  4092 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4093 + with format_element = (HTML_In_Form e) |-> format(cinfo,fn,sn,ic_v,e,is_https),
  4094 + if element is
  4095 + {
  4096 + literal_pt(t) then t,
  4097 + literal(t) then [t],
  4098 + sequence(l) then flat(map(format_element,l))
  4099 + text(opts,t) then
  4100 + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https),
  4101 + preformated(o,s) then
  4102 + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https),
  4103 + paragraph(opts,t) then
  4104 + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https),
  4105 + image(opts, url, alt) then
  4106 + format(cinfo,sn,ic_v,any_image(opts, url, alt),format_element,is_https),
  4107 + image(opts, url, alt, w, h) then
  4108 + format(cinfo,sn,ic_v,any_image(opts, url, alt, w, h),format_element,is_https),
  4109 + table(opts,header_row,rows,footer_row) then
  4110 + format(cinfo,sn,ic_v,any_table(opts, header_row, rows, footer_row),format_element,is_https),
  4111 + center(e) then
  4112 + format(cinfo,sn,ic_v,any_center(e),format_element,is_https),
  4113 + mail_to(a,e) then
  4114 + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https),
  4115 + scroller(w,h,cw,ch,c) then
  4116 + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https),
  4117 + actioner(c,t,a,an,eo,ja) then
  4118 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https),
  4119 +
  4120 + foreign_link_new(target, aspect, url) then
  4121 + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https),
  4122 +
  4123 + foreign_link(options,url) then
  4124 + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https),
  4125 + foreign_link(options,url,name) then
  4126 + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https),
  4127 + private_download(url,name,extra,action) then
  4128 + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https),
  4129 + text_input(options, label_text, id, name, i, w) then
  4130 + [ maybe_label(label_text, id),
  4131 + "<input type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4132 + text_input_ro(options, label_text, id, name,i,w) then
  4133 + [ maybe_label(label_text, id),
  4134 + "<input readonly=\"readonly\" type=\"text\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4135 + password_input(options, label_text, id, name,i,w) then
  4136 + [ maybe_label(label_text, id),
  4137 + "<input type=\"password\" name=\"",name,"\" id=\"",id,"\" size=\"",w,"\" value=\"",i,"\"",format_attrs(options)," />"],
  4138 + text_area(opts,label_text, id, n,i,w,h) then
  4139 + [ maybe_label(label_text, id), "<textarea ",format(opts)," id=\"",id,"\" name=\"",n,"\" cols=\"",w,"\" rows=\"",h,"\">",i,"</textarea>"],
  4140 + file_upload(options, label, id, n, w) then
  4141 + [ maybe_label(label, id),
  4142 + "<input type=\"file\" id=\"",id,"\" size=\"",w,"\" name=\"",n,"\"",format_attrs(options)," />"],
  4143 + selector(opts, label, id, n,s,cs) then
  4144 + [ maybe_label(label, id),
  4145 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],
  4146 + selector(opts, label, id, n,s,cs,sd) then
  4147 + [ maybe_label(label, id),
  4148 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],
  4149 + selector_c(opts, label, id, n,s,cs) then
  4150 + [ maybe_label(label, id),
  4151 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs),"</select>"],
  4152 + selector_c(opts, label, id, n,s,cs,sd) then
  4153 + [ maybe_label(label, id),
  4154 + "<select id=\"",id,"\" name=\"",n,"\" size=\"",s,"\" ",format_attrs(opts),">",format_choices(cs,sd),"</select>"],
  4155 +
  4156 + radio_button(options, label_text, id, n, v, c) then
  4157 + [ maybe_label(label_text, id),
  4158 + "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />"],
  4159 + radio_button_r(options, label_text, id, n, v, c) then
  4160 + [ "<input type=\"radio\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\"" else ""),format_attrs(options)," />",
  4161 + maybe_label(label_text, id)],
  4162 + check_box(options, label_text, id, n, v, c) then
  4163 + [ maybe_label(label_text, id),
  4164 + "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />"]
  4165 + check_box_r(options, label_text, id, n, v, c) then
  4166 + [ "<input type=\"checkbox\" name=\"",n,"\" id=\"",id,"\" value=\"",v,"\"",(if c then " checked=\"checked\" " else ""),format_attrs(options)," />",
  4167 + maybe_label(label_text, id)]
  4168 + div(options, e) then
  4169 + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https),
  4170 + div_empty(options) then
  4171 + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https),
  4172 + hidden(id, name, value) then
  4173 + ["<input type=\"hidden\" id=\"",id,"\" name=\"",name,"\" value=\"",value,"\" />"],
  4174 +
  4175 + }.
  4176 +
  4177 +
  4178 +
  4179 +
  4180 +
  4181 +
  4182 + *** [5.9] Formating 'off form' elements.
  4183 +
  4184 + The encryption type 'multipart/form-data' is required for a form containing an upload.
  4185 +
  4186 +
  4187 +define Bool
  4188 + contains_an_upload
  4189 + (
  4190 + HTML_In_Form form_content
  4191 + ).
  4192 +
  4193 +define Bool
  4194 + contains_an_upload
  4195 + (
  4196 + HTML_Row(HTML_In_Form) row
  4197 + ) =
  4198 + mapor(contains_an_upload,
  4199 + map(content,cells(row))).
  4200 +
  4201 +define Bool
  4202 + contains_an_upload
  4203 + (
  4204 + HTML_Footer_Row(HTML_In_Form) row
  4205 + ) =
  4206 + if row is
  4207 + {
  4208 + empty then false,
  4209 + footer_row(_, cells) then
  4210 + mapor(contains_an_upload,
  4211 + map(content,cells))
  4212 + }.
  4213 +
  4214 +define Bool
  4215 + contains_an_upload
  4216 + (
  4217 + HTML_In_Form form_content
  4218 + ) =
  4219 + if form_content is
  4220 + {
  4221 + literal_pt(t) then false,
  4222 + literal(t) then false,
  4223 + sequence(l) then mapor(contains_an_upload,l)
  4224 + text(o,t) then false,
  4225 + preformated(o,s) then false,
  4226 + paragraph(o,t) then false,
  4227 + image(o,u,a) then false,
  4228 + image(o,u,a,w,h) then false,
  4229 + table(o,_,rows,f_row) then if mapor(contains_an_upload,rows) then true
  4230 + else contains_an_upload(f_row),
  4231 + center(e) then contains_an_upload(e),
  4232 + mail_to(m,e) then false, // 'e' may but should not contain an upload
  4233 + scroller(w,h,cw,ch,e) then contains_an_upload(e),
  4234 + actioner(c,t,a,an,eo,ja) then false,
  4235 + foreign_link_new(_,_,_) then false,
  4236 + foreign_link(o,u) then false,
  4237 + foreign_link(o,u,n) then false,
  4238 + private_download(p,n,e,a) then false,
  4239 + text_input(o,lt,l,n,i,w) then false,
  4240 + text_input_ro(o,lt,l,n,i,w) then false,
  4241 + password_input(o,lt,l,n,i,w) then false,
  4242 + text_area(o,lt,id,n,i,w,h) then false,
  4243 + file_upload(o,l,i,n,w) then true,
  4244 + selector(o,l,i,n,s,c) then false,
  4245 + selector(o,l,i,n,s,c,p) then false,
  4246 + selector_c(o,l,i,n,s,c) then false,
  4247 + selector_c(o,l,i,n,s,c,p) then false,
  4248 + radio_button(o,_,_,n,v,c) then false,
  4249 + radio_button_r(o,_,_,n,v,c) then false,
  4250 + check_box(o,_,_,n,v,c) then false,
  4251 + check_box_r(o,_,_,n,v,c) then false,
  4252 + div(o,c) then contains_an_upload(c),
  4253 + div_empty(o) then false,
  4254 + hidden(_,_,_) then false
  4255 + }.
  4256 +
  4257 +define String
  4258 + enctype
  4259 + (
  4260 + HTML_In_Form form_content
  4261 + ) =
  4262 + if contains_an_upload(form_content)
  4263 + then " enctype=\"multipart/form-data\""
  4264 + else "".
  4265 +
  4266 +
  4267 +
  4268 +define Printable_tree
  4269 + format
  4270 + (
  4271 + CommonInfo cinfo,
  4272 + String sn, // state_name
  4273 + Var(Int) ic_v, // 'idnum' counter variable
  4274 + HTML_Off_Form element,
  4275 + Bool is_https,
  4276 + ) =
  4277 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4278 + with format_element = (HTML_Off_Form e) |-> format(cinfo,sn,ic_v,e,is_https),
  4279 + if element is
  4280 + {
  4281 + literal_pt(t) then t,
  4282 + literal(t) then [t],
  4283 + sequence(l) then flat(map(format_element,l)),
  4284 + text(opts,t) then
  4285 + format(cinfo,sn,ic_v,any_text(opts,t),format_element,is_https),
  4286 + preformated(o,s) then
  4287 + format(cinfo,sn,ic_v,any_preformated(o,s),format_element,is_https),
  4288 + paragraph(opts,t) then
  4289 + format(cinfo,sn,ic_v,any_paragraph(opts,t),format_element,is_https),
  4290 + image(opts,url,alt) then
  4291 + format(cinfo,sn,ic_v,any_image(opts,url,alt),format_element,is_https),
  4292 + image(opts,url,alt,w,h) then
  4293 + format(cinfo,sn,ic_v,any_image(opts,url,alt,w,h),format_element,is_https),
  4294 + table(opts,header_row, rows, footer_row) then
  4295 + format(cinfo,sn,ic_v,any_table(opts,header_row, rows, footer_row),format_element,is_https),
  4296 + center(e) then
  4297 + format(cinfo,sn,ic_v,any_center(e),format_element,is_https),
  4298 + mail_to(a,e) then
  4299 + format(cinfo,sn,ic_v,any_mail_to(a,e),format_element,is_https),
  4300 + scroller(w,h,cw,ch,c) then
  4301 + format(cinfo,sn,ic_v,any_scroller(w,h,cw,ch,c),format_element,is_https),
  4302 + fixed_size(w,h,c) then
  4303 + format(cinfo,sn,ic_v,any_fixed_size(w,h,c),format_element,is_https),
  4304 + fixed_size_2(w,h,fn) then
  4305 + format(cinfo,sn,ic_v,any_fixed_size_2(w,h,fn),format_element,is_https),
  4306 + actioner(c,t,a,an,eo,ja) then
  4307 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,failure),format_element,is_https),
  4308 + actioner(c,t,a,an,eo,ja,fn) then
  4309 + format(cinfo,sn,ic_v,any_actioner(c,t,a,an,eo,ja,success(fn)),format_element,is_https),
  4310 + foreign_link_new(target, aspect, url) then
  4311 + format(cinfo,sn,ic_v,any_foreign_link_new(target,aspect,url),format_element,is_https),
  4312 + foreign_link(options,url) then
  4313 + format(cinfo,sn,ic_v,any_foreign_link(options,url),format_element,is_https),
  4314 + foreign_link(options,url,name) then
  4315 + format(cinfo,sn,ic_v,any_foreign_link(options,url,name),format_element,is_https),
  4316 + private_download(url,name,extra,action) then
  4317 + format(cinfo,sn,ic_v,any_private_download(url,name,extra,action),format_element,is_https),
  4318 + label(n) then ["<a name=\"",n,"\">"],
  4319 + form(fn,attributs, c) then
  4320 + [
  4321 + "<form id=\"",fn,"\"",
  4322 + format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https),
  4323 + " method=\"post\"",
  4324 + enctype(c),
  4325 + " action=\"http",
  4326 + if is_https then "s" else "",
  4327 + "://",common_name,":",to_decimal(http_port),"/\">",
  4328 + // action is set dynamically by
  4329 + // the actioner using JavaScript
  4330 + if fn is htmlId(id) then
  4331 + format(cinfo,id,sn,ic_v,c,is_https),
  4332 + "</form>"
  4333 + ]
  4334 + form(fn,attributs, action_name, extra_ops, c) then
  4335 + with url = make_actioner_url(cinfo, same, same,
  4336 + sn, action_name, extra_ops, is_https),
  4337 + [
  4338 + "<form id=\"",fn,"\"",
  4339 + format(cinfo,sn,ic_v,any_coreattrs(attributs),format_element,is_https),
  4340 + " method=\"post\"",
  4341 + enctype(c),
  4342 + " action=\"" + url + "\">",
  4343 +// " action=\"http",
  4344 +// if is_https then "s" else "",
  4345 +// "://",common_name,":",http_port,"/\">",
  4346 + // action is set dynamically by
  4347 + // the actioner using JavaScript
  4348 + if fn is htmlId(id) then
  4349 + format(cinfo,id,sn,ic_v,c,is_https),
  4350 + "</form>"
  4351 + ]
  4352 + div(options, e) then
  4353 + format(cinfo,sn,ic_v,any_div(options, e),format_element,is_https),
  4354 + div_empty(options) then
  4355 + format(cinfo,sn,ic_v,any_div_empty(options),format_element,is_https),
  4356 + iframe(options, css_styles, css_files, js_files, body) then
  4357 + if body is body(body_options,element) then
  4358 + [ "<iframe", format_attrs(options), ">\n",
  4359 + "<html style=\"margin: 0pt; padding: 0pt;\">\n",
  4360 + "<head>\n",
  4361 + add_css_styles(css_styles),
  4362 + add_css_files(css_files),
  4363 + add_js_files(js_files),
  4364 + "</head>\n",
  4365 + "<body ", format(body_options), ">\n", // format body options
  4366 + format(cinfo,sn,ic_v,element,is_https),
  4367 + "</body>\n",
  4368 + "</html>\n",
  4369 + "</iframe>\n",
  4370 + ],
  4371 +
  4372 + }.
  4373 +
  4374 +
  4375 +
  4376 +
  4377 + *** [5.10] Formating meta-tags.
  4378 +
  4379 +define Printable_tree
  4380 + format_keywords
  4381 + (
  4382 + List(String) l
  4383 + ) =
  4384 + if l is
  4385 + {
  4386 + [] then [ ],
  4387 + [h . t] then if t is []
  4388 + then [h]
  4389 + else [h , ", " . format_keywords(t)]
  4390 + }.
  4391 +
  4392 +
  4393 +define Printable_tree
  4394 + format
  4395 + (
  4396 + CommonInfo cinfo,
  4397 + String state_name,
  4398 + HTML_Meta m,
  4399 + Bool is_https
  4400 + ) =
  4401 + if m is
  4402 + {
  4403 + keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],
  4404 + refresh(co,ta,an,delay) then
  4405 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",
  4406 + make_actioner_url(cinfo,co,ta,state_name,an,[],is_https),"\" />\n"],
  4407 + refresh(url,delay) then
  4408 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],
  4409 + meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],
  4410 + http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],
  4411 + generic_meta(l) then ["<meta ",
  4412 + flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],
  4413 + l)),
  4414 + " />\n"],
  4415 + literal(s) then [s]
  4416 + }.
  4417 +
  4418 +define Printable_tree // c'est le nôtre et c'est meilleur
  4419 + format
  4420 + (
  4421 + HTML_Meta m,
  4422 + ) =
  4423 + if m is
  4424 + {
  4425 + keywords(l) then ["<meta name=\"keywords\" content=\"",format_keywords(l),"\" />\n"],
  4426 + refresh(co,ta,an,delay) then
  4427 + ["<!-- TODO refresh(co,ta,an,delay) --> "], // TODO
  4428 + refresh(url,delay) then
  4429 + ["<meta http-equiv=\"Refresh\" content=\"",delay,"; URL=",url,"\" />\n"],
  4430 + meta(n,c) then ["<meta name=\"",n,"\" content=\"",c,"\" />\n"],
  4431 + http_equiv(n,c) then ["<meta http-equiv=\"",n,"\" content=\"",c,"\" />\n"],
  4432 + generic_meta(l) then ["<meta ",
  4433 + flat(map(((String,String) p) |-> if p is (n,v) then [n,"=\"",v,"\" "],
  4434 + l)),
  4435 + " />\n"],
  4436 + literal(s) then [s]
  4437 + }.
  4438 +
  4439 +
  4440 +define Printable_tree
  4441 + format
  4442 + (
  4443 + CommonInfo cinfo,
  4444 + String state_name,
  4445 + List(HTML_Meta) metas,
  4446 + Bool is_https,
  4447 + String charset
  4448 + ) =
  4449 + if metas is
  4450 + {
  4451 + [] then [format(cinfo,state_name,http_equiv("content-type",
  4452 + "text/html; charset="+charset),is_https)],
  4453 + [h . t] then [format(cinfo,state_name,h,is_https)
  4454 + . format(cinfo,state_name,t,is_https,charset)]
  4455 + }.
  4456 +
  4457 +define Printable_tree
  4458 + _format_html_head
  4459 + (
  4460 + List(HTML_Head_Tag) lwf,
  4461 + Printable_tree so_far
  4462 + )
  4463 + =
  4464 + if lwf is
  4465 + {
  4466 + [] then reverse(so_far),
  4467 + [ h . t] then
  4468 + if h is
  4469 + {
  4470 + meta(meta) then
  4471 + [format(meta) . _format_html_head(t, so_far)],
  4472 + title(title) then
  4473 + ["<title>"+title+"</title>\n" . _format_html_head(t, so_far)],
  4474 + js(jsf) then
  4475 + [add_js_files([jsf]) . _format_html_head(t, so_far)],
  4476 + js_inline(jsi) then
  4477 + ["<script>"+content(jsi)+"</script>\n" . _format_html_head(t, so_far)],
  4478 + css(cssf) then
  4479 + ["<link rel=\"stylesheet\" type=\"text/css\" href=\""+file_name(cssf)+"\" />\n" . _format_html_head(t, so_far)],
  4480 + css_inline(cssi) then
  4481 + ["<style>"+cssi+"</style>\n" . _format_html_head(t, so_far)]
  4482 + }
  4483 + }
  4484 + .
  4485 +
  4486 +public define Printable_tree
  4487 + format_html_head
  4488 + (
  4489 + List(HTML_Head_Tag) lwf,
  4490 + String charset
  4491 + )
  4492 + =
  4493 + with lwf = (List(HTML_Head_Tag))[ meta(http_equiv("content-type", "text/html; charset="+charset)) . lwf],
  4494 + if lwf is
  4495 + {
  4496 + [] then
  4497 + [],
  4498 + [ h . t] then
  4499 + _format_html_head(lwf, [])
  4500 + }
  4501 + .
  4502 +
  4503 +define Printable_tree
  4504 + format
  4505 + (
  4506 + CommonInfo cinfo,
  4507 + String state_name,
  4508 + List(HTTP_header) additional_headers,
  4509 + HTTP_Answer page,
  4510 + Bool is_https,
  4511 + String charset
  4512 + ) =
  4513 + if cinfo is info(common_name,http_port,https_port,site_directory,secret) then
  4514 + with ic_v = var((Int)0),
  4515 + if page is
  4516 + {
  4517 + html_page(status, head_tags, body) then
  4518 + if body is body(options,element) then
  4519 + if format(status) is (status_string, status_headers) then
  4520 + with answer_body =
  4521 + [doctype_w3c_header,
  4522 + html_header,
  4523 +
  4524 + "<head>\n", format_html_head(head_tags, charset),"</head>\n",
  4525 +
  4526 + "<body ", format(options), ">", // format body options
  4527 + format(cinfo,state_name,ic_v,element,is_https),
  4528 + "</body>\n",
  4529 +
  4530 + "</html>"],
  4531 + [ "HTTP/1.1 " + status_string, crlf,
  4532 + format_headers(standard_headers),
  4533 + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),
  4534 + format_headers(status_headers),
  4535 + format_headers(additional_headers),
  4536 + crlf
  4537 + . answer_body
  4538 + ]
  4539 +
  4540 + html_page(status, title, metas, css_styles, css_files, js_files, script, body) then
  4541 + if body is body(options,element) then
  4542 + if format(status) is (status_string, status_headers) then
  4543 + with answer_body =
  4544 + [ doctype_w3c_header,
  4545 + html_header,
  4546 + "<head>\n",
  4547 + add_css_styles(css_styles),
  4548 + add_css_files(css_files),
  4549 + add_js_files(js_files),
  4550 + add_script(script),
  4551 + "<link rel=\"shortcut icon\" href=\"favicon.ico\" />\n",
  4552 + "<script type = \"text/javascript\" language=\"JavaScript\">",
  4553 + " function show_local_popup(divname,stvname) {",
  4554 + " if (document.layers) { var d = eval(document.divname); } else\n",
  4555 + " if (document.getElementById) { var d = eval(\"document.getElementById(divname)\"); } else\n",
  4556 + " if (document.all) { var d = eval(document.all.divname.style)};\n",
  4557 + // " alert(typeof(eval(stvname))); ",
  4558 + " var s = eval(stvname); ",
  4559 + " if (s[0]==0) ",
  4560 + " { s[0]=1; d.style.visibility = 'visible'; d.zIndex = 100; } else\n",
  4561 + " { s[0]=0; d.style.visibility = 'hidden'; }; }",
  4562 + "</script>\n",
  4563 + "<title>",title,"</title>\n", // put title
  4564 + format(cinfo,state_name,metas,is_https,charset), // format the metas
  4565 + "</head>\n",
  4566 + "<body ", format(options), ">", // format body options
  4567 + //"<center>",
  4568 + format(cinfo,state_name,ic_v,element,is_https),
  4569 + //"</center>",
  4570 + "</body>\n",
  4571 + "</html>"
  4572 + ],
  4573 + [ "HTTP/1.1 " + status_string, crlf,
  4574 + format_headers(standard_headers),
  4575 + format_headers(standard_headers_for("text/html", length(answer_body), success(charset))),
  4576 + format_headers(status_headers),
  4577 + format_headers(additional_headers),
  4578 + crlf
  4579 + . answer_body
  4580 + ],
  4581 +
  4582 + plain_text (HTTP_Status status, String text) then
  4583 + if format(status) is (status_string, status_headers) then
  4584 + [ "HTTP/1.1 " + status_string, crlf,
  4585 + format_headers(standard_headers),
  4586 + format_headers(standard_headers_for("text/plain", length(text), success(charset))),
  4587 + format_headers(status_headers),
  4588 + format_headers(additional_headers),
  4589 + crlf,
  4590 + text . (Printable_tree)[]
  4591 + ],
  4592 +
  4593 + custom_text(HTTP_Status status, String mime_type, String content) then
  4594 + if format(status) is (status_string, status_headers) then
  4595 + [ "HTTP/1.1 " + status_string, crlf,
  4596 + format_headers(standard_headers),
  4597 + format_headers(standard_headers_for(mime_type, length(content), success(charset))),
  4598 + format_headers(status_headers),
  4599 + format_headers(additional_headers),
  4600 + crlf,
  4601 + content . (Printable_tree)[]
  4602 + ],
  4603 + custom_binary(HTTP_Status status, String mime_type, ByteArray content, List(HTTP_header) other_headers) then
  4604 + if format(status) is (status_string, status_headers) then
  4605 + [ "HTTP/1.1 " + status_string, crlf,
  4606 + format_headers(status_headers),
  4607 + format_headers(standard_headers_for(mime_type, length(content), failure)),
  4608 + format_headers(status_headers),
  4609 + format_headers(other_headers),
  4610 + format_headers(additional_headers),
  4611 + crlf,
  4612 + content . (Printable_tree)[]
  4613 + ],
  4614 +
  4615 + custom_tree(HTTP_Status status, String mime_type, Printable_tree content) then
  4616 + if format(status) is (status_string, status_headers) then
  4617 + [ "HTTP/1.1 " + status_string, crlf,
  4618 + format_headers(standard_headers),
  4619 + format_headers(standard_headers_for(mime_type, length(content), success(charset))),
  4620 + format_headers(status_headers),
  4621 + format_headers(additional_headers),
  4622 + crlf .
  4623 + content
  4624 + ],
  4625 +
  4626 + http_raw(Printable_tree content) then content,
  4627 +
  4628 + html_content(HTTP_Status status, HTML_Off_Form content_HTML) then
  4629 + if format(status) is (status_string, status_headers) then
  4630 + with content = format(cinfo, state_name, ic_v, content_HTML, is_https),
  4631 + [ "HTTP/1.1 " + status_string, crlf,
  4632 + format_headers(standard_headers),
  4633 + format_headers(standard_headers_for("text/html", length(content), success(charset))),
  4634 + format_headers(status_headers),
  4635 + format_headers(additional_headers),
  4636 + crlf .
  4637 + content
  4638 + ],
  4639 + }.
  4640 +
web/CXM_multihost_http_server.anubis
@@ -2108,7 +2108,7 @@ define List(HTTP_header) @@ -2108,7 +2108,7 @@ define List(HTTP_header)
2108 with headers = (List(HTTP_header)) 2108 with headers = (List(HTTP_header))
2109 [ 2109 [
2110 http_header("Content-Type", to_String(mime_type)), 2110 http_header("Content-Type", to_String(mime_type)),
2111 - http_header("Etag", etag), 2111 + http_header("Etag", "\""+etag+"\""),
2112 http_header("Content-Length",to_decimal(size)), 2112 http_header("Content-Length",to_decimal(size)),
2113 ], 2113 ],
2114 if mb_ftimes is 2114 if mb_ftimes is
@@ -2170,7 +2170,7 @@ define Bool @@ -2170,7 +2170,7 @@ define Bool
2170 if input_etag is 2170 if input_etag is
2171 { 2171 {
2172 failure then false, 2172 failure then false,
2173 - success(etag) then etag = current_etag 2173 + success(etag) then trim_token(etag, '\"') = current_etag //remove triming " because this is quoted string
2174 }. 2174 }.
2175 2175
2176 Sending the answer line, the headers and the body. 2176 Sending the answer line, the headers and the body.
@@ -2190,19 +2190,19 @@ define One @@ -2190,19 +2190,19 @@ define One
2190 One -> One action_before_send_file 2190 One -> One action_before_send_file
2191 ) = 2191 ) =
2192 action_before_send_file(unique); 2192 action_before_send_file(unique);
2193 - with input_etag = http_header_value(input_headers, "If-None-Match"), 2193 + with input_etag = http_header_value(input_headers, "If-None-Match"),
2194 mb_ftimes = get_file_times(full_path), 2194 mb_ftimes = get_file_times(full_path),
2195 current_etag = compute_etag(full_path, mb_ftimes, size), 2195 current_etag = compute_etag(full_path, mb_ftimes, size),
2196 if are_same_etag(input_etag, current_etag) is 2196 if are_same_etag(input_etag, current_etag) is
2197 { 2197 {
2198 false then 2198 false then
2199 forget(reliable_write(connection,to_byte_array("HTTP/1.1 200 OK"+crlf))); 2199 forget(reliable_write(connection,to_byte_array("HTTP/1.1 200 OK"+crlf)));
2200 - forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, current_etag, mb_ftimes)) , crlf])); 2200 + forget(reliable_write(connection,[format_headers(headers + headers_for_send_file(mime_type, size, "\""+current_etag+"\"", mb_ftimes)) , crlf]));
2201 //forget(copy_file_to_Connection(file, connection, size)), 2201 //forget(copy_file_to_Connection(file, connection, size)),
2202 send_file_body(desc,connection,file,size,0,filename), 2202 send_file_body(desc,connection,file,size,0,filename),
2203 true then 2203 true then
2204 forget(reliable_write(connection,to_byte_array("HTTP/1.1 304 Not Modified"+crlf))); 2204 forget(reliable_write(connection,to_byte_array("HTTP/1.1 304 Not Modified"+crlf)));
2205 - forget(reliable_write(connection,[format_headers([http_header("Etag", current_etag) . headers]) , crlf])) 2205 + forget(reliable_write(connection,[format_headers([http_header("Content-length","0") . [http_header("Etag", "\""+current_etag+"\"") . headers]]) , crlf]))
2206 //send_file_body(desc,connection,file,size,0,filename) 2206 //send_file_body(desc,connection,file,size,0,filename)
2207 }. 2207 }.
2208 2208
@@ -2250,7 +2250,12 @@ define One @@ -2250,7 +2250,12 @@ define One
2250 with path = site_directory(desc)+"/public"+uri, 2250 with path = site_directory(desc)+"/public"+uri,
2251 if (Maybe(RStream))file(path, read) is 2251 if (Maybe(RStream))file(path, read) is
2252 { 2252 {
2253 - failure then log_journal_msg(desc,"Cannot find file '"+path+"'.\n"), 2253 + failure then
  2254 + println("HTTP/1.1 404 Not Found"+path);
  2255 + forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+
  2256 + "Content-Length: 0"+crlf+
  2257 + "Connection: close"+crlf+crlf)));
  2258 + log_journal_msg(desc,"Cannot find file '"+path+"'.\n"),
2254 success(f) then with size = file_size(f), 2259 success(f) then with size = file_size(f),
2255 send_file(desc, 2260 send_file(desc,
2256 connection, 2261 connection,
@@ -2275,7 +2280,12 @@ define One @@ -2275,7 +2280,12 @@ define One
2275 absolute_path), 2280 absolute_path),
2276 if (Maybe(RStream))file(absolute_path, read) is 2281 if (Maybe(RStream))file(absolute_path, read) is
2277 { 2282 {
2278 - failure then log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"), 2283 + failure then
  2284 + println("HTTP/1.1 404 Not Found"+absolute_path);
  2285 + forget(reliable_write(connection,to_byte_array("HTTP/1.1 404 Not Found"+crlf+
  2286 + "Content-Length: 0"+crlf+
  2287 + "Connection: close"+crlf+crlf)));
  2288 + log_journal_msg(desc,"Cannot find file '"+absolute_path+"'.\n"),
2279 success(f) then with size = file_size(f), 2289 success(f) then with size = file_size(f),
2280 mime_type = if recognize_mime_type_from_uri(desc,uri) is 2290 mime_type = if recognize_mime_type_from_uri(desc,uri) is
2281 { 2291 {
@@ -3121,6 +3131,21 @@ define Server -&gt; ((RWStream) -&gt; One) @@ -3121,6 +3131,21 @@ define Server -&gt; ((RWStream) -&gt; One)
3121 else 3131 else
3122 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)), 3132 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
3123 http_https_handler(sites, connection, false, dos). 3133 http_https_handler(sites, connection, false, dos).
  3134 +
  3135 +public define One
  3136 + http_direct_handler
  3137 + (
  3138 + List(Web_Site_Description) sites,
  3139 + RWStream conn,
  3140 + DenialOfService dos
  3141 + ) =
  3142 + if remote_IP_address_and_port(conn) is (addr,_) then
  3143 + if is_dubious_IP(addr,dos)
  3144 + then print("Rejecting dubious IP address "+ip_addr_to_string(addr)+"\n")
  3145 + else
  3146 + with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
  3147 + http_https_handler(sites, connection, false, dos).
  3148 +
3124 3149
3125 define Server -> (SSL_Connection -> One) 3150 define Server -> (SSL_Connection -> One)
3126 make_https_handler 3151 make_https_handler