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
Changes suppressed. Click to show
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 2108 with headers = (List(HTTP_header))
2109 2109 [
2110 2110 http_header("Content-Type", to_String(mime_type)),
2111   - http_header("Etag", etag),
  2111 + http_header("Etag", "\""+etag+"\""),
2112 2112 http_header("Content-Length",to_decimal(size)),
2113 2113 ],
2114 2114 if mb_ftimes is
... ... @@ -2170,7 +2170,7 @@ define Bool
2170 2170 if input_etag is
2171 2171 {
2172 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 2176 Sending the answer line, the headers and the body.
... ... @@ -2190,19 +2190,19 @@ define One
2190 2190 One -> One action_before_send_file
2191 2191 ) =
2192 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 2194 mb_ftimes = get_file_times(full_path),
2195 2195 current_etag = compute_etag(full_path, mb_ftimes, size),
2196 2196 if are_same_etag(input_etag, current_etag) is
2197 2197 {
2198 2198 false then
2199 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 2201 //forget(copy_file_to_Connection(file, connection, size)),
2202 2202 send_file_body(desc,connection,file,size,0,filename),
2203 2203 true then
2204 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 2206 //send_file_body(desc,connection,file,size,0,filename)
2207 2207 }.
2208 2208  
... ... @@ -2250,7 +2250,12 @@ define One
2250 2250 with path = site_directory(desc)+"/public"+uri,
2251 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 2259 success(f) then with size = file_size(f),
2255 2260 send_file(desc,
2256 2261 connection,
... ... @@ -2275,7 +2280,12 @@ define One
2275 2280 absolute_path),
2276 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 2289 success(f) then with size = file_size(f),
2280 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 3131 else
3122 3132 with connection = buffered_connection(tcp(conn), var(constant_byte_array(0, 0)), var(0)),
3123 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 3150 define Server -> (SSL_Connection -> One)
3126 3151 make_https_handler
... ...