mhttpd.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 
00003   Name:         mhttpd.c
00004   Created by:   Stefan Ritt
00005 
00006   Contents:     Web server program for midas RPC calls
00007 
00008   $Id: mhttpd.c 4830 2010-09-23 15:40:30Z olchanski $
00009 
00010 \********************************************************************/
00011 
00012 const char *mhttpd_svn_revision = "$Rev: 4830 $";
00013 
00014 #include <math.h>
00015 #include <assert.h>
00016 #include <float.h>
00017 #include <algorithm>
00018 #include "midas.h"
00019 #include "msystem.h"
00020 extern "C" {
00021 #include "mgd.h"
00022 }
00023 #include "history.h"
00024 
00025 #ifdef HAVE_MSCB
00026 #include "mscb.h"
00027 #endif
00028 
00029 /* refresh times in seconds */
00030 #define DEFAULT_REFRESH 60
00031 
00032 /* time until mhttpd disconnects from MIDAS */
00033 #define CONNECT_TIME  3600*24
00034 
00035 /* size of buffer for incoming data, must fit sum of all attachments */
00036 #define WEB_BUFFER_SIZE 10000000
00037 
00038 char return_buffer[WEB_BUFFER_SIZE];
00039 int strlen_retbuf;
00040 int return_length;
00041 char host_name[256];
00042 char referer[256];
00043 int tcp_port = 80;
00044 
00045 #define MAX_GROUPS    32
00046 #define MAX_VARS     100
00047 #define MAX_PARAM    500
00048 #define PARAM_LENGTH 256
00049 #define TEXT_SIZE  50000
00050 
00051 char _param[MAX_PARAM][PARAM_LENGTH];
00052 char *_value[MAX_PARAM];
00053 char _text[TEXT_SIZE];
00054 char *_attachment_buffer[3];
00055 INT _attachment_size[3];
00056 struct in_addr remote_addr;
00057 INT _sock;
00058 BOOL elog_mode = FALSE;
00059 BOOL history_mode = FALSE;
00060 BOOL verbose = FALSE;
00061 char midas_hostname[256];
00062 char midas_expt[256];
00063 #define MAX_N_ALLOWED_HOSTS 10
00064 char allowed_host[MAX_N_ALLOWED_HOSTS][PARAM_LENGTH];
00065 int  n_allowed_hosts;
00066 
00067 const char *mname[] = {
00068    "January",
00069    "February",
00070    "March",
00071    "April",
00072    "May",
00073    "June",
00074    "July",
00075    "August",
00076    "September",
00077    "October",
00078    "November",
00079    "December"
00080 };
00081 
00082 char type_list[20][NAME_LENGTH] = {
00083    "Routine",
00084    "Shift summary",
00085    "Minor error",
00086    "Severe error",
00087    "Fix",
00088    "Question",
00089    "Info",
00090    "Modification",
00091    "Reply",
00092    "Alarm",
00093    "Test",
00094    "Other"
00095 };
00096 
00097 char system_list[20][NAME_LENGTH] = {
00098    "General",
00099    "DAQ",
00100    "Detector",
00101    "Electronics",
00102    "Target",
00103    "Beamline"
00104 };
00105 
00106 
00107 struct Filetype {
00108    char ext[32];
00109    char type[32];
00110 };
00111 
00112 const Filetype filetype[] = {
00113 
00114    {
00115    ".JPG", "image/jpeg",}, {
00116    ".GIF", "image/gif",}, {
00117    ".PNG", "image/png",}, {
00118    ".PS", "application/postscript",}, {
00119    ".EPS", "application/postscript",}, {
00120    ".HTML", "text/html",}, {
00121    ".HTM", "text/html",}, {
00122    ".XLS", "application/x-msexcel",}, {
00123    ".DOC", "application/msword",}, {
00124    ".PDF", "application/pdf",}, {
00125    ".TXT", "text/plain",}, {
00126    ".ASC", "text/plain",}, {
00127    ".ZIP", "application/x-zip-compressed",}, {
00128 ""},};
00129 
00130 /*------------------------------------------------------------------*/
00131 
00132 const unsigned char favicon_png[] = {
00133    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48,
00134    0x44, 0x52,
00135    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90,
00136    0x91, 0x68,
00137    0x36, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD4, 0x0B, 0x1A, 0x08,
00138    0x37, 0x07,
00139    0x0D, 0x7F, 0x16, 0x5C, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
00140    0x2E, 0x23,
00141    0x00, 0x00, 0x2E, 0x23, 0x01, 0x78, 0xA5, 0x3F, 0x76, 0x00, 0x00, 0x00, 0x04, 0x67,
00142    0x41, 0x4D,
00143    0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, 0x01, 0x7D, 0x49,
00144    0x44, 0x41,
00145    0x54, 0x78, 0xDA, 0x63, 0xFC, 0xFF, 0xFF, 0x3F, 0x03, 0x29, 0x80, 0x09, 0xAB, 0xE8,
00146    0xD2, 0x65,
00147    0x77, 0x36, 0x6F, 0x7E, 0x8A, 0x5D, 0xC7, 0x7F, 0x0C, 0x30, 0x67, 0xEE, 0x0D, 0x56,
00148    0xCE, 0xCD,
00149    0x5C, 0xBC, 0x3B, 0xB6, 0x6D, 0x7F, 0x81, 0x29, 0xCB, 0x88, 0xE6, 0x24, 0x20, 0x57,
00150    0x50, 0x7C,
00151    0xDD, 0xCF, 0x1F, 0x6C, 0x40, 0xCB, 0xB5, 0xB5, 0x05, 0xCF, 0x1C, 0xB7, 0x42, 0xB3,
00152    0x80, 0x05,
00153    0x8D, 0xCF, 0xC8, 0xC8, 0x58, 0x5A, 0x2A, 0xFB, 0xF6, 0x4D, 0x37, 0x1B, 0xAB, 0xA0,
00154    0xB4, 0x4C,
00155    0x0A, 0x51, 0x4E, 0x02, 0x82, 0x85, 0xCB, 0x12, 0x0E, 0x1D, 0xAB, 0xC7, 0x2A, 0xC5,
00156    0x82, 0x69,
00157    0xC4, 0xAF, 0x5F, 0x7F, 0x1E, 0x3F, 0xF8, 0xCD, 0xCB, 0xF1, 0xF5, 0xEF, 0xDF, 0x7F,
00158    0xCC, 0xCC,
00159    0x4C, 0x84, 0x6D, 0x98, 0x59, 0xD5, 0xEB, 0xCF, 0xA5, 0x16, 0xC4, 0xAB, 0x71, 0x72,
00160    0xCB, 0x21,
00161    0x4C, 0x59, 0x74, 0x03, 0x5E, 0x3F, 0x7F, 0xB3, 0x6B, 0xD6, 0x22, 0x46, 0xA6, 0x7F,
00162    0x0C, 0x0C,
00163    0x7F, 0xD7, 0x75, 0x4D, 0xFB, 0xF1, 0xFD, 0x27, 0x81, 0x78, 0xB8, 0x7D, 0xE9, 0x0A,
00164    0xCB, 0xFF,
00165    0xDF, 0x4C, 0x8C, 0x8C, 0x40, 0xF6, 0xAD, 0x4B, 0x67, 0x1F, 0xDE, 0xBD, 0x8B, 0x45,
00166    0x03, 0x3C,
00167    0x60, 0x8F, 0x9D, 0xD8, 0xB3, 0xEB, 0x74, 0xB5, 0x90, 0x26, 0x07, 0x03, 0x48, 0xE4,
00168    0x3F, 0x8F,
00169    0xF6, 0xFF, 0x1B, 0x0F, 0x9A, 0x1E, 0x3E, 0x3A, 0xFB, 0xF3, 0xDB, 0x8F, 0xB7, 0x0F,
00170    0x9E, 0x43,
00171    0x83, 0xF1, 0xCF, 0xDF, 0x3F, 0x8A, 0x29, 0xCE, 0x3F, 0x7F, 0xFD, 0xFC, 0xCF, 0xF0,
00172    0xDF, 0x98,
00173    0xE9, 0xB5, 0x8F, 0xBD, 0x8A, 0x3C, 0x6F, 0xEC, 0xB9, 0x2D, 0x47, 0xFE, 0xFC, 0xFF,
00174    0x6F, 0x16,
00175    0x6C, 0xF3, 0xEC, 0xD3, 0x1C, 0x2E, 0x96, 0xEF, 0xBF, 0xAB, 0x7E, 0x32, 0x7D, 0xE2,
00176    0x10, 0xCE,
00177    0x88, 0xF4, 0x69, 0x2B, 0x60, 0xFC, 0xF4, 0xF5, 0x97, 0x78, 0x8A, 0x36, 0xD8, 0x44,
00178    0x86, 0x18,
00179    0x0D, 0xD7, 0x29, 0x95, 0x13, 0xD8, 0xD9, 0x58, 0xE1, 0x0E, 0xF8, 0xF1, 0xF3, 0xDB,
00180    0xC6, 0xD6,
00181    0xEC, 0x5F, 0x53, 0x8E, 0xBF, 0xFE, 0xC3, 0x70, 0x93, 0x8D, 0x6D, 0xDA, 0xCB, 0x0B,
00182    0x4C, 0x3F,
00183    0xFF, 0xFC, 0xFA, 0xCF, 0x0C, 0xB4, 0x09, 0x84, 0x54, 0xD5, 0x74, 0x91, 0x55, 0x03,
00184    0x01, 0x07,
00185    0x3B, 0x97, 0x96, 0x6E, 0xC8, 0x17, 0xFE, 0x7F, 0x4F, 0xF8, 0xFE, 0xBC, 0x95, 0x16,
00186    0x60, 0x62,
00187    0x62, 0x64, 0xE1, 0xE6, 0x60, 0x73, 0xD1, 0xB2, 0x7A, 0xFA, 0xE2, 0xF1, 0xDF, 0x3F,
00188    0xFF, 0xC4,
00189    0x78, 0x44, 0x31, 0xA3, 0x45, 0x2B, 0xD0, 0xE3, 0xF6, 0xD9, 0xE3, 0x2F, 0x2E, 0x9D,
00190    0x29, 0xA9,
00191    0xAC, 0x07, 0xA6, 0x03, 0xF4, 0xB4, 0x44, 0x10, 0x00, 0x00, 0x75, 0x65, 0x12, 0xB0,
00192    0x49, 0xFF,
00193    0x3F, 0x68, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
00194 };
00195 
00196 const unsigned char favicon_ico[] = {
00197    0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x01, 0x00, 0x04, 0x00,
00198    0x28, 0x01,
00199    0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
00200    0x20, 0x00,
00201    0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
00202    0x00, 0x00,
00203    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00204    0xB4, 0x0F,
00205    0x0A, 0x00, 0x5C, 0x86, 0x4C, 0x00, 0x2F, 0x5E, 0x1A, 0x00, 0xBF, 0xD3, 0xD7, 0x00,
00206    0x29, 0x17,
00207    0x8D, 0x00, 0x50, 0xA7, 0xA4, 0x00, 0x59, 0x57, 0x7F, 0x00, 0xC6, 0xA3, 0xAC, 0x00,
00208    0xFC, 0xFE,
00209    0xFC, 0x00, 0x28, 0x12, 0x53, 0x00, 0x58, 0x7D, 0x72, 0x00, 0xC4, 0x3A, 0x34, 0x00,
00210    0x3C, 0x3D,
00211    0x69, 0x00, 0xC5, 0xB6, 0xB9, 0x00, 0x94, 0x92, 0x87, 0x00, 0x7E, 0x7A, 0xAA, 0x00,
00212    0x88, 0x88,
00213    0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x81, 0x22, 0xD8, 0x88, 0x88, 0x88, 0xF6, 0xD8,
00214    0x82, 0x22,
00215    0xE8, 0x88, 0x88, 0x8D, 0x44, 0x98, 0x82, 0x22, 0xA8, 0x88, 0x88, 0x8F, 0x44, 0x48,
00216    0x82, 0x22,
00217    0x25, 0x76, 0x67, 0x55, 0x44, 0xF8, 0x88, 0x88, 0x3A, 0xC9, 0x9C, 0x53, 0x83, 0x88,
00218    0x88, 0x88,
00219    0x8D, 0x99, 0x99, 0x38, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x9C, 0x88, 0x88, 0x88,
00220    0x88, 0x88,
00221    0x88, 0xF9, 0x9D, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8A, 0x58, 0x88, 0x88, 0x88,
00222    0x88, 0x88,
00223    0x88, 0x85, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xEA, 0xAE, 0x88, 0x88, 0x88,
00224    0x88, 0x88,
00225    0x88, 0x00, 0x0B, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x0D, 0x88, 0x88, 0x88,
00226    0x88, 0x88,
00227    0x88, 0x87, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
00228    0x00, 0x00,
00229    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00230    0x00, 0x00,
00231    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00232    0x00, 0x00,
00233    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00234    0x00, 0x00,
00235    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00236 };
00237 
00238 const unsigned char reload_png[] = {
00239 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,
00240 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x08,0x06,0x00,0x00,0x00,0x73,0x7A,0x7A,
00241 0xF4,0x00,0x00,0x00,0x07,0x74,0x49,0x4D,0x45,0x07,0xD9,0x0C,0x0B,0x0B,0x00,0x2D,
00242 0xA2,0x9E,0x3E,0xD3,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0B,0x13,
00243 0x00,0x00,0x0B,0x13,0x01,0x00,0x9A,0x9C,0x18,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,
00244 0x41,0x00,0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x08,0x37,0x49,0x44,0x41,
00245 0x54,0x78,0xDA,0xC5,0x57,0x7B,0x8C,0x54,0xD5,0x19,0xFF,0xDD,0xE7,0xDC,0x99,0xD9,
00246 0x9D,0x9D,0x19,0x16,0x76,0x61,0x59,0xD8,0x5D,0x97,0x5D,0xCA,0xAE,0xF2,0xD8,0x15,
00247 0x2D,0xD0,0x08,0x0D,0x0A,0x26,0xAD,0x8D,0x0F,0xA0,0x2A,0x49,0x63,0x83,0x86,0xBA,
00248 0xA9,0xD2,0x6A,0x52,0x4D,0xF8,0xD7,0x98,0xDA,0xC6,0x34,0x4D,0xAB,0x49,0xD3,0x98,
00249 0xC6,0xB2,0x92,0xC6,0x0A,0x12,0x35,0x51,0x8B,0xA5,0x8D,0x46,0x14,0x44,0xAA,0x3C,
00250 0x0A,0xD8,0x65,0x81,0x65,0x76,0xD9,0xE7,0xBC,0xEF,0xCC,0x7D,0xF7,0x3B,0xE7,0xCE,
00251 0x63,0x77,0x0B,0x5A,0x9A,0x26,0x9E,0xE4,0x9B,0x3B,0xF7,0x9C,0xEF,0xF1,0x3B,0xDF,
00252 0xF7,0x9D,0xEF,0x7C,0x17,0xF8,0x9A,0x87,0x70,0x1D,0xBC,0x12,0xD1,0x1A,0xA2,0xCD,
00253 0x44,0xAB,0x05,0x11,0x9D,0x5A,0x08,0xF3,0x54,0x0D,0xAA,0x59,0x84,0x59,0xD4,0x31,
00254 0xE6,0xB9,0x38,0x47,0x6B,0x47,0x88,0xDE,0x26,0xFA,0x90,0xC8,0xFE,0x7F,0x00,0x08,
00255 0x13,0xED,0x24,0xCE,0xBE,0xE6,0xE5,0x4A,0x6B,0xD7,0x7A,0x19,0x5D,0xB7,0x0A,0x58,
00256 0xDA,0xED,0x62,0xC1,0x7C,0x1B,0xD1,0x5A,0x1B,0xD9,0xBC,0x84,0xE1,0x2B,0x32,0xCE,
00257 0x9E,0x14,0x71,0xE2,0xB0,0x87,0x93,0x7F,0xB3,0x71,0xE9,0xB8,0x7D,0x01,0x1E,0x5E,
00258 0x20,0xD9,0x17,0x89,0x72,0xFF,0x2B,0x80,0x7B,0x05,0x09,0xBF,0x6A,0xD9,0x10,0x5E,
00259 0xD8,0xB3,0x25,0x8C,0xE6,0x76,0x20,0x56,0x63,0x61,0x5E,0xCC,0xA4,0xA7,0x83,0x90,
00260 0xE6,0x40,0x51,0x3C,0x14,0x4D,0x11,0xB9,0x82,0x84,0x0C,0x01,0x49,0x66,0x65,0xA4,
00261 0x72,0x0A,0x86,0x06,0x80,0x4F,0xFE,0xA4,0x63,0xE0,0xBD,0x7C,0xC2,0x73,0xF0,0x13,
00262 0xD2,0xF5,0xEA,0xB5,0xDC,0x7A,0xB5,0xA1,0x10,0xFD,0x36,0xDC,0xAC,0xFE,0x7C,0xE5,
00263 0xAE,0xC6,0xBA,0x25,0x1B,0x43,0xE8,0x6C,0xB7,0xD0,0xDD,0x9A,0x47,0x7B,0x53,0x11,
00264 0x91,0xB0,0x03,0x41,0x14,0x60,0xB8,0x64,0xB8,0x28,0x21,0x6F,0xCA,0x30,0x1C,0x11,
00265 0x0E,0xC5,0x45,0x94,0x7D,0xAD,0x9E,0x2A,0x23,0xB2,0x34,0x8C,0xE8,0x4D,0x35,0x91,
00266 0xE4,0x80,0x71,0x9F,0x99,0x76,0x16,0xD0,0xCA,0xBB,0x44,0xCE,0x57,0x01,0x08,0x10,
00267 0xBD,0x56,0xB7,0x2A,0xF2,0x40,0xC7,0x23,0x0B,0x84,0xEE,0x2E,0x13,0x77,0xAF,0x9B,
00268 0xC0,0x8D,0x6D,0x79,0xDA,0xB1,0x0B,0xC7,0x15,0x60,0x39,0x44,0x64,0xDC,0xB2,0x05,
00269 0x98,0x64,0x98,0xBF,0xD3,0xD3,0xE4,0xF3,0x02,0x3C,0x02,0xA7,0x85,0x3C,0x4E,0x96,
00270 0xAC,0x20,0xD8,0x1D,0x17,0xF2,0x93,0x4E,0x4F,0x71,0xD8,0xE8,0x21,0xDD,0xFB,0xA6,
00271 0xE7,0xC6,0x6C,0x00,0x2C,0x24,0x7B,0x6A,0x7A,0x62,0xF7,0x34,0x6F,0x6D,0xC4,0xB6,
00272 0x0D,0xE3,0xF8,0xDE,0xDA,0x49,0x68,0xAA,0xCB,0x0D,0x94,0x0D,0x31,0x32,0xC8,0xB8,
00273 0x61,0xF9,0x20,0xEC,0xF2,0x3C,0x07,0x25,0x72,0x10,0xEC,0xDD,0x23,0x75,0x35,0x11,
00274 0xFA,0x25,0xAF,0x98,0xF3,0x63,0x28,0xA4,0x9C,0x25,0xE6,0x70,0xB1,0x83,0x6D,0xF0,
00275 0x5A,0x00,0x1E,0x53,0x5A,0xC2,0x4F,0x34,0xDD,0xDF,0x24,0x3C,0xB9,0x75,0x08,0xBD,
00276 0x9D,0xB9,0xAA,0x72,0x7A,0xEA,0x86,0x84,0x34,0xC5,0x38,0x93,0x95,0x50,0xA0,0x98,
00277 0x5B,0x14,0x7B,0x87,0x00,0x78,0xB4,0x26,0xBA,0xA4,0xCC,0xF3,0xB8,0x12,0x93,0x03,
00278 0x14,0x2B,0xDE,0x51,0x35,0x0F,0xA1,0xB0,0x87,0x4C,0x34,0x86,0xFC,0x85,0xC2,0x32,
00279 0x27,0x65,0xA5,0x88,0xED,0xE3,0xD9,0x00,0x9A,0xA1,0x8A,0xFB,0xA2,0x0F,0xB4,0x05,
00280 0x76,0x3F,0x74,0x19,0x5D,0xAD,0xBA,0xBF,0x1B,0x52,0x52,0x20,0x43,0x57,0xA6,0x02,
00281 0x48,0x66,0x64,0x98,0xB4,0x6B,0xD7,0x13,0xF8,0xEE,0x98,0xB9,0xE9,0xE4,0x2B,0x24,
00282 0xD7,0x13,0x1A,0x49,0xF0,0x90,0xB3,0x28,0x37,0x6C,0x89,0xEB,0x10,0x64,0x81,0x83,
00283 0x98,0x0C,0xC5,0x05,0xFD,0x1F,0x53,0xEB,0xE0,0x78,0x7B,0x88,0x3D,0x33,0x1D,0xC0,
00284 0x73,0xCA,0x37,0x1B,0xD7,0x3C,0xBC,0x53,0xC7,0xFA,0xE5,0xA9,0x8A,0xBB,0xD3,0xBA,
00285 0x8C,0xA1,0xB1,0x00,0x77,0xB7,0x6F,0x94,0x91,0x84,0xB9,0xC1,0x15,0x58,0x1C,0xDE,
00286 0x88,0x05,0xE1,0x6F,0x21,0xA6,0x76,0xC2,0xA3,0xE3,0x92,0xB3,0xC6,0x4B,0x60,0x04,
00287 0xC8,0xA2,0x87,0x5A,0xC5,0x46,0xDE,0xA2,0x79,0xD3,0x07,0x21,0x52,0x6A,0x0B,0xAA,
00288 0x84,0xC9,0xA4,0xA2,0x3A,0x17,0x73,0x21,0x62,0x7D,0x53,0x2E,0x19,0x8F,0x41,0x11,
00289 0xB7,0x77,0x6C,0x0E,0x53,0xC2,0x9D,0xAF,0x18,0x4F,0xE6,0xC8,0xF8,0x78,0x80,0x2B,
00290 0xF4,0x13,0x44,0xC2,0xF2,0xF8,0x0F,0xB0,0xBA,0xFE,0x31,0x44,0xD4,0x45,0x10,0x84,
00291 0xEA,0x29,0xF6,0xC8,0xFD,0x19,0xF3,0x12,0x8E,0x4C,0xFC,0x1A,0x9F,0x4D,0xFD,0x81,
00292 0x64,0x5C,0x3E,0xDF,0x54,0x53,0x44,0x91,0xC0,0x4F,0x18,0x3E,0x88,0x39,0x0D,0x54,
00293 0x3B,0xD6,0xC6,0x30,0x76,0x78,0x74,0x3B,0x25,0xCB,0x53,0x65,0x0F,0xDC,0x87,0x25,
00294 0xD1,0x6D,0x3F,0xDB,0x9D,0x47,0x63,0xDC,0xE2,0x8C,0x79,0x12,0x18,0x18,0x0D,0x91,
00295 0xA7,0xC8,0xE5,0x7C,0x47,0xB5,0xB8,0xB7,0xA5,0x1F,0x3D,0xF5,0x3B,0xA1,0xC9,0xD1,
00296 0x19,0xC6,0x39,0x38,0x7A,0x67,0xF3,0x37,0x44,0x36,0x61,0x7E,0xE8,0x66,0x9C,0x49,
00297 0xBF,0x0D,0xCB,0xB3,0x38,0xF8,0x48,0xC0,0xC6,0x68,0x2E,0x80,0x82,0xE5,0x87,0x54,
00298 0xD6,0x04,0x8C,0x9D,0xB1,0x55,0x4C,0x16,0x4F,0x94,0x01,0xFC,0xB8,0xF9,0xF6,0xE8,
00299 0xAA,0x9D,0x0F,0xA5,0x60,0xBB,0x02,0x3F,0x4E,0xE7,0xC7,0x82,0xD0,0xC9,0x75,0x3C,
00300 0xDE,0x9E,0x84,0x2D,0x64,0xBC,0x2D,0xF2,0xED,0xD2,0x6E,0x5D,0x5C,0xCC,0x1E,0xC2,
00301 0xB1,0xF1,0x17,0x71,0x62,0xEA,0x8F,0x48,0xE4,0x0E,0x43,0x24,0xEF,0xD4,0xA9,0x8B,
00302 0x39,0x90,0x58,0xA0,0x15,0x0D,0xDA,0x0A,0xF2,0xC4,0x6B,0xB4,0x01,0x3F,0x24,0xAA,
00303 0xEC,0x62,0x38,0xA3,0x71,0xEF,0x0A,0x14,0x8A,0xE4,0x08,0x79,0xF9,0x5C,0x26,0x59,
00304 0x0E,0xC1,0x8D,0x6B,0x6E,0xB3,0xB8,0x71,0xC6,0x90,0xD6,0x15,0x4C,0xE6,0x95,0x4A,
00305 0xA1,0xEC,0x99,0xF3,0x20,0xDA,0x6A,0xD7,0x97,0x32,0x3C,0x87,0xFD,0x83,0x3B,0xF0,
00306 0xCF,0xCC,0x41,0xAA,0x28,0x7E,0x4E,0xB0,0xDF,0xF7,0xC7,0x5E,0xC2,0x37,0x22,0x1B,
00307 0x71,0x77,0xEB,0xEF,0xA1,0x4A,0x35,0x9C,0xBF,0x3B,0xF6,0x20,0x8E,0x4D,0xF6,0x73,
00308 0xB9,0x10,0x1D,0x65,0x4D,0x76,0xA8,0x68,0xA9,0xDC,0x46,0xCD,0x0D,0x01,0xE8,0xC0,
00309 0x2A,0xB1,0x7C,0x02,0x96,0x2D,0x35,0x2B,0xB1,0xBF,0x92,0x51,0x61,0xBA,0x12,0x91,
00310 0xC8,0xE9,0xD6,0xB9,0x3B,0xF8,0xCE,0x58,0x9C,0x0F,0x5C,0x78,0x02,0xC7,0x52,0x87,
00311 0xA0,0xBB,0x94,0xE1,0x25,0x1E,0xF6,0x64,0xEF,0x6C,0x9E,0xAD,0x33,0x3E,0xC6,0xCF,
00312 0xE4,0xCA,0x3A,0x2C,0x0A,0x65,0x34,0x64,0xFB,0x36,0xE8,0xE8,0xAA,0xF5,0x7C,0xEF,
00313 0x8B,0xCB,0x00,0xEA,0x1B,0xEA,0xED,0xCA,0x79,0x9F,0x2C,0x28,0x15,0x41,0x45,0xAC,
00314 0x47,0x43,0x70,0x29,0x67,0x4A,0x9B,0x09,0x1C,0x9E,0x78,0x73,0x06,0xB8,0x99,0x24,
00315 0xF1,0x75,0xC6,0xC7,0x06,0x93,0x63,0xF2,0xE5,0xF5,0x60,0xC0,0x85,0x59,0xAA,0x0F,
00316 0xAA,0xC6,0xBD,0x1B,0x95,0x4B,0xE9,0xAD,0x28,0x8A,0xEB,0x97,0x52,0x62,0xC8,0x18,
00317 0x32,0x4F,0x3E,0x36,0xEA,0xC4,0x38,0x44,0xC1,0x4F,0x95,0x11,0xFD,0x5F,0x28,0x50,
00318 0x4E,0xC0,0xFB,0xF2,0x3B,0x6C,0xB4,0x70,0x01,0xD1,0xC0,0x42,0x2E,0xC7,0x00,0x18,
00319 0x6E,0x8A,0xCF,0x8B,0xA4,0xC6,0xF7,0x32,0xE5,0x19,0x65,0x0D,0xD9,0x15,0x7D,0x00,
00320 0x1E,0x4C,0xC3,0x40,0x40,0xB5,0xFD,0x7A,0x5E,0x70,0xA8,0x9C,0x94,0x8C,0x24,0x72,
00321 0x97,0xF0,0xE9,0x95,0x37,0xD0,0x16,0xED,0xC5,0xA1,0xCB,0x2F,0xF3,0x4B,0xA7,0x5A,
00322 0xB7,0x45,0x3A,0xEB,0x71,0x64,0xAC,0x89,0x19,0x00,0xA2,0x81,0xA6,0x4A,0xB2,0xA6,
00323 0x8D,0x4C,0x45,0xC6,0x71,0x51,0xBD,0x37,0x4C,0x9E,0x9D,0xD9,0x72,0x12,0x8E,0x4C,
00324 0x8E,0x0A,0x2D,0x81,0xB8,0xBF,0xC8,0x76,0xCF,0x5C,0x56,0x1E,0xCF,0x9F,0xEE,0x83,
00325 0x48,0xE9,0xEC,0x50,0x11,0xF1,0x44,0xDF,0x1B,0xAA,0xA8,0xE1,0xE9,0xEE,0x97,0xD1,
00326 0x11,0xE9,0xC5,0x5B,0x97,0x7F,0x87,0x57,0x06,0x9F,0x65,0x67,0x11,0x2B,0x62,0xB7,
00327 0x61,0x9E,0xD6,0xE2,0x7B,0x22,0x7F,0x01,0xA3,0x46,0x92,0xE6,0x7D,0x19,0xD3,0xAA,
00328 0x96,0x75,0x33,0xC5,0xEF,0xA3,0xCB,0x65,0x00,0x47,0x07,0x4F,0x7A,0x2D,0x73,0x3B,
00329 0xFC,0x45,0x91,0xAA,0x18,0x2B,0x1E,0x95,0x21,0xD2,0x7F,0xB1,0x54,0x6F,0x1D,0xF0,
00330 0xBC,0xEF,0xEB,0xF8,0x05,0x3A,0xEB,0x6E,0xE6,0xCB,0x1D,0xB5,0xAB,0xC9,0x6B,0x22,
00331 0xDA,0x6B,0x6F,0xC2,0x23,0x1D,0xBF,0xAC,0xD4,0x88,0x77,0x2E,0xF5,0xA3,0x38,0x6D,
00332 0x23,0x69,0x5D,0xF2,0xC3,0xCC,0xEE,0x8A,0xA1,0x22,0x9B,0xFA,0xA4,0xBC,0x7A,0xE0,
00333 0xC4,0xDF,0x9D,0x8A,0x7B,0xC2,0x8A,0x83,0x22,0x85,0xE1,0x6A,0xC4,0x0C,0xDD,0xB3,
00334 0xE8,0x71,0xAC,0x6D,0xF8,0x4E,0xA5,0x02,0x9E,0x19,0x3F,0x8E,0x47,0x3B,0x9F,0xC3,
00335 0xB3,0xAB,0x5E,0x45,0x54,0xAD,0xE7,0xF3,0xE7,0x26,0x3E,0xC3,0xBE,0xA1,0xBD,0x33,
00336 0x64,0xC7,0xD2,0x6A,0xF5,0x56,0x3D,0x9B,0x61,0x6C,0xEF,0x96,0x3D,0xF0,0xD6,0xE7,
00337 0x07,0xED,0x7C,0x26,0x25,0x84,0xA5,0xA0,0x80,0xB8,0x6A,0xE2,0xB4,0x53,0xCB,0x2B,
00338 0xE0,0xEC,0xB1,0xA1,0x61,0x33,0xEE,0x6F,0xED,0x9B,0x51,0x01,0xEF,0x5A,0xF2,0xC3,
00339 0x19,0x3C,0x5F,0x4C,0x9C,0xC2,0xD3,0x1F,0xFD,0x08,0x19,0x95,0x5C,0xE6,0xF8,0xEE,
00340 0x77,0x29,0xFE,0xA3,0x49,0xBF,0x06,0x98,0x79,0x0A,0xE7,0xA9,0x54,0x9E,0xD9,0x2D,
00341 0x7B,0x20,0x65,0xE4,0xB1,0xE7,0xFD,0x7E,0xBF,0x16,0x30,0x57,0xCF,0xD3,0x0C,0xE8,
00342 0xB6,0xC4,0x13,0xB2,0x4C,0x3A,0x25,0xE9,0xD6,0x96,0x1D,0x94,0xDD,0x22,0xAE,0x36,
00343 0xB2,0x46,0x16,0x2F,0x1D,0x7D,0x01,0x3B,0x0E,0x6D,0x47,0x42,0x4C,0xCF,0x90,0x4D,
00344 0x8C,0xAB,0xFC,0x56,0x65,0xC7,0xD0,0xFA,0x70,0x0C,0x74,0x34,0xD8,0x6D,0x98,0x9A,
00345 0x7E,0x1B,0x7E,0x3E,0x74,0xC2,0x7E,0xB8,0xFB,0xBB,0x41,0x55,0x0C,0x48,0x08,0x49,
00346 0x36,0x46,0x0A,0x1A,0x72,0xB6,0xEC,0x37,0x1A,0x44,0x36,0x25,0xA7,0x48,0xBD,0xC0,
00347 0x9A,0x85,0x6B,0x66,0x80,0x18,0x4E,0x27,0xB0,0xFB,0x2F,0xBB,0xF1,0xCC,0xD1,0x67,
00348 0xF0,0x41,0xE1,0x23,0x14,0xA9,0xA7,0x62,0x85,0xA7,0x2C,0x97,0xD3,0xA9,0xB8,0x8D,
00349 0x28,0xBE,0xF1,0xA4,0x0D,0x6F,0xEF,0x40,0x96,0x32,0xFD,0xFB,0x98,0x75,0x1D,0xA7,
00350 0x1D,0x13,0xFA,0x95,0xB3,0xF6,0xA6,0x8E,0xDB,0x83,0x02,0x33,0x56,0x27,0xDB,0x18,
00351 0x2E,0x6A,0xD0,0x1D,0xD9,0x57,0x48,0x74,0x3C,0x79,0x1A,0x1F,0x9C,0x3A,0x8C,0xDE,
00352 0xC6,0x55,0x88,0x87,0xA2,0x5C,0xB0,0x56,0x8B,0x60,0x10,0x09,0xFC,0x35,0x7B,0x04,
00353 0x16,0x9D,0x92,0x32,0x2F,0xA3,0x42,0x51,0xC4,0xF8,0xB0,0xDF,0x47,0x58,0x16,0x39,
00354 0xF7,0x95,0x2F,0x3C,0x8C,0x17,0x9F,0x24,0xB1,0x83,0x4C,0x76,0x76,0x47,0x74,0x24,
00355 0x95,0x70,0x97,0xE5,0xA6,0xDC,0xAE,0xA6,0x5B,0x82,0xFC,0x22,0x8A,0x4B,0x26,0x92,
00356 0x96,0x8A,0xB4,0xAD,0xF8,0x5E,0xA0,0x13,0x31,0x24,0x8C,0xA3,0xFF,0xD8,0xEB,0x08,
00357 0x9A,0x21,0xAC,0x6C,0xEA,0x22,0x6F,0x08,0xF8,0x74,0xF4,0x0C,0x0E,0x8E,0x7D,0x5C,
00358 0xD9,0x35,0x4B,0xB6,0xA2,0x2E,0x20,0x33,0x2A,0xF8,0xC6,0x59,0xE7,0x74,0xE0,0x22,
00359 0x70,0x72,0x6A,0x2F,0xD9,0x79,0xAA,0x5A,0x4B,0xFE,0x73,0x68,0x44,0xFB,0x96,0xDC,
00360 0x19,0xBA,0xF3,0x96,0x5D,0x71,0xDE,0xE9,0xB2,0xBC,0x18,0x36,0x82,0x18,0x34,0xC2,
00361 0xC8,0xBB,0x4A,0x85,0xD1,0xCD,0xBB,0x58,0x69,0x77,0x51,0x2D,0x58,0x8C,0x03,0xD9,
00362 0xF7,0x60,0x46,0x2C,0x5F,0xA9,0x4D,0xE9,0x9B,0xA5,0x3E,0x52,0x2F,0x15,0x1E,0x83,
00363 0x76,0xBE,0x7F,0x10,0x38,0x3E,0xF1,0x06,0x2D,0x6F,0x21,0x32,0xBE,0x0C,0x00,0xAF,
00364 0x33,0x44,0xBF,0x89,0x77,0xAA,0x3B,0x7A,0x7F,0x5A,0x2F,0x68,0x4D,0x81,0x6A,0x93,
00365 0x42,0xD7,0xF8,0x04,0x51,0x96,0x80,0x14,0x4B,0xBD,0x82,0x50,0xEA,0x07,0x25,0x32,
00366 0x2C,0x99,0x0E,0x5C,0xA3,0x5A,0xF1,0xAC,0xE1,0x22,0xBC,0x3F,0x9F,0xF7,0x90,0xC8,
00367 0xB3,0x0F,0x94,0x5D,0x44,0xD6,0x74,0x43,0x5F,0xF5,0x61,0xB2,0x8D,0x3A,0xDA,0xE7,
00368 0x9B,0xEF,0x88,0x2C,0x68,0xBE,0x2B,0x06,0x79,0x8E,0x5A,0x6D,0xBF,0x1D,0xDF,0xAD,
00369 0x33,0x5A,0xF2,0xE9,0x2D,0xFA,0x38,0x9D,0xA8,0x43,0x23,0x54,0x6A,0x26,0x86,0x28,
00370 0x96,0x8F,0x93,0xAE,0xFD,0x57,0x33,0xF0,0xDF,0x7C,0x9A,0xD5,0x10,0xF5,0x11,0xE7,
00371 0xA3,0x75,0x5D,0xC1,0x45,0x91,0x15,0xB5,0xD0,0xDA,0xC3,0x10,0xE7,0x06,0xE0,0x28,
00372 0x72,0xF5,0xFB,0x40,0xF7,0x60,0x8C,0x18,0x30,0x06,0xF2,0xB0,0x4E,0xA5,0xE1,0x9D,
00373 0xCF,0x9E,0x9F,0xF6,0x69,0xA6,0x5F,0x4B,0xF9,0xF5,0x7C,0x9C,0xB2,0xA2,0xB5,0x8E,
00374 0x68,0x13,0xD1,0x6A,0x92,0xEC,0x10,0x02,0xC2,0x3C,0x41,0x16,0x15,0xD7,0x72,0x4D,
00375 0x98,0xDE,0x18,0x19,0x3C,0x0B,0xBF,0xDD,0x7E,0x07,0xFE,0xC7,0xA9,0x73,0x1D,0xFA,
00376 0xBF,0x9E,0xF1,0x6F,0x1F,0xE9,0x4A,0x5D,0x98,0x0E,0x02,0x3D,0x00,0x00,0x00,0x00,
00377 0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
00378 };
00379 
00380 /*------------------------------------------------------------------*/
00381 
00382 void show_hist_page(const char *path, int path_size, char *buffer, int *buffer_size,
00383                     int refresh);
00384 int vaxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
00385           int minor, int major, int text, int label, int grid, double ymin, double ymax,
00386           BOOL logaxis);
00387 void haxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
00388            int minor, int major, int text, int label, int grid, double xmin, double xmax);
00389 void get_elog_url(char *url, int len);
00390 
00391 /*------------------------------------------------------------------*/
00392 
00393 char *stristr(const char *str, const char *pattern)
00394 {
00395    char c1, c2, *ps, *pp;
00396 
00397    if (str == NULL || pattern == NULL)
00398       return NULL;
00399 
00400    while (*str) {
00401       ps = (char *) str;
00402       pp = (char *) pattern;
00403       c1 = *ps;
00404       c2 = *pp;
00405       if (toupper(c1) == toupper(c2)) {
00406          while (*pp) {
00407             c1 = *ps;
00408             c2 = *pp;
00409 
00410             if (toupper(c1) != toupper(c2))
00411                break;
00412 
00413             ps++;
00414             pp++;
00415          }
00416 
00417          if (!*pp)
00418             return (char *) str;
00419       }
00420       str++;
00421    }
00422 
00423    return NULL;
00424 }
00425 
00426 /*------------------------------------------------------------------*/
00427 
00428 void rsputs(const char *str)
00429 {
00430    if (strlen_retbuf + strlen(str) > sizeof(return_buffer)-40) {
00431       strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
00432       strlen_retbuf = strlen(return_buffer);
00433    } else {
00434       strcpy(return_buffer + strlen_retbuf, str);
00435       strlen_retbuf += strlen(str);
00436    }
00437 }
00438 
00439 /*------------------------------------------------------------------*/
00440 
00441 void rsputs2(const char *str)
00442 {
00443    int i, j, k;
00444    char *p, link[256];
00445 
00446    if (strlen_retbuf + strlen(str) > sizeof(return_buffer)) {
00447       strlcpy(return_buffer, "<H1>Error: return buffer too small</H1>",
00448               sizeof(return_buffer));
00449       strlen_retbuf = strlen(return_buffer);
00450    } else {
00451       j = strlen_retbuf;
00452       for (i = 0; i < (int) strlen(str); i++) {
00453          if (strncmp(str + i, "http://", 7) == 0) {
00454             p = (char *) (str + i + 7);
00455             i += 7;
00456             for (k = 0; *p && *p != ' ' && *p != '\n'; k++, i++)
00457                link[k] = *p++;
00458             link[k] = 0;
00459 
00460             sprintf(return_buffer + j, "<a href=\"http://%s\">http://%s</a>", link, link);
00461             j += strlen(return_buffer + j);
00462          } else
00463             switch (str[i]) {
00464             case '<':
00465                strlcat(return_buffer, "&lt;", sizeof(return_buffer));
00466                j += 4;
00467                break;
00468             case '>':
00469                strlcat(return_buffer, "&gt;", sizeof(return_buffer));
00470                j += 4;
00471                break;
00472             default:
00473                return_buffer[j++] = str[i];
00474             }
00475       }
00476 
00477       return_buffer[j] = 0;
00478       strlen_retbuf = j;
00479    }
00480 }
00481 
00482 /*------------------------------------------------------------------*/
00483 
00484 void rsprintf(const char *format, ...)
00485 {
00486    va_list argptr;
00487    char str[10000];
00488 
00489    va_start(argptr, format);
00490    vsprintf(str, (char *) format, argptr);
00491    va_end(argptr);
00492 
00493    if (strlen_retbuf + strlen(str) > sizeof(return_buffer))
00494       strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
00495    else
00496       strcpy(return_buffer + strlen_retbuf, str);
00497 
00498    strlen_retbuf += strlen(str);
00499 }
00500 
00501 /*------------------------------------------------------------------*/
00502 
00503 /* Parameter handling functions similar to setenv/getenv */
00504 
00505 void initparam()
00506 {
00507    memset(_param, 0, sizeof(_param));
00508    memset(_value, 0, sizeof(_value));
00509    _text[0] = 0;
00510 }
00511 
00512 void setparam(const char *param, const char *value)
00513 {
00514    int i;
00515 
00516    if (equal_ustring(param, "text")) {
00517       if (strlen(value) >= TEXT_SIZE)
00518          printf("Error: parameter value too big\n");
00519 
00520       strlcpy(_text, value, TEXT_SIZE);
00521       _text[TEXT_SIZE - 1] = 0;
00522       return;
00523    }
00524 
00525    for (i = 0; i < MAX_PARAM; i++)
00526       if (_param[i][0] == 0)
00527          break;
00528 
00529    if (i < MAX_PARAM) {
00530       strlcpy(_param[i], param, PARAM_LENGTH);
00531 
00532       _value[i] = (char*)malloc(strlen(value)+1);
00533       strlcpy(_value[i], value, strlen(value)+1);
00534       _value[i][strlen(value)] = 0;
00535 
00536    } else {
00537       printf("Error: parameter array too small\n");
00538    }
00539 }
00540 
00541 void freeparam()
00542 {
00543    int i;
00544 
00545    for (i=0 ; i<MAX_PARAM ; i++)
00546       if (_value[i] != NULL) {
00547          free(_value[i]);
00548          _value[i] = NULL;
00549       }
00550 }
00551 
00552 const char *getparam(const char *param)
00553 {
00554    int i;
00555 
00556    if (equal_ustring(param, "text"))
00557       return _text;
00558 
00559    for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
00560       if (equal_ustring(param, _param[i]))
00561          break;
00562 
00563    if (i == MAX_PARAM)
00564       return NULL;
00565 
00566    if (_value[i] == NULL)
00567       return "";
00568       
00569    return _value[i];
00570 }
00571 
00572 BOOL isparam(const char *param)
00573 {
00574    int i;
00575 
00576    for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
00577       if (equal_ustring(param, _param[i]))
00578          break;
00579 
00580    if (i < MAX_PARAM && _param[i][0])
00581       return TRUE;
00582 
00583    return FALSE;
00584 }
00585 
00586 void unsetparam(const char *param)
00587 {
00588    int i;
00589 
00590    for (i = 0; i < MAX_PARAM; i++)
00591       if (equal_ustring(param, _param[i]))
00592          break;
00593 
00594    if (i < MAX_PARAM) {
00595       _param[i][0] = 0;
00596       _value[i][0] = 0;
00597    }
00598 }
00599 
00600 /*------------------------------------------------------------------*/
00601 
00602 int mhttpd_revision()
00603 {
00604    return atoi(mhttpd_svn_revision+6);
00605 }
00606 
00607 /*------------------------------------------------------------------*/
00608 
00609 void urlDecode(char *p)
00610 /********************************************************************\
00611    Decode the given string in-place by expanding %XX escapes
00612 \********************************************************************/
00613 {
00614    char *pD, str[3];
00615    int i;
00616 
00617    pD = p;
00618    while (*p) {
00619       if (*p == '%') {
00620          /* Escape: next 2 chars are hex representation of the actual character */
00621          p++;
00622          if (isxdigit(p[0]) && isxdigit(p[1])) {
00623             str[0] = p[0];
00624             str[1] = p[1];
00625             str[2] = 0;
00626             sscanf(p, "%02X", &i);
00627 
00628             *pD++ = (char) i;
00629             p += 2;
00630          } else
00631             *pD++ = '%';
00632       } else if (*p == '+') {
00633          /* convert '+' to ' ' */
00634          *pD++ = ' ';
00635          p++;
00636       } else {
00637          *pD++ = *p++;
00638       }
00639    }
00640    *pD = '\0';
00641 }
00642 
00643 void urlEncode(char *ps, int ps_size)
00644 /********************************************************************\
00645    Encode the given string in-place by adding %XX escapes
00646 \********************************************************************/
00647 {
00648    char *pd, *p, str[256];
00649 
00650    pd = str;
00651    p = ps;
00652    while (*p) {
00653       if (strchr(" %&=+#\"'", *p)) {
00654          sprintf(pd, "%%%02X", *p);
00655          pd += 3;
00656          p++;
00657       } else {
00658          *pd++ = *p++;
00659       }
00660    }
00661    *pd = '\0';
00662    assert(pd - str < (int)sizeof(str));
00663    strlcpy(ps, str, ps_size);
00664 }
00665 
00666 /*------------------------------------------------------------------*/
00667 
00668 char message_buffer[256] = "";
00669 
00670 INT print_message(const char *message)
00671 {
00672    strlcpy(message_buffer, message, sizeof(message_buffer));
00673    return SUCCESS;
00674 }
00675 
00676 void receive_message(HNDLE hBuf, HNDLE id, EVENT_HEADER * pheader, void *message)
00677 {
00678    time_t tm;
00679    char str[80], line[256];
00680 
00681    /* prepare time */
00682    time(&tm);
00683    strcpy(str, ctime(&tm));
00684    str[19] = 0;
00685 
00686    /* print message text which comes after event header */
00687    strlcpy(line, str + 11, sizeof(line));
00688    strlcat(line, (char *) message, sizeof(line));
00689    print_message(line);
00690 }
00691 
00692 /*-------------------------------------------------------------------*/
00693 
00694 INT sendmail(const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
00695 {
00696    struct sockaddr_in bind_addr;
00697    struct hostent *phe;
00698    int i, s, strsize, offset;
00699    char *str, buf[256];
00700    time_t now;
00701    struct tm *ts;
00702 
00703    if (verbose)
00704       printf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
00705 
00706    /* create a new socket for connecting to remote server */
00707    s = socket(AF_INET, SOCK_STREAM, 0);
00708    if (s == -1)
00709       return -1;
00710 
00711    /* connect to remote node port 25 */
00712    memset(&bind_addr, 0, sizeof(bind_addr));
00713    bind_addr.sin_family = AF_INET;
00714    bind_addr.sin_port = htons((short) 25);
00715 
00716    phe = gethostbyname(smtp_host);
00717    if (phe == NULL)
00718       return -1;
00719    memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
00720 
00721    if (connect(s, (const sockaddr*)&bind_addr, sizeof(bind_addr)) < 0) {
00722       closesocket(s);
00723       return -1;
00724    }
00725 
00726    strsize = TEXT_SIZE + 1000;
00727    str = (char*)malloc(strsize);
00728 
00729    recv_string(s, str, strsize, 3000);
00730    if (verbose)
00731       puts(str);
00732 
00733    /* drain server messages */
00734    do {
00735       str[0] = 0;
00736       recv_string(s, str, strsize, 300);
00737       if (verbose)
00738          puts(str);
00739    } while (str[0]);
00740 
00741    sprintf(str, "HELO %s\r\n", host_name);
00742    send(s, str, strlen(str), 0);
00743    if (verbose)
00744       puts(str);
00745    recv_string(s, str, strsize, 3000);
00746    if (verbose)
00747       puts(str);
00748 
00749    if (strchr(from, '<')) {
00750       strlcpy(buf, strchr(from, '<') + 1, sizeof(buf));
00751       if (strchr(buf, '>'))
00752          *strchr(buf, '>') = 0;
00753    } else
00754       strlcpy(buf, from, sizeof(buf));
00755 
00756    sprintf(str, "MAIL FROM: %s\n", buf);
00757    send(s, str, strlen(str), 0);
00758    if (verbose)
00759       puts(str);
00760    recv_string(s, str, strsize, 3000);
00761    if (verbose)
00762       puts(str);
00763 
00764    sprintf(str, "RCPT TO: <%s>\r\n", to);
00765    send(s, str, strlen(str), 0);
00766    if (verbose)
00767       puts(str);
00768    recv_string(s, str, strsize, 3000);
00769    if (verbose)
00770       puts(str);
00771 
00772    sprintf(str, "DATA\r\n");
00773    send(s, str, strlen(str), 0);
00774    if (verbose)
00775       puts(str);
00776    recv_string(s, str, strsize, 3000);
00777    if (verbose)
00778       puts(str);
00779 
00780    sprintf(str, "To: %s\r\nFrom: %s\r\nSubject: %s\r\n", to, from, subject);
00781    send(s, str, strlen(str), 0);
00782    if (verbose)
00783       puts(str);
00784 
00785    sprintf(str, "X-Mailer: mhttpd revision %d\r\n", mhttpd_revision());
00786    send(s, str, strlen(str), 0);
00787    if (verbose)
00788       puts(str);
00789 
00790    time(&now);
00791    ts = localtime(&now);
00792    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", ts);
00793    offset = (-(int) timezone);
00794    if (ts->tm_isdst)
00795       offset += 3600;
00796    sprintf(str, "Date: %s %+03d%02d\r\n", buf, (int) (offset / 3600),
00797            (int) ((abs((int) offset) / 60) % 60));
00798    send(s, str, strlen(str), 0);
00799    if (verbose)
00800       puts(str);
00801 
00802    sprintf(str, "Content-Type: TEXT/PLAIN; charset=US-ASCII\r\n\r\n");
00803    send(s, str, strlen(str), 0);
00804    if (verbose)
00805       puts(str);
00806 
00807    /* analyze text for "." at beginning of line */
00808    const char* p = text;
00809    str[0] = 0;
00810    while (strstr(p, "\r\n.\r\n")) {
00811       i = (POINTER_T) strstr(p, "\r\n.\r\n") - (POINTER_T) p + 1;
00812       strlcat(str, p, i);
00813       p += i + 4;
00814       strlcat(str, "\r\n..\r\n", strsize);
00815    }
00816    strlcat(str, p, strsize);
00817    strlcat(str, "\r\n", strsize);
00818    send(s, str, strlen(str), 0);
00819    if (verbose)
00820       puts(str);
00821 
00822    /* send ".<CR>" to signal end of message */
00823    sprintf(str, ".\r\n");
00824    send(s, str, strlen(str), 0);
00825    if (verbose)
00826       puts(str);
00827    recv_string(s, str, strsize, 3000);
00828    if (verbose)
00829       puts(str);
00830 
00831    sprintf(str, "QUIT\n");
00832    send(s, str, strlen(str), 0);
00833    if (verbose)
00834       puts(str);
00835    recv_string(s, str, strsize, 3000);
00836    if (verbose)
00837       puts(str);
00838 
00839    closesocket(s);
00840    free(str);
00841 
00842    return 1;
00843 }
00844 
00845 /*------------------------------------------------------------------*/
00846 
00847 void redirect(const char *path)
00848 {
00849    char str[256];
00850 
00851    //printf("redirect to [%s]\n", path);
00852 
00853    strlcpy(str, path, sizeof(str));
00854    if (str[0] == 0)
00855       strcpy(str, "./");
00856 
00857    /* redirect */
00858    rsprintf("HTTP/1.0 302 Found\r\n");
00859    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
00860    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n");
00861 
00862    if (strncmp(path, "http:", 5) == 0)
00863       rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
00864    else if (strncmp(path, "https:", 6) == 0)
00865       rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
00866    else {
00867       rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
00868    }
00869 }
00870 
00871 void redirect2(const char *path)
00872 {
00873    redirect(path);
00874    send_tcp(_sock, return_buffer, strlen(return_buffer) + 1, 0x10000);
00875    closesocket(_sock);
00876    return_length = -1;
00877 }
00878 
00879 /*------------------------------------------------------------------*/
00880 
00881 INT search_callback(HNDLE hDB, HNDLE hKey, KEY * key, INT level, void *info)
00882 {
00883    INT i, size, status;
00884    char *search_name, *p;
00885    static char data_str[MAX_ODB_PATH];
00886    static char str1[MAX_ODB_PATH], str2[MAX_ODB_PATH], ref[MAX_ODB_PATH];
00887    char path[MAX_ODB_PATH], data[10000];
00888 
00889    search_name = (char *) info;
00890 
00891    /* convert strings to uppercase */
00892    for (i = 0; key->name[i]; i++)
00893       str1[i] = toupper(key->name[i]);
00894    str1[i] = 0;
00895    for (i = 0; key->name[i]; i++)
00896       str2[i] = toupper(search_name[i]);
00897    str2[i] = 0;
00898 
00899    if (strstr(str1, str2) != NULL) {
00900       db_get_path(hDB, hKey, str1, MAX_ODB_PATH);
00901       strlcpy(path, str1 + 1, sizeof(path));    /* strip leading '/' */
00902       strlcpy(str1, path, sizeof(str1));
00903       urlEncode(str1, sizeof(str1));
00904 
00905       if (key->type == TID_KEY || key->type == TID_LINK) {
00906          /* for keys, don't display data value */
00907          rsprintf("<tr><td bgcolor=#FFD000><a href=\"%s\">%s</a></tr>\n", str1, path);
00908       } else {
00909          /* strip variable name from path */
00910          p = path + strlen(path) - 1;
00911          while (*p && *p != '/')
00912             *p-- = 0;
00913          if (*p == '/')
00914             *p = 0;
00915 
00916          /* display single value */
00917          if (key->num_values == 1) {
00918             size = sizeof(data);
00919             status = db_get_data(hDB, hKey, data, &size, key->type);
00920             if (status == DB_NO_ACCESS)
00921                strcpy(data_str, "<no read access>");
00922             else
00923                db_sprintf(data_str, data, key->item_size, 0, key->type);
00924 
00925             sprintf(ref, "%s?cmd=Set", str1);
00926 
00927             rsprintf("<tr><td bgcolor=#FFFF00>");
00928 
00929             rsprintf("<a href=\"%s\">%s</a>/%s", path, path, key->name);
00930 
00931             rsprintf("<td><a href=\"%s\">%s</a></tr>\n", ref, data_str);
00932          } else {
00933             /* display first value */
00934             rsprintf("<tr><td rowspan=%d bgcolor=#FFFF00>%s\n", key->num_values, path);
00935 
00936             for (i = 0; i < key->num_values; i++) {
00937                size = sizeof(data);
00938                db_get_data(hDB, hKey, data, &size, key->type);
00939                db_sprintf(data_str, data, key->item_size, i, key->type);
00940 
00941                sprintf(ref, "%s?cmd=Set&index=%d", str1, i);
00942 
00943                if (i > 0)
00944                   rsprintf("<tr>");
00945 
00946                rsprintf("<td><a href=\"%s\">[%d] %s</a></tr>\n", ref, i, data_str);
00947             }
00948          }
00949       }
00950    }
00951 
00952    return SUCCESS;
00953 }
00954 
00955 /*------------------------------------------------------------------*/
00956 
00957 void show_help_page()
00958 {
00959    /* header */
00960    rsprintf("HTTP/1.0 200 Document follows\r\n");
00961    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
00962    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
00963 
00964    rsprintf("<html><head>\n");
00965    rsprintf("<title>MIDAS WWW Gateway Help</title>\n");
00966    rsprintf("</head>\n\n");
00967 
00968    rsprintf("<body>\n");
00969    rsprintf("<h1>Using the MIDAS WWW Gateway</h1>\n");
00970    rsprintf("With the MIDAS WWW Gateway basic experiment control can be achieved.\n");
00971    rsprintf("The status page displays the current run status including front-end\n");
00972    rsprintf("and logger statistics. The Start and Stop buttons can start and stop\n");
00973    rsprintf("a run. The ODB button switches into the Online Database mode, where\n");
00974    rsprintf
00975        ("the contents of the experiment database can be displayed and modified.<P>\n\n");
00976 
00977    rsprintf("For more information, refer to the\n");
00978    rsprintf("<A HREF=\"http://midas.psi.ch/htmldoc/index.html\">PSI MIDAS manual</A>,\n");
00979    rsprintf
00980        ("<A HREF=\"http://ladd00.triumf.ca/~daqweb/doc/midas/html/\">Triumf MIDAS manual</A>.<P>\n\n");
00981 
00982    rsprintf("<hr>\n");
00983    rsprintf("<address>\n");
00984    rsprintf("<a href=\"http://pibeta.psi.ch/~stefan\">S. Ritt</a>, 26 Sep 2000");
00985    rsprintf("</address>");
00986 
00987    rsprintf("</body></html>\r\n");
00988 }
00989 
00990 /*------------------------------------------------------------------*/
00991 
00992 void show_header(HNDLE hDB, const char *title, const char *method, const char *path, int colspan,
00993                  int refresh)
00994 {
00995    time_t now;
00996    char str[256];
00997    int size;
00998 
00999    /* header */
01000    rsprintf("HTTP/1.0 200 Document follows\r\n");
01001    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
01002    rsprintf("Pragma: no-cache\r\n");
01003    rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
01004    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
01005 
01006    rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
01007    rsprintf("<html><head>\n");
01008 
01009    /* style sheet */
01010    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
01011    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
01012 
01013    /* auto refresh */
01014    if (refresh > 0)
01015       rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
01016 
01017    rsprintf("<title>%s</title></head>\n", title);
01018 
01019    strlcpy(str, path, sizeof(str));
01020    if (str[0] == 0)
01021       strcpy(str, "./");
01022 
01023    urlEncode(str, sizeof(str));
01024 
01025    if (equal_ustring(method, "POST"))
01026       rsprintf
01027           ("<body><form name=\"form1\" method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n\n",
01028            str);
01029    else
01030       rsprintf("<body><form name=\"form1\" method=\"%s\" action=\"%s\">\n\n", method,
01031                str);
01032 
01033    /* title row */
01034 
01035    size = sizeof(str);
01036    str[0] = 0;
01037    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
01038    time(&now);
01039 
01040    rsprintf("<table border=3 cellpadding=2>\n");
01041    rsprintf("<tr><th colspan=%d bgcolor=\"#A0A0FF\">MIDAS experiment \"%s\"", colspan,
01042             str);
01043 
01044    if (refresh > 0)
01045       rsprintf("<th colspan=%d bgcolor=\"#A0A0FF\">%s &nbsp;&nbsp;Refr:%d</tr>\n",
01046                colspan, ctime(&now), refresh);
01047    else
01048       rsprintf("<th colspan=%d bgcolor=\"#A0A0FF\">%s</tr>\n", colspan, ctime(&now));
01049 }
01050 
01051 /*------------------------------------------------------------------*/
01052 
01053 void show_text_header()
01054 {
01055    rsprintf("HTTP/1.0 200 Document follows\r\n");
01056    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
01057    rsprintf("Pragma: no-cache\r\n");
01058    rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
01059    rsprintf("Content-Type: text/plain; charset=iso-8859-1\r\n\r\n");
01060 }
01061 
01062 /*------------------------------------------------------------------*/
01063 
01064 void show_error(const char *error)
01065 {
01066    /* header */
01067    rsprintf("HTTP/1.0 200 Document follows\r\n");
01068    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
01069    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
01070 
01071    rsprintf("<html><head>\n");
01072    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
01073    rsprintf("<title>MIDAS error</title></head>\n");
01074    rsprintf("<body><H1>%s</H1></body></html>\n", error);
01075 }
01076 
01077 /*------------------------------------------------------------------*/
01078 
01079 void exec_script(HNDLE hkey)
01080 /********************************************************************\
01081 
01082   Routine: exec_script
01083 
01084   Purpose: Execute script from /Script tree
01085 
01086   exec_script is enabled by the tree /Script
01087   The /Script struct is composed of list of keys
01088   from which the name of the key is the button name
01089   and the sub-structure is a record as follow:
01090 
01091   /Script/<button_name> = <script command> (TID_STRING)
01092 
01093   The "Script command", containing possible arguements,
01094   is directly executed.
01095 
01096   /Script/<button_name>/<script command>
01097                         <soft link1>|<arg1>
01098                         <soft link2>|<arg2>
01099                            ...
01100 
01101   The arguments for the script are derived from the
01102   subtree below <button_name>, where <button_name> must be
01103   TID_KEY. The subtree may then contain arguments or links
01104   to other values in the ODB, like run number etc.
01105 
01106 \********************************************************************/
01107 {
01108    INT i, size;
01109    KEY key;
01110    HNDLE hDB, hsubkey;
01111    char command[256];
01112    char data[1000], str[256];
01113 
01114    cm_get_experiment_database(&hDB, NULL);
01115    db_get_key(hDB, hkey, &key);
01116    command[0] = 0;
01117 
01118    if (key.type == TID_STRING) {
01119       size = sizeof(command);
01120       db_get_data(hDB, hkey, command, &size, TID_STRING);
01121    } else
01122       for (i = 0;; i++) {
01123          db_enum_key(hDB, hkey, i, &hsubkey);
01124          if (!hsubkey)
01125             break;
01126          db_get_key(hDB, hsubkey, &key);
01127 
01128          if (key.type != TID_KEY) {
01129             size = sizeof(data);
01130             db_get_data(hDB, hsubkey, data, &size, key.type);
01131             db_sprintf(str, data, key.item_size, 0, key.type);
01132 
01133             if (i > 0)
01134                strlcat(command, " ", sizeof(command));
01135 
01136             strlcat(command, str, sizeof(command));
01137          }
01138       }
01139 
01140    /* printf("exec_script: %s\n", command); */
01141 
01142    if (command[0])
01143       ss_system(command);
01144 
01145    return;
01146 }
01147 
01148 /*------------------------------------------------------------------*/
01149 
01150 int requested_transition = 0;
01151 int requested_old_state = 0;
01152 
01153 void show_status_page(int refresh, const char *cookie_wpwd)
01154 {
01155    int i, j, k, h, m, s, status, size, type;
01156    BOOL flag, first;
01157    char str[1000], msg[256], name[32], ref[256], bgcol[32], fgcol[32], alarm_class[32],
01158       value_str[256], *p;
01159    const char *trans_name[] = { "Start", "Stop", "Pause", "Resume" };
01160    time_t now;
01161    DWORD difftime;
01162    double d, value, compression_ratio;
01163    HNDLE hDB, hkey, hLKey, hsubkey, hkeytmp;
01164    KEY key;
01165    int  ftp_mode, previous_mode;
01166    char client_name[NAME_LENGTH];
01167    struct tm *gmt;
01168    BOOL new_window;
01169 
01170    RUNINFO_STR(runinfo_str);
01171    RUNINFO runinfo;
01172    EQUIPMENT_INFO equipment;
01173    EQUIPMENT_STATS equipment_stats;
01174    CHN_SETTINGS chn_settings;
01175    CHN_STATISTICS chn_stats;
01176 
01177    cm_get_experiment_database(&hDB, NULL);
01178 
01179    status = db_check_record(hDB, 0, "/Runinfo", strcomb(runinfo_str), FALSE);
01180    if (status == DB_STRUCT_MISMATCH) {
01181       cm_msg(MERROR, "show_status_page", "Aborting on mismatching /Runinfo structure");
01182       cm_disconnect_experiment();
01183       abort();
01184    }
01185 
01186    if (status != DB_SUCCESS) {
01187       cm_msg(MERROR, "show_status_page",
01188              "Aborting on invalid access to ODB /Runinfo, status=%d", status);
01189       cm_disconnect_experiment();
01190       abort();
01191    }
01192 
01193    db_find_key(hDB, 0, "/Runinfo", &hkey);
01194    assert(hkey);
01195 
01196    size = sizeof(runinfo);
01197    status = db_get_record(hDB, hkey, &runinfo, &size, 0);
01198    assert(status == DB_SUCCESS);
01199 
01200    /* header */
01201    rsprintf("HTTP/1.1 200 OK\r\n");
01202    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
01203    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n");
01204    rsprintf("Pragma: no-cache\r\n");
01205    rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n");
01206    if (cookie_wpwd[0]) {
01207       time(&now);
01208       now += 3600 * 24;
01209       gmt = gmtime(&now);
01210       strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", gmt);
01211 
01212       rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", cookie_wpwd, str);
01213    }
01214 
01215    rsprintf("\r\n<html>\n");
01216 
01217    /* auto refresh */
01218    if (refresh > 0)
01219       rsprintf("<head><meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
01220 
01221    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
01222    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
01223 
01224    size = sizeof(str);
01225    str[0] = 0;
01226    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
01227    time(&now);
01228 
01229    rsprintf("<title>%s status</title></head>\n", str);
01230 
01231    rsprintf("<body><form method=\"GET\" action=\".\">\n");
01232 
01233    rsprintf("<table border=3 cellpadding=2>\n");
01234 
01235    /*---- title row ----*/
01236 
01237    rsprintf("<tr><th colspan=3 bgcolor=#A0A0FF>MIDAS experiment \"%s\"", str);
01238    rsprintf("<th colspan=3 bgcolor=#A0A0FF>%s &nbsp;&nbsp;Refr:%d</tr>\n", ctime(&now),
01239             refresh);
01240 
01241    /*---- menu buttons ----*/
01242 
01243    rsprintf("<tr><td colspan=6 bgcolor=#C0C0C0>\n");
01244 
01245 #ifdef HAVE_MSCB
01246    strlcpy(str, "Start, Pause, ODB, Messages, ELog, Alarms, Programs, History, MSCB, Config, Help", sizeof(str));
01247 #else
01248    strlcpy(str, "Start, Pause, ODB, Messages, ELog, Alarms, Programs, History, Config, Help", sizeof(str));
01249 #endif
01250    size = sizeof(str);
01251    db_get_value(hDB, 0, "/Experiment/Menu Buttons", str, &size, TID_STRING, TRUE);
01252 
01253    p = strtok(str, ", ");
01254 
01255    while (p) {
01256 
01257       strlcpy(str, p, sizeof(str));
01258 
01259       if (stricmp(str, "Start") == 0) {
01260          if (runinfo.state == STATE_STOPPED)
01261             rsprintf("<input type=submit name=cmd %s value=Start>\n", runinfo.transition_in_progress?"disabled":"");
01262          else {
01263             rsprintf("<noscript>\n");
01264             if (runinfo.state == STATE_PAUSED || runinfo.state == STATE_RUNNING)
01265                rsprintf("<input type=submit name=cmd %s value=Stop>\n", runinfo.transition_in_progress?"disabled":"");
01266             rsprintf("</noscript>\n");
01267             rsprintf("<script type=\"text/javascript\">\n");
01268             rsprintf("<!--\n");
01269             rsprintf("function stop()\n");
01270             rsprintf("{\n");
01271             rsprintf("   flag = confirm('Are you sure to stop the run?');\n");
01272             rsprintf("   if (flag == true)\n");
01273             rsprintf("      window.location.href = '?cmd=Stop';\n");
01274             rsprintf("}\n");
01275             if (runinfo.state == STATE_PAUSED || runinfo.state == STATE_RUNNING)
01276                rsprintf("document.write('<input type=button %s value=Stop onClick=\"stop();\">\\n');\n", runinfo.transition_in_progress?"disabled":"");
01277             rsprintf("//-->\n");
01278             rsprintf("</script>\n");
01279          }
01280       } else if (stricmp(str, "Pause") == 0) {
01281          if (runinfo.state != STATE_STOPPED) {
01282             rsprintf("<noscript>\n");
01283             if (runinfo.state == STATE_RUNNING)
01284                rsprintf("<input type=submit name=cmd %s value=Pause>\n", runinfo.transition_in_progress?"disabled":"");
01285             rsprintf("</noscript>\n");
01286             rsprintf("<script type=\"text/javascript\">\n");
01287             rsprintf("<!--\n");
01288             rsprintf("function pause()\n");
01289             rsprintf("{\n");
01290             rsprintf("   flag = confirm('Are you sure to pause the run?');\n");
01291             rsprintf("   if (flag == true)\n");
01292             rsprintf("      window.location.href = '?cmd=Pause';\n");
01293             rsprintf("}\n");
01294             if (runinfo.state == STATE_RUNNING)
01295                rsprintf("document.write('<input type=button %s value=Pause onClick=\"pause();\"\\n>');\n", runinfo.transition_in_progress?"disabled":"");
01296             rsprintf("//-->\n");
01297             rsprintf("</script>\n");
01298             if (runinfo.state == STATE_PAUSED)
01299                rsprintf("<input type=submit name=cmd %s value=Resume>\n", runinfo.transition_in_progress?"disabled":"");
01300          }
01301       } else
01302          rsprintf("<input type=submit name=cmd value=\"%s\">\n", str);
01303 
01304       p = strtok(NULL, ", ");
01305    }
01306 
01307    /*---- script buttons ----*/
01308 
01309    status = db_find_key(hDB, 0, "Script", &hkey);
01310    if (status == DB_SUCCESS) {
01311       rsprintf("<tr><td colspan=6 bgcolor=#E0FFFF>\n");
01312 
01313       for (i = 0;; i++) {
01314          db_enum_link(hDB, hkey, i, &hsubkey);
01315          if (!hsubkey)
01316             break;
01317          db_get_key(hDB, hsubkey, &key);
01318          rsprintf("<input type=submit name=script value=\"%s\">\n", key.name);
01319       }
01320    }
01321 
01322    rsprintf("</tr>\n\n");
01323 
01324    /*---- manual triggered equipment ----*/
01325 
01326    if (db_find_key(hDB, 0, "/equipment", &hkey) == DB_SUCCESS) {
01327       first = TRUE;
01328       for (i = 0;; i++) {
01329          db_enum_key(hDB, hkey, i, &hsubkey);
01330          if (!hsubkey)
01331             break;
01332 
01333          db_get_key(hDB, hsubkey, &key);
01334 
01335          db_find_key(hDB, hsubkey, "Common", &hkeytmp);
01336 
01337          if (hkeytmp) {
01338             size = sizeof(type);
01339             db_get_value(hDB, hkeytmp, "Type", &type, &size, TID_INT, TRUE);
01340             if (type & EQ_MANUAL_TRIG) {
01341                if (first)
01342                   rsprintf("<tr><td colspan=6 bgcolor=#E0FFE0>\n");
01343 
01344                first = FALSE;
01345 
01346                sprintf(str, "Trigger %s event", key.name);
01347                rsprintf("<input type=submit name=cmd value=\"%s\">\n", str);
01348             }
01349          }
01350       }
01351       if (!first)
01352          rsprintf("</tr>\n\n");
01353    }
01354 
01355    /*---- aliases ----*/
01356 
01357    first = TRUE;
01358 
01359    db_find_key(hDB, 0, "/Alias", &hkey);
01360    if (hkey) {
01361       if (first) {
01362          rsprintf("<tr><td colspan=6 bgcolor=#E0E0FF>\n");
01363          first = FALSE;
01364       }
01365       for (i = 0;; i++) {
01366          db_enum_link(hDB, hkey, i, &hsubkey);
01367          if (!hsubkey)
01368             break;
01369 
01370          db_get_key(hDB, hsubkey, &key);
01371 
01372          strlcpy(name, key.name, sizeof(name));
01373          new_window = (name[strlen(name) - 1] != '&');
01374          if (!new_window)
01375             name[strlen(name) - 1] = 0;
01376 
01377          if (key.type == TID_STRING) {
01378             /* html link */
01379             size = sizeof(ref);
01380             db_get_data(hDB, hsubkey, ref, &size, TID_STRING);
01381             if (new_window)
01382                rsprintf("<button type=\"button\" onclick=\"window.open('%s');\">%s</button>\n", ref, name);
01383             else
01384                rsprintf("<button type=\"button\" onclick=\"document.location.href='%s';\">%s</button>\n", ref, name);
01385          } else if (key.type == TID_LINK) {
01386             /* odb link */
01387             sprintf(ref, "./Alias/%s", key.name);
01388 
01389             if (new_window)
01390                rsprintf("<button type=\"button\" onclick=\"window.open('%s');\">%s</button>\n", ref, name);
01391             else
01392                rsprintf("<button type=\"button\" onclick=\"document.location.href='%s';\">%s</button>\n", ref, name);
01393          }
01394       }
01395    }
01396 
01397    /*---- custom pages ----*/
01398 
01399    db_find_key(hDB, 0, "/Custom", &hkey);
01400    if (hkey) {
01401       for (i = 0;; i++) {
01402          db_enum_link(hDB, hkey, i, &hsubkey);
01403          if (!hsubkey)
01404             break;
01405 
01406          db_get_key(hDB, hsubkey, &key);
01407 
01408          /* skip "Images" */
01409          if (key.type != TID_STRING)
01410             continue;
01411 
01412          /* skip "Path" */
01413          if (equal_ustring(key.name, "Path"))
01414             continue;
01415 
01416          strlcpy(name, key.name, sizeof(name));
01417 
01418          /* check if hidden page */
01419          if (name[strlen(name) - 1] == '!')
01420             continue;
01421 
01422          if (first) {
01423             rsprintf("<tr><td colspan=6 bgcolor=#E0E0FF>\n");
01424             first = FALSE;
01425          }
01426 
01427          new_window = (name[strlen(name) - 1] != '&');
01428          if (!new_window)
01429             name[strlen(name) - 1] = 0;
01430 
01431          sprintf(ref, "./CS/%s", name);
01432 
01433          if (new_window)
01434             rsprintf("<button type=\"button\" onclick=\"window.open('%s');\">%s</button>\n", ref, name);
01435          else
01436             rsprintf("<button type=\"button\" onclick=\"document.location.href='%s';\">%s</button>\n", ref, name);
01437        }
01438    }
01439 
01440    /*---- alarms ----*/
01441 
01442    /* go through all triggered alarms */
01443    db_find_key(hDB, 0, "/Alarms/Alarms", &hkey);
01444    if (hkey) {
01445       /* check global alarm flag */
01446       flag = TRUE;
01447       size = sizeof(flag);
01448       db_get_value(hDB, 0, "/Alarms/Alarm System active", &flag, &size, TID_BOOL, TRUE);
01449       if (flag) {
01450          for (i = 0;; i++) {
01451             db_enum_link(hDB, hkey, i, &hsubkey);
01452 
01453             if (!hsubkey)
01454                break;
01455 
01456             size = sizeof(flag);
01457             db_get_value(hDB, hsubkey, "Triggered", &flag, &size, TID_INT, TRUE);
01458             if (flag) {
01459                size = sizeof(alarm_class);
01460                db_get_value(hDB, hsubkey, "Alarm Class", alarm_class, &size, TID_STRING,
01461                             TRUE);
01462 
01463                strcpy(bgcol, "red");
01464                sprintf(str, "/Alarms/Classes/%s/Display BGColor", alarm_class);
01465                size = sizeof(bgcol);
01466                db_get_value(hDB, 0, str, bgcol, &size, TID_STRING, TRUE);
01467 
01468                strcpy(fgcol, "black");
01469                sprintf(str, "/Alarms/Classes/%s/Display FGColor", alarm_class);
01470                size = sizeof(fgcol);
01471                db_get_value(hDB, 0, str, fgcol, &size, TID_STRING, TRUE);
01472 
01473                size = sizeof(msg);
01474                db_get_value(hDB, hsubkey, "Alarm Message", msg, &size, TID_STRING, TRUE);
01475 
01476                size = sizeof(j);
01477                db_get_value(hDB, hsubkey, "Type", &j, &size, TID_INT, TRUE);
01478 
01479                if (j == AT_EVALUATED) {
01480                   size = sizeof(str);
01481                   db_get_value(hDB, hsubkey, "Condition", str, &size, TID_STRING, TRUE);
01482 
01483                   /* retrieve value */
01484                   al_evaluate_condition(str, value_str);
01485                   sprintf(str, msg, value_str);
01486                } else
01487                   strlcpy(str, msg, sizeof(str));
01488 
01489                rsprintf("<tr><td colspan=6 bgcolor=\"%s\" align=center>", bgcol);
01490 
01491                rsprintf("<font color=\"%s\" size=+3>%s: %s</font></tr>\n", fgcol,
01492                         alarm_class, str);
01493             }
01494          }
01495       }
01496    }
01497 
01498    /*---- run info ----*/
01499 
01500    rsprintf("<tr align=center><td>Run #%d", runinfo.run_number);
01501 
01502    if (runinfo.state == STATE_STOPPED)
01503       rsprintf("<td colspan=1 bgcolor=#FF0000>Stopped");
01504    else if (runinfo.state == STATE_PAUSED)
01505       rsprintf("<td colspan=1 bgcolor=#FFFF00>Paused");
01506    else if (runinfo.state == STATE_RUNNING)
01507       rsprintf("<td colspan=1 bgcolor=#00FF00>Running");
01508    else
01509       rsprintf("<td colspan=1 bgcolor=#FFFFFF>Unknown");
01510 
01511    if (runinfo.transition_in_progress)
01512       requested_transition = 0;
01513 
01514    if (runinfo.state != requested_old_state)
01515       requested_transition = 0;
01516 
01517    if (requested_transition == TR_STOP)
01518       rsprintf("<br><b>Run stop requested</b>");
01519 
01520    if (requested_transition == TR_START)
01521       rsprintf("<br><b>Run start requested</b>");
01522 
01523    if (requested_transition == TR_PAUSE)
01524       rsprintf("<br><b>Run pause requested</b>");
01525 
01526    if (requested_transition == TR_RESUME)
01527       rsprintf("<br><b>Run resume requested</b>");
01528 
01529    if (runinfo.transition_in_progress == TR_STOP)
01530       rsprintf("<br><b>Stopping run</b>");
01531 
01532    if (runinfo.transition_in_progress == TR_START)
01533       rsprintf("<br><b>Starting run</b>");
01534 
01535    if (runinfo.transition_in_progress == TR_PAUSE)
01536       rsprintf("<br><b>Pausing run</b>");
01537 
01538    if (runinfo.transition_in_progress == TR_RESUME)
01539       rsprintf("<br><b>Resuming run</b>");
01540 
01541    if (runinfo.requested_transition)
01542       for (i = 0; i < 4; i++)
01543          if (runinfo.requested_transition & (1 << i))
01544             rsprintf("<br><b>%s requested</b>", trans_name[i]);
01545 
01546    sprintf(ref, "Alarms/Alarm system active?cmd=set");
01547 
01548    size = sizeof(flag);
01549    db_get_value(hDB, 0, "Alarms/Alarm system active", &flag, &size, TID_BOOL, TRUE);
01550    strlcpy(str, flag ? "00FF00" : "FFC0C0", sizeof(str));
01551    rsprintf("<td bgcolor=#%s><a href=\"%s\">Alarms: %s</a>", str, ref,
01552             flag ? "On" : "Off");
01553 
01554    sprintf(ref, "Logger/Auto restart?cmd=set");
01555 
01556    if (cm_exist("RunSubmit", FALSE) == CM_SUCCESS)
01557       rsprintf("<td bgcolor=#00FF00>Restart: RunSubmit");
01558    else {
01559      size = sizeof(flag);
01560      db_get_value(hDB, 0, "Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
01561      strlcpy(str, flag ? "00FF00" : "FFFF00", sizeof(str));
01562      rsprintf("<td bgcolor=#%s><a href=\"%s\">Restart: %s</a>", str, ref,
01563               flag ? "Yes" : "No");
01564    }
01565 
01566    if (cm_exist("Logger", FALSE) != CM_SUCCESS && cm_exist("FAL", FALSE) != CM_SUCCESS)
01567       rsprintf("<td colspan=2 bgcolor=#FF0000>Logger not running</tr>\n");
01568    else {
01569       /* write data flag */
01570       size = sizeof(flag);
01571       db_get_value(hDB, 0, "/Logger/Write data", &flag, &size, TID_BOOL, TRUE);
01572 
01573       if (!flag)
01574          rsprintf("<td colspan=2 bgcolor=#FFFF00>Logging disabled</tr>\n");
01575       else {
01576          size = sizeof(str);
01577          db_get_value(hDB, 0, "/Logger/Data dir", str, &size, TID_STRING, TRUE);
01578 
01579          rsprintf("<td colspan=3>Data dir: %s</tr>\n", str);
01580       }
01581    }
01582 
01583    /*---- time ----*/
01584 
01585    rsprintf("<tr align=center><td colspan=3>Start: %s", runinfo.start_time);
01586 
01587    difftime = (DWORD) (now - runinfo.start_time_binary);
01588    h = difftime / 3600;
01589    m = difftime % 3600 / 60;
01590    s = difftime % 60;
01591 
01592    if (runinfo.state == STATE_STOPPED)
01593       rsprintf("<td colspan=3>Stop: %s</tr>\n", runinfo.stop_time);
01594    else
01595       rsprintf("<td colspan=3>Running time: %dh%02dm%02ds</tr>\n", h, m, s);
01596 
01597 
01598    /*---- run comment ----*/
01599 
01600    size = sizeof(str);
01601    if (db_get_value(hDB, 0, "/Experiment/Run parameters/Comment", str,
01602                     &size, TID_STRING, FALSE) == DB_SUCCESS)
01603       rsprintf("<tr align=center><td colspan=6 bgcolor=#E0E0FF><b>%s</b></td></tr>\n",
01604                str);
01605    size = sizeof(str);
01606    if (db_get_value(hDB, 0, "/Experiment/Run parameters/Run Description", str,
01607                     &size, TID_STRING, FALSE) == DB_SUCCESS)
01608       rsprintf("<tr align=center><td colspan=6 bgcolor=#E0E0FF><b>%s</b></td></tr>\n",
01609                str);
01610 
01611    /*---- Equipment list ----*/
01612 
01613    rsprintf("<tr><td colspan=6><table border=1 width=100%%>\n");
01614 
01615    rsprintf("<tr><th>Equipment<th>Status<th>Events");
01616    rsprintf("<th>Events[/s]<th>Data[MB/s]\n");
01617 
01618    if (db_find_key(hDB, 0, "/equipment", &hkey) == DB_SUCCESS) {
01619       for (i = 0;; i++) {
01620          db_enum_key(hDB, hkey, i, &hsubkey);
01621          if (!hsubkey)
01622             break;
01623 
01624          db_get_key(hDB, hsubkey, &key);
01625 
01626          memset(&equipment, 0, sizeof(equipment));
01627          memset(&equipment_stats, 0, sizeof(equipment_stats));
01628 
01629          db_find_key(hDB, hsubkey, "Common", &hkeytmp);
01630 
01631          if (hkeytmp) {
01632             db_get_record_size(hDB, hkeytmp, 0, &size);
01633             /* discard wrong equipments (caused by analyzer) */
01634             if (size <= (int)sizeof(equipment))
01635                db_get_record(hDB, hkeytmp, &equipment, &size, 0);
01636          }
01637 
01638          db_find_key(hDB, hsubkey, "Statistics", &hkeytmp);
01639 
01640          if (hkeytmp) {
01641             db_get_record_size(hDB, hkeytmp, 0, &size);
01642             if (size == sizeof(equipment_stats))
01643                db_get_record(hDB, hkeytmp, &equipment_stats, &size, 0);
01644          }
01645 
01646          sprintf(ref, "SC/%s", key.name);
01647 
01648          /* check if client running this equipment is present */
01649          if (cm_exist(equipment.frontend_name, TRUE) != CM_SUCCESS
01650              && cm_exist("FAL", TRUE) != CM_SUCCESS)
01651             rsprintf
01652                 ("<tr><td><a href=\"%s\">%s</a><td align=center bgcolor=#FF0000>(frontend stopped)",
01653                  ref, key.name);
01654          else {
01655             if (equipment.enabled) {
01656                if (equipment.status[0] == 0)
01657                   rsprintf("<tr><td><a href=\"%s\">%s</a><td align=center bgcolor=\"%s\">%s@%s", ref, key.name, "#00FF00", equipment.frontend_name, equipment.frontend_host);
01658                else
01659                   rsprintf("<tr><td><a href=\"%s\">%s</a><td align=center bgcolor=\"%s\">%s", ref, key.name, equipment.status_color, equipment.status);
01660             } else
01661                rsprintf("<tr><td><a href=\"%s\">%s</a><td align=center bgcolor=#FFFF00>(disabled)", ref, key.name);
01662          }
01663 
01664          /* event statistics */
01665          d = equipment_stats.events_sent;
01666          if (d > 1E9)
01667             sprintf(str, "%1.3lfG", d / 1E9);
01668          else if (d > 1E6)
01669             sprintf(str, "%1.3lfM", d / 1E6);
01670          else
01671             sprintf(str, "%1.0lf", d);
01672 
01673          rsprintf("<td align=center>%s<td align=center>%1.1lf<td align=center>%1.3lf\n",
01674                   str, equipment_stats.events_per_sec, equipment_stats.kbytes_per_sec/1024.0);
01675       }
01676    }
01677 
01678    rsprintf("</table></td></tr>\n");
01679 
01680    /*---- Logging channels ----*/
01681 
01682    rsprintf
01683        ("<tr><th colspan=2>Channel<th>Events<th>MB written<th>Compression<th>GB total</tr>\n");
01684 
01685    if (db_find_key(hDB, 0, "/Logger/Channels", &hkey) == DB_SUCCESS) {
01686       for (i = 0;; i++) {
01687          db_enum_key(hDB, hkey, i, &hsubkey);
01688          if (!hsubkey)
01689             break;
01690 
01691          db_get_key(hDB, hsubkey, &key);
01692 
01693          db_find_key(hDB, hsubkey, "Settings", &hkeytmp);
01694          assert(hkeytmp);
01695          size = sizeof(chn_settings);
01696          if (db_get_record(hDB, hkeytmp, &chn_settings, &size, 0) != DB_SUCCESS)
01697             continue;
01698 
01699          db_find_key(hDB, hsubkey, "Statistics", &hkeytmp);
01700          assert(hkeytmp);
01701          size = sizeof(chn_stats);
01702          if (db_get_record(hDB, hkeytmp, &chn_stats, &size, 0) != DB_SUCCESS)
01703             continue;
01704 
01705          /* filename */
01706 
01707          strlcpy(str, chn_settings.current_filename, sizeof(str));
01708 
01709          if (equal_ustring(chn_settings.type, "FTP")) {
01710             char *token, orig[256];
01711 
01712             strlcpy(orig, str, sizeof(orig));
01713 
01714             strlcpy(str, "ftp://", sizeof(str));
01715             token = strtok(orig, ", ");
01716             if (token) {
01717                strlcat(str, token, sizeof(str));
01718                token = strtok(NULL, ", ");
01719                token = strtok(NULL, ", ");
01720                token = strtok(NULL, ", ");
01721                token = strtok(NULL, ", ");
01722                if (token) {
01723                   strlcat(str, "/", sizeof(str));
01724                   strlcat(str, token, sizeof(str));
01725                   strlcat(str, "/", sizeof(str));
01726                   token = strtok(NULL, ", ");
01727                   strlcat(str, token, sizeof(str));
01728                }
01729             }
01730          }
01731 
01732          sprintf(ref, "Logger/Channels/%s/Settings", key.name);
01733 
01734          if (cm_exist("Logger", FALSE) != CM_SUCCESS
01735              && cm_exist("FAL", FALSE) != CM_SUCCESS)
01736             rsprintf("<tr><td colspan=2 bgcolor=\"FF0000\">");
01737          else if (!flag)
01738             rsprintf("<tr><td colspan=2 bgcolor=\"FFFF00\">");
01739          else if (chn_settings.active)
01740             rsprintf("<tr><td colspan=2 bgcolor=\"00FF00\">");
01741          else
01742             rsprintf("<tr><td colspan=2 bgcolor=\"FFFF00\">");
01743 
01744          rsprintf("<B><a href=\"%s\">#%s:</a></B>&nbsp;&nbsp;%s", ref, key.name, str);
01745 
01746          /* statistics */
01747 
01748          if (chn_settings.compression > 0) {
01749             rsprintf("<td align=center>%1.0lf<td align=center>%1.3lf\n",
01750                  chn_stats.events_written, chn_stats.bytes_written / 1024 / 1024);
01751 
01752             if (chn_stats.bytes_written_uncompressed > 0)
01753                compression_ratio = 1 - chn_stats.bytes_written / chn_stats.bytes_written_uncompressed;
01754             else
01755                compression_ratio = 0;
01756 
01757             rsprintf("<td align=center>%4.1lf%%", compression_ratio * 100);
01758          } else {
01759             rsprintf("<td align=center>%1.0lf<td align=center>%1.3lf\n",
01760                  chn_stats.events_written, chn_stats.bytes_written_uncompressed / 1024 / 1024);
01761 
01762             rsprintf("<td align=center>N/A</td>");
01763          }
01764 
01765          rsprintf("<td align=center>%1.3lf</tr>\n", chn_stats.bytes_written_total / 1024 / 1024 / 1024);
01766       }
01767    }
01768 
01769    /*---- Lazy Logger ----*/
01770 
01771    if (db_find_key(hDB, 0, "/Lazy", &hkey) == DB_SUCCESS) {
01772       status = db_find_key(hDB, 0, "System/Clients", &hkey);
01773       if (status != DB_SUCCESS)
01774          return;
01775 
01776       k = 0;
01777       previous_mode = -1;
01778       /* loop over all clients */
01779       for (j = 0;; j++) {
01780          status = db_enum_key(hDB, hkey, j, &hsubkey);
01781          if (status == DB_NO_MORE_SUBKEYS)
01782             break;
01783 
01784          if (status == DB_SUCCESS) {
01785             /* get client name */
01786             size = sizeof(client_name);
01787             db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
01788             client_name[4] = 0; /* search only for the 4 first char */
01789             if (equal_ustring(client_name, "Lazy")) {
01790                sprintf(str, "/Lazy/%s", &client_name[5]);
01791                status = db_find_key(hDB, 0, str, &hLKey);
01792                if (status == DB_SUCCESS) {
01793                   size = sizeof(str);
01794                   db_get_value(hDB, hLKey, "Settings/Backup Type", str, &size, TID_STRING,
01795                                TRUE);
01796                   ftp_mode = equal_ustring(str, "FTP");
01797 
01798                   if (previous_mode != ftp_mode)
01799                      k = 0;
01800                   if (k == 0) {
01801                      if (ftp_mode)
01802                         rsprintf
01803                             ("<tr><th colspan=2>Lazy Destination<th>Progress<th>File Name<th>Speed [MB/s]<th>Total</tr>\n");
01804                      else
01805                         rsprintf
01806                             ("<tr><th colspan=2>Lazy Label<th>Progress<th>File Name<th># Files<th>Total</tr>\n");
01807                   }
01808                   previous_mode = ftp_mode;
01809                   if (ftp_mode) {
01810                      size = sizeof(str);
01811                      db_get_value(hDB, hLKey, "Settings/Path", str, &size, TID_STRING,
01812                                   TRUE);
01813                      if (strchr(str, ','))
01814                         *strchr(str, ',') = 0;
01815                   } else {
01816                      size = sizeof(str);
01817                      db_get_value(hDB, hLKey, "Settings/List Label", str, &size,
01818                                   TID_STRING, TRUE);
01819                      if (str[0] == 0)
01820                         strcpy(str, "(empty)");
01821                   }
01822 
01823                   sprintf(ref, "Lazy/%s/Settings", &client_name[5]);
01824 
01825                   rsprintf("<tr><td colspan=2><B><a href=\"%s\">%s</a></B>", ref, str);
01826 
01827                   size = sizeof(value);
01828                   db_get_value(hDB, hLKey, "Statistics/Copy progress (%)", &value, &size,
01829                                TID_DOUBLE, TRUE);
01830                   rsprintf("<td align=center>%1.0f %%", value);
01831 
01832                   size = sizeof(str);
01833                   db_get_value(hDB, hLKey, "Statistics/Backup File", str, &size,
01834                                TID_STRING, TRUE);
01835                   rsprintf("<td align=center>%s", str);
01836 
01837                   if (ftp_mode) {
01838                      size = sizeof(value);
01839                      db_get_value(hDB, hLKey, "Statistics/Copy Rate (Bytes per s)",
01840                                   &value, &size, TID_DOUBLE, TRUE);
01841                      rsprintf("<td align=center>%1.1f", value / 1024.0 / 1024.0);
01842                   } else {
01843                      size = sizeof(i);
01844                      db_get_value(hDB, hLKey, "/Statistics/Number of files", &i, &size,
01845                                   TID_INT, TRUE);
01846                      rsprintf("<td align=center>%d", i);
01847                   }
01848 
01849                   size = sizeof(value);
01850                   db_get_value(hDB, hLKey, "Statistics/Backup status (%)", &value, &size,
01851                                TID_DOUBLE, TRUE);
01852                   rsprintf("<td align=center>%1.1f %%", value);
01853                   k++;
01854                }
01855             }
01856          }
01857       }
01858 
01859       rsprintf("</tr>\n");
01860    }
01861 
01862    /*---- Messages ----*/
01863 
01864    rsprintf("<tr><td colspan=6>");
01865 
01866    if (message_buffer[0]) {
01867       if (strstr(message_buffer, ",ERROR]"))
01868          rsprintf("<span style=\"color:white;background-color:red\"><b>%s</b></span>",
01869                   message_buffer);
01870       else
01871          rsprintf("<b>%s</b>", message_buffer);
01872    }
01873 
01874    rsprintf("</tr>");
01875 
01876    /*---- Clients ----*/
01877 
01878    if (db_find_key(hDB, 0, "/System/Clients", &hkey) == DB_SUCCESS) {
01879       for (i = 0;; i++) {
01880          db_enum_key(hDB, hkey, i, &hsubkey);
01881          if (!hsubkey)
01882             break;
01883 
01884          if (i % 3 == 0)
01885             rsprintf("<tr bgcolor=#E0E0FF>");
01886 
01887          size = sizeof(name);
01888          db_get_value(hDB, hsubkey, "Name", name, &size, TID_STRING, TRUE);
01889          size = sizeof(str);
01890          db_get_value(hDB, hsubkey, "Host", str, &size, TID_STRING, TRUE);
01891 
01892          rsprintf("<td colspan=2 align=center>%s [%s]", name, str);
01893 
01894          if (i % 3 == 2)
01895             rsprintf("</tr>\n");
01896       }
01897 
01898       if (i % 3 != 0)
01899          rsprintf("</tr>\n");
01900    }
01901 
01902    rsprintf("</table>\n");
01903    rsprintf("</body></html>\r\n");
01904 }
01905 
01906 /*------------------------------------------------------------------*/
01907 
01908 void show_messages_page(int refresh, int n_message)
01909 {
01910    int size, more;
01911    char str[256], buffer[100000], line[256], *pline;
01912    time_t now;
01913    HNDLE hDB;
01914    BOOL eob;
01915 
01916    cm_get_experiment_database(&hDB, NULL);
01917 
01918    /* header */
01919    rsprintf("HTTP/1.0 200 Document follows\r\n");
01920    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
01921    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
01922 
01923    rsprintf("<html><head>\n");
01924 
01925    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
01926    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
01927 
01928    /* auto refresh */
01929    if (refresh > 0)
01930       rsprintf("<meta http-equiv=\"Refresh\" content=\"%d\">\n\n", refresh);
01931 
01932    rsprintf("<title>MIDAS messages</title></head>\n");
01933    rsprintf("<body><form method=\"GET\" action=\".\">\n");
01934 
01935    rsprintf("<table columns=2 border=3 cellpadding=2>\n");
01936 
01937    /*---- title row ----*/
01938 
01939    size = sizeof(str);
01940    str[0] = 0;
01941    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
01942    time(&now);
01943 
01944    rsprintf("<tr><th bgcolor=#A0A0FF>MIDAS experiment \"%s\"", str);
01945    rsprintf("<th bgcolor=#A0A0FF>%s</tr>\n", ctime(&now));
01946 
01947    /*---- menu buttons ----*/
01948 
01949    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
01950 
01951    rsprintf("<input type=submit name=cmd value=ODB>\n");
01952    rsprintf("<input type=submit name=cmd value=Status>\n");
01953    rsprintf("<input type=submit name=cmd value=Config>\n");
01954    rsprintf("<input type=submit name=cmd value=Help>\n");
01955    rsprintf("</tr>\n\n");
01956 
01957    /*---- messages ----*/
01958 
01959    rsprintf("<tr><td colspan=2>\n");
01960 
01961    /* more button */
01962    if (n_message == 20)
01963       more = 100;
01964    else
01965       more = n_message + 100;
01966 
01967    rsprintf("<input type=submit name=cmd value=More%d><p>\n", more);
01968 
01969    cm_msg_retrieve(n_message, buffer, sizeof(buffer));
01970 
01971    pline = buffer;
01972    eob = FALSE;
01973 
01974    do {
01975       strlcpy(line, pline, sizeof(line));
01976 
01977       /* extract single line */
01978       if (strchr(line, '\n'))
01979          *strchr(line, '\n') = 0;
01980       if (strchr(line, '\r'))
01981          *strchr(line, '\r') = 0;
01982 
01983       pline += strlen(line);
01984 
01985       while (*pline == '\r' || *pline == '\n')
01986          pline++;
01987 
01988       /* check for error */
01989       if (strstr(line, ",ERROR]"))
01990          rsprintf("<span style=\"color:white;background-color:red\">%s</span>", line);
01991       else
01992          rsprintf("%s", line);
01993 
01994       rsprintf("<br>\n");
01995    } while (!eob && *pline);
01996 
01997    rsprintf("</tr></table>\n");
01998    rsprintf("</body></html>\r\n");
01999 }
02000 
02001 /*------------------------------------------------------------------*/
02002 
02003 void strencode(char *text)
02004 {
02005    int i;
02006 
02007    for (i = 0; i < (int) strlen(text); i++) {
02008       switch (text[i]) {
02009       case '\n':
02010          rsprintf("<br>\n");
02011          break;
02012       case '<':
02013          rsprintf("&lt;");
02014          break;
02015       case '>':
02016          rsprintf("&gt;");
02017          break;
02018       case '&':
02019          rsprintf("&amp;");
02020          break;
02021       case '\"':
02022          rsprintf("&quot;");
02023          break;
02024       default:
02025          rsprintf("%c", text[i]);
02026       }
02027    }
02028 }
02029 
02030 /*------------------------------------------------------------------*/
02031 
02032 void strencode2(char *b, char *text)
02033 {
02034    int i;
02035 
02036    for (i = 0; i < (int) strlen(text); b++, i++) {
02037       switch (text[i]) {
02038       case '\n':
02039          sprintf(b, "<br>\n");
02040          break;
02041       case '<':
02042          sprintf(b, "&lt;");
02043          break;
02044       case '>':
02045          sprintf(b, "&gt;");
02046          break;
02047       case '&':
02048          sprintf(b, "&amp;");
02049          break;
02050       case '\"':
02051          sprintf(b, "&quot;");
02052          break;
02053       default:
02054          sprintf(b, "%c", text[i]);
02055       }
02056    }
02057    *b = 0;
02058 }
02059 
02060 /*------------------------------------------------------------------*/
02061 
02062 void strencode3(char *text)
02063 {
02064    int i;
02065 
02066    for (i = 0; i < (int) strlen(text); i++) {
02067       switch (text[i]) {
02068       case '<':
02069          rsprintf("&lt;");
02070          break;
02071       case '>':
02072          rsprintf("&gt;");
02073          break;
02074       case '&':
02075          rsprintf("&amp;");
02076          break;
02077       case '\"':
02078          rsprintf("&quot;");
02079          break;
02080       default:
02081          rsprintf("%c", text[i]);
02082       }
02083    }
02084 }
02085 
02086 /*------------------------------------------------------------------*/
02087 
02088 void show_elog_new(const char *path, BOOL bedit, const char *odb_att, const char *action_path)
02089 {
02090    int i, j, size, run_number, wrap, status;
02091    char str[256], ref[256], *p;
02092    char date[80], author[80], type[80], system[80], subject[256], text[10000],
02093        orig_tag[80], reply_tag[80], att1[256], att2[256], att3[256], encoding[80];
02094    time_t now;
02095    HNDLE hDB, hkey, hsubkey;
02096    BOOL display_run_number;
02097    KEY key;
02098 
02099    //printf("show_elog_new, path [%s], action_path [%s], att [%s]\n", path, action_path, odb_att);
02100 
02101    if (!action_path)
02102      action_path = "./";
02103 
02104    cm_get_experiment_database(&hDB, NULL);
02105    display_run_number = TRUE;
02106    size = sizeof(BOOL);
02107    db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL,
02108                 TRUE);
02109 
02110    /* get message for reply */
02111    type[0] = system[0] = 0;
02112    att1[0] = att2[0] = att3[0] = 0;
02113    subject[0] = 0;
02114    run_number = 0;
02115 
02116    if (path) {
02117       strlcpy(str, path, sizeof(str));
02118       size = sizeof(text);
02119       el_retrieve(str, date, &run_number, author, type, system, subject,
02120                   text, &size, orig_tag, reply_tag, att1, att2, att3, encoding);
02121    }
02122 
02123    if (run_number < 0) {
02124       cm_msg(MERROR, "show_elog_new", "aborting on attempt to use invalid run number %d",
02125              run_number);
02126       abort();
02127    }
02128 
02129    /* header */
02130    rsprintf("HTTP/1.0 200 Document follows\r\n");
02131    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
02132    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
02133 
02134    rsprintf("<html><head>\n");
02135    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
02136    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
02137    rsprintf("<title>MIDAS ELog</title></head>\n");
02138    rsprintf
02139        ("<body><form method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n", action_path);
02140 
02141    rsprintf("<table border=3 cellpadding=5>\n");
02142 
02143   /*---- title row ----*/
02144 
02145    size = sizeof(str);
02146    str[0] = 0;
02147    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
02148 
02149    rsprintf("<tr><th bgcolor=#A0A0FF>MIDAS Electronic Logbook");
02150    if (elog_mode)
02151       rsprintf("<th bgcolor=#A0A0FF>Logbook \"%s\"</tr>\n", str);
02152    else
02153       rsprintf("<th bgcolor=#A0A0FF>Experiment \"%s\"</tr>\n", str);
02154 
02155   /*---- menu buttons ----*/
02156 
02157    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
02158 
02159    rsprintf("<input type=submit name=cmd value=Submit>\n");
02160    rsprintf("</tr>\n\n");
02161 
02162   /*---- entry form ----*/
02163 
02164    if (display_run_number) {
02165       if (bedit) {
02166          rsprintf("<tr><td bgcolor=#FFFF00>Entry date: %s<br>", date);
02167          time(&now);
02168          rsprintf("Revision date: %s", ctime(&now));
02169       } else {
02170          time(&now);
02171          rsprintf("<tr><td bgcolor=#FFFF00>Entry date: %s", ctime(&now));
02172       }
02173 
02174       if (!bedit) {
02175          run_number = 0;
02176          size = sizeof(run_number);
02177          status =
02178              db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT,
02179                           TRUE);
02180          assert(status == SUCCESS);
02181       }
02182 
02183       if (run_number < 0) {
02184          cm_msg(MERROR, "show_elog_new",
02185                 "aborting on attempt to use invalid run number %d", run_number);
02186          abort();
02187       }
02188 
02189       rsprintf("<td bgcolor=#FFFF00>Run number: ");
02190       rsprintf("<input type=\"text\" size=10 maxlength=10 name=\"run\" value=\"%d\"</tr>",
02191                run_number);
02192    } else {
02193       if (bedit) {
02194          rsprintf("<tr><td colspan=2 bgcolor=#FFFF00>Entry date: %s<br>", date);
02195          time(&now);
02196          rsprintf("Revision date: %s", ctime(&now));
02197       } else {
02198          time(&now);
02199          rsprintf("<tr><td colspan=2 bgcolor=#FFFF00>Entry date: %s", ctime(&now));
02200       }
02201    }
02202 
02203    if (bedit) {
02204       strlcpy(str, author, sizeof(str));
02205       if (strchr(str, '@'))
02206          *strchr(str, '@') = 0;
02207    } else
02208       str[0] = 0;
02209 
02210    rsprintf
02211        ("<tr><td bgcolor=#FFA0A0>Author: <input type=\"text\" size=\"15\" maxlength=\"80\" name=\"Author\" value=\"%s\">\n",
02212         str);
02213 
02214    /* get type list from ODB */
02215    size = 20 * NAME_LENGTH;
02216    if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS)
02217       db_set_value(hDB, 0, "/Elog/Types", type_list, NAME_LENGTH * 20, 20, TID_STRING);
02218    db_find_key(hDB, 0, "/Elog/Types", &hkey);
02219    if (hkey)
02220       db_get_data(hDB, hkey, type_list, &size, TID_STRING);
02221 
02222    /* add types from forms */
02223    for (j = 0; j < 20 && type_list[j][0]; j++);
02224    db_find_key(hDB, 0, "/Elog/Forms", &hkey);
02225    if (hkey)
02226       for (i = 0; j < 20; i++) {
02227          db_enum_link(hDB, hkey, i, &hsubkey);
02228          if (!hsubkey)
02229             break;
02230 
02231          db_get_key(hDB, hsubkey, &key);
02232          strlcpy(type_list[j++], key.name, NAME_LENGTH);
02233       }
02234 
02235    /* get system list from ODB */
02236    size = 20 * NAME_LENGTH;
02237    if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
02238       db_set_value(hDB, 0, "/Elog/Systems", system_list, NAME_LENGTH * 20, 20,
02239                    TID_STRING);
02240    db_find_key(hDB, 0, "/Elog/Systems", &hkey);
02241    if (hkey)
02242       db_get_data(hDB, hkey, system_list, &size, TID_STRING);
02243 
02244    sprintf(ref, "/ELog/");
02245 
02246    rsprintf
02247        ("<td bgcolor=#FFA0A0><a href=\"%s\" target=\"_blank\">Type:</a> <select name=\"type\">\n",
02248         ref);
02249    for (i = 0; i < 20 && type_list[i][0]; i++)
02250       if ((path && !bedit && equal_ustring(type_list[i], "reply")) ||
02251           (bedit && equal_ustring(type_list[i], type)))
02252          rsprintf("<option selected value=\"%s\">%s\n", type_list[i], type_list[i]);
02253       else
02254          rsprintf("<option value=\"%s\">%s\n", type_list[i], type_list[i]);
02255    rsprintf("</select></tr>\n");
02256 
02257    rsprintf
02258        ("<tr><td bgcolor=#A0FFA0><a href=\"%s\" target=\"_blank\">  System:</a> <select name=\"system\">\n",
02259         ref);
02260    for (i = 0; i < 20 && system_list[i][0]; i++)
02261       if (path && equal_ustring(system_list[i], system))
02262          rsprintf("<option selected value=\"%s\">%s\n", system_list[i], system_list[i]);
02263       else
02264          rsprintf("<option value=\"%s\">%s\n", system_list[i], system_list[i]);
02265    rsprintf("</select>\n");
02266 
02267    str[0] = 0;
02268    if (path && !bedit)
02269       sprintf(str, "Re: %s", subject);
02270    else
02271       sprintf(str, "%s", subject);
02272    rsprintf
02273        ("<td bgcolor=#A0FFA0>Subject: <input type=text size=20 maxlength=\"80\" name=Subject value=\"%s\"></tr>\n",
02274         str);
02275 
02276    if (path) {
02277       /* hidden text for original message */
02278       rsprintf("<input type=hidden name=orig value=\"%s\">\n", path);
02279 
02280       if (bedit)
02281          rsprintf("<input type=hidden name=edit value=1>\n");
02282    }
02283 
02284    /* increased wrapping for replys (leave space for '> ' */
02285    wrap = (path && !bedit) ? 78 : 76;
02286 
02287    rsprintf("<tr><td colspan=2>Text:<br>\n");
02288    rsprintf("<textarea rows=10 cols=%d wrap=hard name=Text>", wrap);
02289 
02290    if (path) {
02291       if (bedit) {
02292          rsputs(text);
02293       } else {
02294          p = text;
02295          do {
02296             if (strchr(p, '\r')) {
02297                *strchr(p, '\r') = 0;
02298                rsprintf("> %s\n", p);
02299                p += strlen(p) + 1;
02300                if (*p == '\n')
02301                   p++;
02302             } else {
02303                rsprintf("> %s\n\n", p);
02304                break;
02305             }
02306 
02307          } while (TRUE);
02308       }
02309    }
02310 
02311    rsprintf("</textarea><br>\n");
02312 
02313    /* HTML check box */
02314    if (bedit && encoding[0] == 'H')
02315       rsprintf
02316           ("<input type=checkbox checked name=html value=1>Submit as HTML text</tr>\n");
02317    else
02318       rsprintf("<input type=checkbox name=html value=1>Submit as HTML text</tr>\n");
02319 
02320    if (bedit && att1[0])
02321       rsprintf
02322           ("<tr><td colspan=2 align=center bgcolor=#8080FF>If no attachment are resubmitted, the original ones are kept</tr>\n");
02323 
02324    /* attachment */
02325    rsprintf
02326        ("<tr><td colspan=2 align=center>Enter attachment filename(s) or ODB tree(s), use \"\\\" as an ODB directory separator:</tr>");
02327 
02328    if (odb_att) {
02329       str[0] = 0;
02330       if (odb_att[0] != '\\' && odb_att[0] != '/')
02331          strlcpy(str, "\\", sizeof(str));
02332       strlcat(str, odb_att, sizeof(str));
02333       rsprintf
02334           ("<tr><td colspan=2>Attachment1: <input type=hidden name=attachment0 value=\"%s\"><b>%s</b></tr>\n",
02335            str, str);
02336    } else
02337       rsprintf
02338           ("<tr><td colspan=2>Attachment1: <input type=\"file\" size=\"60\" maxlength=\"256\" name=\"attfile1\" value=\"%s\" accept=\"filetype/*\"></tr>\n",
02339            att1);
02340 
02341    rsprintf
02342        ("<tr><td colspan=2>Attachment2: <input type=\"file\" size=\"60\" maxlength=\"256\" name=\"attfile2\" value=\"%s\" accept=\"filetype/*\"></tr>\n",
02343         att2);
02344    rsprintf
02345        ("<tr><td colspan=2>Attachment3: <input type=\"file\" size=\"60\" maxlength=\"256\" name=\"attfile3\" value=\"%s\" accept=\"filetype/*\"></tr>\n",
02346         att3);
02347 
02348    rsprintf("</table>\n");
02349    rsprintf("</body></html>\r\n");
02350 }
02351 
02352 /*------------------------------------------------------------------*/
02353 
02354 void show_elog_query()
02355 {
02356    int i, size;
02357    char str[256];
02358    time_t now;
02359    struct tm *tms;
02360    HNDLE hDB, hkey, hkeyroot;
02361    KEY key;
02362    BOOL display_run_number;
02363 
02364    /* get flag for displaying run number */
02365    cm_get_experiment_database(&hDB, NULL);
02366    display_run_number = TRUE;
02367    size = sizeof(BOOL);
02368    db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL,
02369                 TRUE);
02370 
02371    /* header */
02372    rsprintf("HTTP/1.0 200 Document follows\r\n");
02373    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
02374    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
02375 
02376    rsprintf("<html><head>\n");
02377    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
02378    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
02379    rsprintf("<title>MIDAS ELog</title></head>\n");
02380    rsprintf("<body><form method=\"GET\" action=\"./\">\n");
02381 
02382    rsprintf("<table border=3 cellpadding=5>\n");
02383 
02384   /*---- title row ----*/
02385 
02386    size = sizeof(str);
02387    str[0] = 0;
02388    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
02389 
02390    rsprintf("<tr><th colspan=2 bgcolor=#A0A0FF>MIDAS Electronic Logbook");
02391    if (elog_mode)
02392       rsprintf("<th colspan=2 bgcolor=#A0A0FF>Logbook \"%s\"</tr>\n", str);
02393    else
02394       rsprintf("<th colspan=2 bgcolor=#A0A0FF>Experiment \"%s\"</tr>\n", str);
02395 
02396   /*---- menu buttons ----*/
02397 
02398    rsprintf("<tr><td colspan=4 bgcolor=#C0C0C0>\n");
02399 
02400    rsprintf("<input type=submit name=cmd value=\"Submit Query\">\n");
02401    rsprintf("<input type=reset value=\"Reset Form\">\n");
02402    rsprintf("</tr>\n\n");
02403 
02404   /*---- entry form ----*/
02405 
02406    rsprintf("<tr><td colspan=2 bgcolor=#C0C000>");
02407    rsprintf("<input type=checkbox name=mode value=\"summary\">Summary only\n");
02408    rsprintf("<td colspan=2 bgcolor=#C0C000>");
02409    rsprintf("<input type=checkbox name=attach value=1>Show attachments</tr>\n");
02410 
02411    time(&now);
02412    now -= 3600 * 24;
02413    tms = localtime(&now);
02414    tms->tm_year += 1900;
02415 
02416    rsprintf("<tr><td bgcolor=#FFFF00>Start date: ");
02417    rsprintf("<td colspan=3 bgcolor=#FFFF00><select name=\"m1\">\n");
02418 
02419    for (i = 0; i < 12; i++)
02420       if (i == tms->tm_mon)
02421          rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
02422       else
02423          rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
02424    rsprintf("</select>\n");
02425 
02426    rsprintf("<select name=\"d1\">");
02427    for (i = 0; i < 31; i++)
02428       if (i + 1 == tms->tm_mday)
02429          rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
02430       else
02431          rsprintf("<option value=%d>%d\n", i + 1, i + 1);
02432    rsprintf("</select>\n");
02433 
02434    rsprintf(" <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">",
02435             tms->tm_year);
02436    rsprintf("</tr>\n");
02437 
02438    rsprintf("<tr><td bgcolor=#FFFF00>End date: ");
02439    rsprintf("<td colspan=3 bgcolor=#FFFF00><select name=\"m2\" value=\"%s\">\n",
02440             mname[tms->tm_mon]);
02441 
02442    rsprintf("<option value=\"\">\n");
02443    for (i = 0; i < 12; i++)
02444       rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
02445    rsprintf("</select>\n");
02446 
02447    rsprintf("<select name=\"d2\">");
02448    rsprintf("<option selected value=\"\">\n");
02449    for (i = 0; i < 31; i++)
02450       rsprintf("<option value=%d>%d\n", i + 1, i + 1);
02451    rsprintf("</select>\n");
02452 
02453    rsprintf(" <input type=\"text\" size=5 maxlength=5 name=\"y2\">");
02454    rsprintf("</tr>\n");
02455 
02456    if (display_run_number) {
02457       rsprintf("<tr><td bgcolor=#A0FFFF>Start run: ");
02458       rsprintf
02459           ("<td bgcolor=#A0FFFF><input type=\"text\" size=\"10\" maxlength=\"10\" name=\"r1\">\n");
02460       rsprintf("<td bgcolor=#A0FFFF>End run: ");
02461       rsprintf
02462           ("<td bgcolor=#A0FFFF><input type=\"text\" size=\"10\" maxlength=\"10\" name=\"r2\">\n");
02463       rsprintf("</tr>\n");
02464    }
02465 
02466    /* get type list from ODB */
02467    size = 20 * NAME_LENGTH;
02468    if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS)
02469       db_set_value(hDB, 0, "/Elog/Types", type_list, NAME_LENGTH * 20, 20, TID_STRING);
02470    db_find_key(hDB, 0, "/Elog/Types", &hkey);
02471    if (hkey)
02472       db_get_data(hDB, hkey, type_list, &size, TID_STRING);
02473 
02474    /* get system list from ODB */
02475    size = 20 * NAME_LENGTH;
02476    if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
02477       db_set_value(hDB, 0, "/Elog/Systems", system_list, NAME_LENGTH * 20, 20,
02478                    TID_STRING);
02479    db_find_key(hDB, 0, "/Elog/Systems", &hkey);
02480    if (hkey)
02481       db_get_data(hDB, hkey, system_list, &size, TID_STRING);
02482 
02483    rsprintf("<tr><td colspan=2 bgcolor=#FFA0A0>Author: ");
02484    rsprintf("<input type=\"test\" size=\"15\" maxlength=\"80\" name=\"author\">\n");
02485 
02486    rsprintf("<td colspan=2 bgcolor=#FFA0A0>Type: ");
02487    rsprintf("<select name=\"type\">\n");
02488    rsprintf("<option value=\"\">\n");
02489    for (i = 0; i < 20 && type_list[i][0]; i++)
02490       rsprintf("<option value=\"%s\">%s\n", type_list[i], type_list[i]);
02491    /* add forms as types */
02492    db_find_key(hDB, 0, "/Elog/Forms", &hkeyroot);
02493    if (hkeyroot)
02494       for (i = 0;; i++) {
02495          db_enum_link(hDB, hkeyroot, i, &hkey);
02496          if (!hkey)
02497             break;
02498          db_get_key(hDB, hkey, &key);
02499          rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
02500       }
02501    rsprintf("</select></tr>\n");
02502 
02503    rsprintf("<tr><td colspan=2 bgcolor=#A0FFA0>System: ");
02504    rsprintf("<select name=\"system\">\n");
02505    rsprintf("<option value=\"\">\n");
02506    for (i = 0; i < 20 && system_list[i][0]; i++)
02507       rsprintf("<option value=\"%s\">%s\n", system_list[i], system_list[i]);
02508    rsprintf("</select>\n");
02509 
02510    rsprintf("<td colspan=2 bgcolor=#A0FFA0>Subject: ");
02511    rsprintf("<input type=\"text\" size=\"15\" maxlength=\"80\" name=\"subject\"></tr>\n");
02512 
02513    rsprintf("<tr><td colspan=4 bgcolor=#FFA0FF>Text: ");
02514    rsprintf("<input type=\"text\" size=\"15\" maxlength=\"80\" name=\"subtext\">\n");
02515    rsprintf("<i>(case insensitive substring)</i><tr>\n");
02516 
02517    rsprintf("</tr></table>\n");
02518    rsprintf("</body></html>\r\n");
02519 }
02520 
02521 /*------------------------------------------------------------------*/
02522 
02523 void show_elog_delete(char *path)
02524 {
02525    HNDLE hDB;
02526    int size, status;
02527    char str[256];
02528    BOOL allow_delete;
02529 
02530    /* get flag for allowing delete */
02531    cm_get_experiment_database(&hDB, NULL);
02532    allow_delete = FALSE;
02533    size = sizeof(BOOL);
02534    db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
02535 
02536    /* redirect if confirm = NO */
02537    if (getparam("confirm") && *getparam("confirm")
02538        && strcmp(getparam("confirm"), "No") == 0) {
02539       sprintf(str, "../EL/%s", path);
02540       redirect(str);
02541       return;
02542    }
02543 
02544    /* header */
02545    sprintf(str, "../EL/%s", path);
02546    show_header(hDB, "Delete ELog entry", "GET", str, 1, 0);
02547 
02548    if (!allow_delete) {
02549       rsprintf
02550           ("<tr><td colspan=2 bgcolor=#FF8080 align=center><h1>Message deletion disabled in ODB</h1>\n");
02551    } else {
02552       if (getparam("confirm") && *getparam("confirm")) {
02553          if (strcmp(getparam("confirm"), "Yes") == 0) {
02554             /* delete message */
02555             status = el_delete_message(path);
02556             rsprintf("<tr><td colspan=2 bgcolor=#80FF80 align=center>");
02557             if (status == EL_SUCCESS)
02558                rsprintf("<b>Message successfully deleted</b></tr>\n");
02559             else
02560                rsprintf("<b>Error deleting message: status = %d</b></tr>\n", status);
02561 
02562             rsprintf("<input type=hidden name=cmd value=last>\n");
02563             rsprintf
02564                 ("<tr><td colspan=2 align=center><input type=submit value=\"Goto last message\"></tr>\n");
02565          }
02566       } else {
02567          /* define hidden field for command */
02568          rsprintf("<input type=hidden name=cmd value=delete>\n");
02569 
02570          rsprintf("<tr><td colspan=2 bgcolor=#FF8080 align=center>");
02571          rsprintf("<b>Are you sure to delete this message?</b></tr>\n");
02572 
02573          rsprintf("<tr><td align=center><input type=submit name=confirm value=Yes>\n");
02574          rsprintf("<td align=center><input type=submit name=confirm value=No>\n");
02575          rsprintf("</tr>\n\n");
02576       }
02577    }
02578 
02579    rsprintf("</table>\n");
02580    rsprintf("</body></html>\r\n");
02581 }
02582 
02583 /*------------------------------------------------------------------*/
02584 
02585 void show_elog_submit_query(INT last_n)
02586 {
02587    int i, size, run, status, m1, d2, m2, y2, index, colspan;
02588    char date[80], author[80], type[80], system[80], subject[256], text[10000],
02589        orig_tag[80], reply_tag[80], attachment[3][256], encoding[80];
02590    char str[256], str2[10000], tag[256], ref[256], file_name[256];
02591    HNDLE hDB;
02592    BOOL full, show_attachments, display_run_number;
02593    time_t ltime_start, ltime_end, ltime_current, now;
02594    struct tm tms, *ptms;
02595    FILE *f;
02596 
02597    /* get flag for displaying run number */
02598    cm_get_experiment_database(&hDB, NULL);
02599    display_run_number = TRUE;
02600    size = sizeof(BOOL);
02601    db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL,
02602                 TRUE);
02603 
02604    /* header */
02605    rsprintf("HTTP/1.0 200 Document follows\r\n");
02606    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
02607    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
02608 
02609    rsprintf("<html><head>\n");
02610    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
02611    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
02612    rsprintf("<title>MIDAS ELog</title></head>\n");
02613    rsprintf("<body><form method=\"GET\" action=\"./\">\n");
02614 
02615    rsprintf("<table border=3 cellpadding=2 width=\"100%%\">\n");
02616 
02617    /* get mode */
02618    if (last_n) {
02619       full = TRUE;
02620       show_attachments = FALSE;
02621    } else {
02622       full = !(*getparam("mode"));
02623       show_attachments = (*getparam("attach") > 0);
02624    }
02625 
02626    /*---- title row ----*/
02627 
02628    size = sizeof(str);
02629    str[0] = 0;
02630    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
02631 
02632    colspan = full ? 3 : 4;
02633    if (!display_run_number)
02634       colspan--;
02635 
02636    rsprintf("<tr><th colspan=3 bgcolor=#A0A0FF>MIDAS Electronic Logbook");
02637    if (elog_mode)
02638       rsprintf("<th colspan=%d bgcolor=#A0A0FF>Logbook \"%s\"</tr>\n", colspan, str);
02639    else
02640       rsprintf("<th colspan=%d bgcolor=#A0A0FF>Experiment \"%s\"</tr>\n", colspan, str);
02641 
02642    /*---- menu buttons ----*/
02643 
02644    if (!full) {
02645       colspan = display_run_number ? 7 : 6;
02646       rsprintf("<tr><td colspan=%d bgcolor=#C0C0C0>\n", colspan);
02647 
02648       rsprintf("<input type=submit name=cmd value=\"Query\">\n");
02649       rsprintf("<input type=submit name=cmd value=\"ELog\">\n");
02650       rsprintf("<input type=submit name=cmd value=\"Status\">\n");
02651       rsprintf("</tr>\n\n");
02652    }
02653 
02654    /*---- convert end date to ltime ----*/
02655 
02656    ltime_end = ltime_start = 0;
02657    m1 = m2 = d2 = y2 = 0;
02658 
02659    if (!last_n) {
02660       strlcpy(str, getparam("m1"), sizeof(str));
02661       for (m1 = 0; m1 < 12; m1++)
02662          if (equal_ustring(str, mname[m1]))
02663             break;
02664       if (m1 == 12)
02665          m1 = 0;
02666 
02667       if (*getparam("m2") || *getparam("y2") || *getparam("d2")) {
02668          if (*getparam("m2")) {
02669             strlcpy(str, getparam("m2"), sizeof(str));
02670             for (m2 = 0; m2 < 12; m2++)
02671                if (equal_ustring(str, mname[m2]))
02672                   break;
02673             if (m2 == 12)
02674                m2 = 0;
02675          } else
02676             m2 = m1;
02677 
02678          if (*getparam("y2"))
02679             y2 = atoi(getparam("y2"));
02680          else
02681             y2 = atoi(getparam("y1"));
02682 
02683          if (*getparam("d2"))
02684             d2 = atoi(getparam("d2"));
02685          else
02686             d2 = atoi(getparam("d1"));
02687 
02688          memset(&tms, 0, sizeof(struct tm));
02689          tms.tm_year = y2 % 100;
02690          tms.tm_mon = m2;
02691          tms.tm_mday = d2;
02692          tms.tm_hour = 24;
02693 
02694          if (tms.tm_year < 90)
02695             tms.tm_year += 100;
02696          ltime_end = mktime(&tms);
02697       }
02698    }
02699 
02700   /*---- title row ----*/
02701 
02702    colspan = full ? 6 : 7;
02703    if (!display_run_number)
02704       colspan--;
02705 
02706    /* menu buttons */
02707    rsprintf("<tr><td colspan=%d bgcolor=#C0C0C0>\n", colspan);
02708    rsprintf("<input type=submit name=cmd value=Query>\n");
02709    rsprintf("<input type=submit name=cmd value=Last>\n");
02710    if (!elog_mode)
02711       rsprintf("<input type=submit name=cmd value=Status>\n");
02712    rsprintf("</tr>\n");
02713 
02714    if (*getparam("r1")) {
02715       if (*getparam("r2"))
02716          rsprintf
02717              ("<tr><td colspan=%d bgcolor=#FFFF00><b>Query result between runs %s and %s</b></tr>\n",
02718               colspan, getparam("r1"), getparam("r2"));
02719       else
02720          rsprintf
02721              ("<tr><td colspan=%d bgcolor=#FFFF00><b>Query result between run %s and today</b></tr>\n",
02722               colspan, getparam("r1"));
02723    } else {
02724       if (last_n) {
02725          if (last_n < 24) {
02726             rsprintf("<tr><td colspan=6><a href=\"last%d\">Last %d hours</a></tr>\n",
02727                         last_n * 2, last_n * 2);
02728 
02729             rsprintf("<tr><td colspan=6 bgcolor=#FFFF00><b>Last %d hours</b></tr>\n",
02730                      last_n);
02731          } else {
02732             rsprintf("<tr><td colspan=6><a href=\"last%d\">Last %d days</a></tr>\n",
02733                         last_n * 2, last_n / 24 * 2);
02734 
02735             rsprintf("<tr><td colspan=6 bgcolor=#FFFF00><b>Last %d days</b></tr>\n",
02736                      last_n / 24);
02737          }
02738       }
02739 
02740       else if (*getparam("m2") || *getparam("y2") || *getparam("d2"))
02741          rsprintf
02742              ("<tr><td colspan=%d bgcolor=#FFFF00><b>Query result between %s %s %s and %s %d %d</b></tr>\n",
02743               colspan, getparam("m1"), getparam("d1"), getparam("y1"), mname[m2], d2, y2);
02744       else {
02745          time(&now);
02746          ptms = localtime(&now);
02747          ptms->tm_year += 1900;
02748 
02749          rsprintf
02750              ("<tr><td colspan=%d bgcolor=#FFFF00><b>Query result between %s %s %s and %s %d %d</b></tr>\n",
02751               colspan, getparam("m1"), getparam("d1"), getparam("y1"),
02752               mname[ptms->tm_mon], ptms->tm_mday, ptms->tm_year);
02753       }
02754    }
02755 
02756    rsprintf("</tr>\n<tr>");
02757 
02758    rsprintf("<td colspan=%d bgcolor=#FFA0A0>\n", colspan);
02759 
02760    if (*getparam("author"))
02761       rsprintf("Author: <b>%s</b>   ", getparam("author"));
02762 
02763    if (*getparam("type"))
02764       rsprintf("Type: <b>%s</b>   ", getparam("type"));
02765 
02766    if (*getparam("system"))
02767       rsprintf("System: <b>%s</b>   ", getparam("system"));
02768 
02769    if (*getparam("subject"))
02770       rsprintf("Subject: <b>%s</b>   ", getparam("subject"));
02771 
02772    if (*getparam("subtext"))
02773       rsprintf("Text: <b>%s</b>   ", getparam("subtext"));
02774 
02775    rsprintf("</tr>\n");
02776 
02777   /*---- table titles ----*/
02778 
02779    if (display_run_number) {
02780       if (full)
02781          rsprintf("<tr><th>Date<th>Run<th>Author<th>Type<th>System<th>Subject</tr>\n");
02782       else
02783          rsprintf
02784              ("<tr><th>Date<th>Run<th>Author<th>Type<th>System<th>Subject<th>Text</tr>\n");
02785    } else {
02786       if (full)
02787          rsprintf("<tr><th>Date<th>Author<th>Type<th>System<th>Subject</tr>\n");
02788       else
02789          rsprintf("<tr><th>Date<th>Author<th>Type<th>System<th>Subject<th>Text</tr>\n");
02790    }
02791 
02792   /*---- do query ----*/
02793 
02794    if (last_n) {
02795       time(&now);
02796       ltime_start = now - 3600 * last_n;
02797       ptms = localtime(&ltime_start);
02798       sprintf(tag, "%02d%02d%02d.0", ptms->tm_year % 100, ptms->tm_mon + 1,
02799               ptms->tm_mday);
02800    } else if (*getparam("r1")) {
02801       /* do run query */
02802       el_search_run(atoi(getparam("r1")), tag);
02803    } else {
02804       /* do date-date query */
02805       sprintf(tag, "%02d%02d%02d.0", atoi(getparam("y1")) % 100, m1 + 1,
02806               atoi(getparam("d1")));
02807    }
02808 
02809    do {
02810       size = sizeof(text);
02811       status = el_retrieve(tag, date, &run, author, type, system, subject,
02812                            text, &size, orig_tag, reply_tag,
02813                            attachment[0], attachment[1], attachment[2], encoding);
02814       strlcat(tag, "+1", sizeof(tag));
02815 
02816       /* check for end run */
02817       if (*getparam("r2") && atoi(getparam("r2")) < run)
02818          break;
02819 
02820       /* convert date to unix format */
02821       memset(&tms, 0, sizeof(struct tm));
02822       tms.tm_year = (tag[0] - '0') * 10 + (tag[1] - '0');
02823       tms.tm_mon = (tag[2] - '0') * 10 + (tag[3] - '0') - 1;
02824       tms.tm_mday = (tag[4] - '0') * 10 + (tag[5] - '0');
02825       tms.tm_hour = (date[11] - '0') * 10 + (date[12] - '0');
02826       tms.tm_min = (date[14] - '0') * 10 + (date[15] - '0');
02827       tms.tm_sec = (date[17] - '0') * 10 + (date[18] - '0');
02828 
02829       if (tms.tm_year < 90)
02830          tms.tm_year += 100;
02831       ltime_current = mktime(&tms);
02832 
02833       /* check for start date */
02834       if (ltime_start > 0)
02835          if (ltime_current < ltime_start)
02836             continue;
02837 
02838       /* check for end date */
02839       if (ltime_end > 0) {
02840          if (ltime_current > ltime_end)
02841             break;
02842       }
02843 
02844       if (status == EL_SUCCESS) {
02845          /* do filtering */
02846          if (*getparam("type") && !equal_ustring(getparam("type"), type))
02847             continue;
02848          if (*getparam("system") && !equal_ustring(getparam("system"), system))
02849             continue;
02850 
02851          if (*getparam("author")) {
02852             strlcpy(str, getparam("author"), sizeof(str));
02853             for (i = 0; i < (int) strlen(str); i++)
02854                str[i] = toupper(str[i]);
02855             str[i] = 0;
02856             for (i = 0; i < (int) strlen(author) && author[i] != '@'; i++)
02857                str2[i] = toupper(author[i]);
02858             str2[i] = 0;
02859 
02860             if (strstr(str2, str) == NULL)
02861                continue;
02862          }
02863 
02864          if (*getparam("subject")) {
02865             strlcpy(str, getparam("subject"), sizeof(str));
02866             for (i = 0; i < (int) strlen(str); i++)
02867                str[i] = toupper(str[i]);
02868             str[i] = 0;
02869             for (i = 0; i < (int) strlen(subject); i++)
02870                str2[i] = toupper(subject[i]);
02871             str2[i] = 0;
02872 
02873             if (strstr(str2, str) == NULL)
02874                continue;
02875          }
02876 
02877          if (*getparam("subtext")) {
02878             strlcpy(str, getparam("subtext"), sizeof(str));
02879             for (i = 0; i < (int) strlen(str); i++)
02880                str[i] = toupper(str[i]);
02881             str[i] = 0;
02882             for (i = 0; i < (int) strlen(text); i++)
02883                str2[i] = toupper(text[i]);
02884             str2[i] = 0;
02885 
02886             if (strstr(str2, str) == NULL)
02887                continue;
02888          }
02889 
02890          /* filter passed: display line */
02891 
02892          strlcpy(str, tag, sizeof(str));
02893          if (strchr(str, '+'))
02894             *strchr(str, '+') = 0;
02895          sprintf(ref, "/EL/%s", str);
02896 
02897          strlcpy(str, text, sizeof(str));
02898 
02899          if (full) {
02900             if (display_run_number) {
02901                rsprintf("<tr><td><a href=%s>%s</a><td>%d<td>%s<td>%s<td>%s<td>%s</tr>\n",
02902                         ref, date, run, author, type, system, subject);
02903                rsprintf("<tr><td colspan=6>");
02904             } else {
02905                rsprintf("<tr><td><a href=%s>%s</a><td>%s<td>%s<td>%s<td>%s</tr>\n", ref,
02906                         date, author, type, system, subject);
02907                rsprintf("<tr><td colspan=5>");
02908             }
02909 
02910             if (equal_ustring(encoding, "plain")) {
02911                rsputs("<pre>");
02912                rsputs2(text);
02913                rsputs("</pre>");
02914             } else
02915                rsputs(text);
02916 
02917             if (!show_attachments && attachment[0][0]) {
02918                if (attachment[1][0])
02919                   rsprintf("Attachments: ");
02920                else
02921                   rsprintf("Attachment: ");
02922             } else
02923                rsprintf("</tr>\n");
02924 
02925             for (index = 0; index < 3; index++) {
02926                if (attachment[index][0]) {
02927                   char ref1[256];
02928 
02929                   for (i = 0; i < (int) strlen(attachment[index]); i++)
02930                      str[i] = toupper(attachment[index][i]);
02931                   str[i] = 0;
02932 
02933                   strlcpy(ref1, attachment[index], sizeof(ref1));
02934                   urlEncode(ref1, sizeof(ref1));
02935                   
02936                   sprintf(ref, "/EL/%s", ref1);
02937 
02938                   if (!show_attachments) {
02939                      rsprintf("<a href=\"%s\"><b>%s</b></a> ", ref,
02940                               attachment[index] + 14);
02941                   } else {
02942                      colspan = display_run_number ? 6 : 5;
02943                      if (strstr(str, ".GIF") || strstr(str, ".PNG")
02944                          || strstr(str, ".JPG")) {
02945                         rsprintf
02946                             ("<tr><td colspan=%d>Attachment: <a href=\"%s\"><b>%s</b></a><br>\n",
02947                              colspan, ref, attachment[index] + 14);
02948                         if (show_attachments)
02949                            rsprintf("<img src=\"%s\"></tr>", ref);
02950                      } else {
02951                         rsprintf
02952                             ("<tr><td colspan=%d bgcolor=#C0C0FF>Attachment: <a href=\"%s\"><b>%s</b></a>\n",
02953                              colspan, ref, attachment[index] + 14);
02954 
02955                         if ((strstr(str, ".TXT") ||
02956                              strstr(str, ".ASC") || strchr(str, '.') == NULL)
02957                             && show_attachments) {
02958                            /* display attachment */
02959                            rsprintf("<br><pre>");
02960 
02961                            file_name[0] = 0;
02962                            size = sizeof(file_name);
02963                            memset(file_name, 0, size);
02964                            db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size,
02965                                         TID_STRING, TRUE);
02966                            if (file_name[0] != 0)
02967                               if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
02968                                  strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
02969                            strlcat(file_name, attachment[index], sizeof(file_name));
02970 
02971                            f = fopen(file_name, "rt");
02972                            if (f != NULL) {
02973                               while (!feof(f)) {
02974                                  str[0] = 0;
02975                                  fgets(str, sizeof(str), f);
02976                                  rsputs2(str);
02977                               }
02978                               fclose(f);
02979                            }
02980 
02981                            rsprintf("</pre>\n");
02982                         }
02983                         rsprintf("</tr>\n");
02984                      }
02985                   }
02986                }
02987             }
02988 
02989             if (!show_attachments && attachment[0][0])
02990                rsprintf("</tr>\n");
02991 
02992          } else {
02993             if (display_run_number)
02994                rsprintf("<tr><td><a href=%s>%s</a><td>%d<td>%s<td>%s<td>%s<td>%s\n", ref,
02995                         date, run, author, type, system, subject);
02996             else
02997                rsprintf("<tr><td><a href=%s>%s</a><td>%s<td>%s<td>%s<td>%s\n", ref, date,
02998                         author, type, system, subject);
02999 
03000             if (equal_ustring(encoding, "HTML"))
03001                rsputs(text);
03002             else
03003                strencode(text);
03004 
03005             rsprintf("</tr>\n");
03006          }
03007       }
03008 
03009    } while (status == EL_SUCCESS);
03010 
03011    rsprintf("</table>\n");
03012    rsprintf("</body></html>\r\n");
03013 }
03014 
03015 /*------------------------------------------------------------------*/
03016 
03017 void show_rawfile(char *path)
03018 {
03019    int size, lines, i, buf_size, offset;
03020    char *p;
03021    FILE *f;
03022    char file_name[256], str[100], buffer[100000];
03023    HNDLE hDB;
03024 
03025    cm_get_experiment_database(&hDB, NULL);
03026 
03027    lines = 10;
03028    if (*getparam("lines"))
03029       lines = atoi(getparam("lines"));
03030 
03031    if (*getparam("cmd") && equal_ustring(getparam("cmd"), "More lines"))
03032       lines *= 2;
03033 
03034    /* header */
03035    rsprintf("HTTP/1.0 200 Document follows\r\n");
03036    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03037    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
03038 
03039    rsprintf("<html><head>\n");
03040    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
03041    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
03042    rsprintf("<title>MIDAS File Display %s</title></head>\n", path);
03043    rsprintf("<body><form method=\"GET\" action=\"./%s\">\n", path);
03044 
03045    rsprintf("<input type=hidden name=lines value=%d>\n", lines);
03046 
03047    rsprintf("<table border=3 cellpadding=1 width=\"100%%\">\n");
03048 
03049    /*---- title row ----*/
03050 
03051    size = sizeof(str);
03052    str[0] = 0;
03053    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
03054 
03055    rsprintf("<tr><th bgcolor=#A0A0FF>MIDAS File Display <code>\"%s\"</code>", path);
03056    if (elog_mode)
03057       rsprintf("<th bgcolor=#A0A0FF>Logbook \"%s\"</tr>\n", str);
03058    else
03059       rsprintf("<th bgcolor=#A0A0FF>Experiment \"%s\"</tr>\n", str);
03060 
03061    /*---- menu buttons ----*/
03062 
03063    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
03064 
03065    rsprintf("<input type=submit name=cmd value=\"ELog\">\n");
03066    if (!elog_mode)
03067       rsprintf("<input type=submit name=cmd value=\"Status\">\n");
03068 
03069    rsprintf("<input type=submit name=cmd value=\"More lines\">\n");
03070 
03071    rsprintf("</tr>\n\n");
03072 
03073    /*---- open file ----*/
03074 
03075    cm_get_experiment_database(&hDB, NULL);
03076    file_name[0] = 0;
03077    if (hDB > 0) {
03078       size = sizeof(file_name);
03079       memset(file_name, 0, size);
03080       db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
03081       if (file_name[0] != 0)
03082          if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
03083             strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
03084    }
03085    strlcat(file_name, path, sizeof(file_name));
03086 
03087    f = fopen(file_name, "r");
03088    if (f == NULL) {
03089       rsprintf("<h3>Cannot find file \"%s\"</h3>\n", file_name);
03090       rsprintf("</body></html>\n");
03091       return;
03092    }
03093 
03094    /*---- file contents ----*/
03095 
03096    rsprintf("<tr><td colspan=2>\n");
03097 
03098    rsprintf("<pre>\n");
03099 
03100    buf_size = sizeof(buffer);
03101 
03102    /* position buf_size bytes before the EOF */
03103    fseek(f, -(buf_size - 1), SEEK_END);
03104    offset = ftell(f);
03105    if (offset != 0) {
03106       /* go to end of line */
03107       fgets(buffer, buf_size - 1, f);
03108       offset = ftell(f) - offset;
03109       buf_size -= offset;
03110    }
03111 
03112    memset(buffer, 0, buf_size);
03113    fread(buffer, 1, buf_size - 1, f);
03114    buffer[buf_size - 1] = 0;
03115    fclose(f);
03116 
03117    p = buffer + (buf_size - 2);
03118 
03119    /* goto end of buffer */
03120    while (p != buffer && *p == 0)
03121       p--;
03122 
03123    /* strip line break */
03124    while (p != buffer && (*p == '\n' || *p == '\r'))
03125       *(p--) = 0;
03126 
03127    /* trim buffer so that last lines remain */
03128    for (i = 0; i < lines; i++) {
03129       while (p != buffer && *p != '\n')
03130          p--;
03131 
03132       while (p != buffer && (*p == '\n' || *p == '\r'))
03133          p--;
03134    }
03135    if (p != buffer) {
03136       p++;
03137       while (*p == '\n' || *p == '\r')
03138          p++;
03139    }
03140 
03141    buf_size = (buf_size - 1) - ((POINTER_T) p - (POINTER_T) buffer);
03142 
03143    memmove(buffer, p, buf_size);
03144    buffer[buf_size] = 0;
03145 
03146    rsputs(buffer);
03147 
03148    rsprintf("</pre>\n");
03149 
03150    rsprintf("</td></tr></table></body></html>\r\n");
03151 }
03152 
03153 /*------------------------------------------------------------------*/
03154 
03155 void show_form_query()
03156 {
03157    int i = 0, size, run_number, status;
03158    char str[256];
03159    time_t now;
03160    HNDLE hDB, hkey, hkeyroot;
03161    KEY key;
03162 
03163    cm_get_experiment_database(&hDB, NULL);
03164 
03165    /* header */
03166    rsprintf("HTTP/1.0 200 Document follows\r\n");
03167    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03168    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
03169 
03170    rsprintf("<html><head>\n");
03171    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
03172    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
03173    rsprintf("<title>MIDAS ELog</title></head>\n");
03174    rsprintf("<body><form method=\"GET\" action=\"./\">\n");
03175 
03176    if (*getparam("form") == 0)
03177       return;
03178 
03179    /* hidden field for form */
03180    rsprintf("<input type=hidden name=form value=\"%s\">\n", getparam("form"));
03181 
03182    rsprintf("<table border=3 cellpadding=1>\n");
03183 
03184    /*---- title row ----*/
03185 
03186    rsprintf("<tr><th colspan=2 bgcolor=#A0A0FF>MIDAS Electronic Logbook");
03187    rsprintf("<th colspan=2 bgcolor=#A0A0FF>Form \"%s\"</tr>\n", getparam("form"));
03188 
03189    /*---- menu buttons ----*/
03190 
03191    rsprintf("<tr><td colspan=4 bgcolor=#C0C0C0>\n");
03192 
03193    rsprintf("<input type=submit name=cmd value=\"Submit\">\n");
03194    rsprintf("<input type=reset value=\"Reset Form\">\n");
03195    rsprintf("</tr>\n\n");
03196 
03197    /*---- entry form ----*/
03198 
03199    time(&now);
03200    rsprintf("<tr><td colspan=2 bgcolor=#FFFF00>Entry date: %s", ctime(&now));
03201 
03202    run_number = 0;
03203    size = sizeof(run_number);
03204    status =
03205        db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
03206    assert(status == SUCCESS);
03207 
03208    if (run_number < 0) {
03209       cm_msg(MERROR, "show_form_query",
03210              "aborting on attempt to use invalid run number %d", run_number);
03211       abort();
03212    }
03213 
03214    rsprintf("<td bgcolor=#FFFF00>Run number: ");
03215    rsprintf("<input type=\"text\" size=10 maxlength=10 name=\"run\" value=\"%d\"</tr>",
03216             run_number);
03217 
03218    rsprintf
03219        ("<tr><td colspan=2 bgcolor=#FFA0A0>Author: <input type=\"text\" size=\"15\" maxlength=\"80\" name=\"Author\">\n");
03220 
03221    rsprintf
03222        ("<tr><th bgcolor=#A0FFA0>Item<th bgcolor=#FFFF00>Checked<th bgcolor=#A0A0FF colspan=2>Comment</tr>\n");
03223 
03224    sprintf(str, "/Elog/Forms/%s", getparam("form"));
03225    db_find_key(hDB, 0, str, &hkeyroot);
03226    i = 0;
03227    if (hkeyroot)
03228       for (i = 0;; i++) {
03229          db_enum_link(hDB, hkeyroot, i, &hkey);
03230          if (!hkey)
03231             break;
03232 
03233          db_get_key(hDB, hkey, &key);
03234 
03235          strlcpy(str, key.name, sizeof(str));
03236          if (str[0])
03237             str[strlen(str) - 1] = 0;
03238          if (equal_ustring(str, "attachment")) {
03239             size = sizeof(str);
03240             db_get_data(hDB, hkey, str, &size, TID_STRING);
03241             rsprintf("<tr><td colspan=2 align=center bgcolor=#FFFFFF><b>%s:</b>",
03242                      key.name);
03243             rsprintf
03244                 ("<td bgcolor=#A0A0FF colspan=2><input type=text size=30 maxlength=255 name=c%d value=\"%s\"></tr>\n",
03245                  i, str);
03246          } else {
03247             rsprintf("<tr><td bgcolor=#A0FFA0>%d <b>%s</b>", i + 1, key.name);
03248             rsprintf
03249                 ("<td bgcolor=#FFFF00 align=center><input type=checkbox name=x%d value=1>",
03250                  i);
03251             rsprintf
03252                 ("<td bgcolor=#A0A0FF colspan=2><input type=text size=30 maxlength=255 name=c%d></tr>\n",
03253                  i);
03254          }
03255       }
03256 
03257 
03258    /*---- menu buttons at bottom ----*/
03259 
03260    if (i > 10) {
03261       rsprintf("<tr><td colspan=4 bgcolor=#C0C0C0>\n");
03262 
03263       rsprintf("<input type=submit name=cmd value=\"Submit\">\n");
03264       rsprintf("</tr>\n\n");
03265    }
03266 
03267    rsprintf("</tr></table>\n");
03268    rsprintf("</body></html>\r\n");
03269 }
03270 
03271 /*------------------------------------------------------------------*/
03272 
03273 void gen_odb_attachment(char *path, char *b)
03274 {
03275    HNDLE hDB, hkeyroot, hkey;
03276    KEY key;
03277    INT i, j, size;
03278    char str[256], data_str[256], hex_str[256];
03279    char data[10000];
03280    time_t now;
03281 
03282    cm_get_experiment_database(&hDB, NULL);
03283    db_find_key(hDB, 0, path, &hkeyroot);
03284    assert(hkeyroot);
03285 
03286    /* title row */
03287    size = sizeof(str);
03288    str[0] = 0;
03289    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
03290    time(&now);
03291 
03292    sprintf(b, "<table border=3 cellpadding=1>\n");
03293    sprintf(b + strlen(b), "<tr><th colspan=2 bgcolor=#A0A0FF>%s</tr>\n", ctime(&now));
03294    sprintf(b + strlen(b), "<tr><th colspan=2 bgcolor=#FFA0A0>%s</tr>\n", path);
03295 
03296    /* enumerate subkeys */
03297    for (i = 0;; i++) {
03298       db_enum_link(hDB, hkeyroot, i, &hkey);
03299       if (!hkey)
03300          break;
03301       db_get_key(hDB, hkey, &key);
03302 
03303       /* resolve links */
03304       if (key.type == TID_LINK) {
03305          db_enum_key(hDB, hkeyroot, i, &hkey);
03306          db_get_key(hDB, hkey, &key);
03307       }
03308 
03309       if (key.type == TID_KEY) {
03310          /* for keys, don't display data value */
03311          sprintf(b + strlen(b), "<tr><td colspan=2 bgcolor=#FFD000>%s</td></tr>\n",
03312                  key.name);
03313       } else {
03314          /* display single value */
03315          if (key.num_values == 1) {
03316             size = sizeof(data);
03317             db_get_data(hDB, hkey, data, &size, key.type);
03318             db_sprintf(data_str, data, key.item_size, 0, key.type);
03319             db_sprintfh(hex_str, data, key.item_size, 0, key.type);
03320 
03321             if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
03322                strcpy(data_str, "(empty)");
03323                hex_str[0] = 0;
03324             }
03325 
03326             if (strcmp(data_str, hex_str) != 0 && hex_str[0])
03327                sprintf(b + strlen(b),
03328                        "<tr><td bgcolor=#FFFF00>%s</td><td bgcolor=#FFFFFF>%s (%s)</td></tr>\n",
03329                        key.name, data_str, hex_str);
03330             else {
03331                sprintf(b + strlen(b),
03332                        "<tr><td bgcolor=#FFFF00>%s</td><td bgcolor=#FFFFFF>", key.name);
03333                strencode2(b + strlen(b), data_str);
03334                sprintf(b + strlen(b), "</td></tr>\n");
03335             }
03336          } else {
03337             /* display first value */
03338             sprintf(b + strlen(b), "<tr><td  bgcolor=#FFFF00 rowspan=%d>%s</td>\n",
03339                     key.num_values, key.name);
03340 
03341             for (j = 0; j < key.num_values; j++) {
03342                size = sizeof(data);
03343                db_get_data_index(hDB, hkey, data, &size, j, key.type);
03344                db_sprintf(data_str, data, key.item_size, 0, key.type);
03345                db_sprintfh(hex_str, data, key.item_size, 0, key.type);
03346 
03347                if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
03348                   strcpy(data_str, "(empty)");
03349                   hex_str[0] = 0;
03350                }
03351 
03352                if (j > 0)
03353                   sprintf(b + strlen(b), "<tr>");
03354 
03355                if (strcmp(data_str, hex_str) != 0 && hex_str[0])
03356                   sprintf(b + strlen(b),
03357                           "<td bgcolor=#FFFFFF>[%d] %s (%s)<br></td></tr>\n", j, data_str,
03358                           hex_str);
03359                else
03360                   sprintf(b + strlen(b), "<td bgcolor=#FFFFFF>[%d] %s<br></td></tr>\n", j,
03361                           data_str);
03362             }
03363          }
03364       }
03365    }
03366 
03367    sprintf(b + strlen(b), "</table>\n");
03368 }
03369 
03370 /*------------------------------------------------------------------*/
03371 
03372 void submit_elog()
03373 {
03374    char str[80], author[256], path[256], path1[256];
03375    char mail_to[256], mail_from[256], mail_text[10000], mail_list[256],
03376        smtp_host[256], tag[80], mail_param[1000];
03377    char *buffer[3], *p, *pitem;
03378    HNDLE hDB, hkey;
03379    char att_file[3][256];
03380    int i, fh, size, n_mail, index;
03381    struct hostent *phe;
03382    char mhttpd_full_url[256];
03383 
03384    cm_get_experiment_database(&hDB, NULL);
03385    strlcpy(att_file[0], getparam("attachment0"), sizeof(att_file[0]));
03386    strlcpy(att_file[1], getparam("attachment1"), sizeof(att_file[1]));
03387    strlcpy(att_file[2], getparam("attachment2"), sizeof(att_file[2]));
03388 
03389    /* check for author */
03390    if (*getparam("author") == 0) {
03391       rsprintf("HTTP/1.0 200 Document follows\r\n");
03392       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03393       rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
03394 
03395       rsprintf("<html><head>\n");
03396       rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
03397       rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
03398       rsprintf("<title>ELog Error</title></head>\n");
03399       rsprintf("<i>Error: No author supplied.</i><p>\n");
03400       rsprintf("Please go back and enter your name in the <i>author</i> field.\n");
03401       rsprintf("<body></body></html>\n");
03402       return;
03403    }
03404 
03405    /* check for valid attachment files */
03406    for (i = 0; i < 3; i++) {
03407       buffer[i] = NULL;
03408       sprintf(str, "attachment%d", i);
03409       if (getparam(str) && *getparam(str) && _attachment_size[i] == 0) {
03410          /* replace '\' by '/' */
03411          strlcpy(path, getparam(str), sizeof(path));
03412          strlcpy(path1, path, sizeof(path1));
03413          while (strchr(path, '\\'))
03414             *strchr(path, '\\') = '/';
03415 
03416          /* check if valid ODB tree */
03417          if (db_find_key(hDB, 0, path, &hkey) == DB_SUCCESS) {
03418            buffer[i] = (char*)M_MALLOC(100000);
03419             gen_odb_attachment(path, buffer[i]);
03420             strlcpy(att_file[i], path, sizeof(att_file[0]));
03421             strlcat(att_file[i], ".html", sizeof(att_file[0]));
03422             _attachment_buffer[i] = buffer[i];
03423             _attachment_size[i] = strlen(buffer[i]) + 1;
03424          }
03425          /* check if local file */
03426          else if ((fh = open(path1, O_RDONLY | O_BINARY)) >= 0) {
03427             size = lseek(fh, 0, SEEK_END);
03428             buffer[i] = (char*)M_MALLOC(size);
03429             lseek(fh, 0, SEEK_SET);
03430             read(fh, buffer[i], size);
03431             close(fh);
03432             strlcpy(att_file[i], path, sizeof(att_file[0]));
03433             _attachment_buffer[i] = buffer[i];
03434             _attachment_size[i] = size;
03435          } else if (strncmp(path, "/HS/", 4) == 0) {
03436            buffer[i] = (char*)M_MALLOC(100000);
03437             size = 100000;
03438             strlcpy(str, path + 4, sizeof(str));
03439             if (strchr(str, '?')) {
03440                p = strchr(str, '?') + 1;
03441                p = strtok(p, "&");
03442                while (p != NULL) {
03443                   pitem = p;
03444                   p = strchr(p, '=');
03445                   if (p != NULL) {
03446                      *p++ = 0;
03447                      urlDecode(pitem);
03448                      urlDecode(p);
03449 
03450                      setparam(pitem, p);
03451 
03452                      p = strtok(NULL, "&");
03453                   }
03454                }
03455                *strchr(str, '?') = 0;
03456             }
03457             show_hist_page(str, sizeof(str), buffer[i], &size, 0);
03458             strlcpy(att_file[i], str, sizeof(att_file[0]));
03459             _attachment_buffer[i] = buffer[i];
03460             _attachment_size[i] = size;
03461             unsetparam("scale");
03462             unsetparam("offset");
03463             unsetparam("width");
03464             unsetparam("index");
03465          } else {
03466             rsprintf("HTTP/1.0 200 Document follows\r\n");
03467             rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03468             rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
03469 
03470             rsprintf("<html><head>\n");
03471             rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
03472             rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
03473             rsprintf("<title>ELog Error</title></head>\n");
03474             rsprintf("<i>Error: Attachment file <i>%s</i> not valid.</i><p>\n",
03475                      getparam(str));
03476             rsprintf
03477                 ("Please go back and enter a proper filename (use the <b>Browse</b> button).\n");
03478             rsprintf("<body></body></html>\n");
03479             return;
03480          }
03481       }
03482    }
03483 
03484    /* add remote host name to author */
03485    phe = gethostbyaddr((char *) &remote_addr, 4, PF_INET);
03486    if (phe == NULL) {
03487       /* use IP number instead */
03488       strlcpy(str, (char *) inet_ntoa(remote_addr), sizeof(str));
03489    } else
03490       strlcpy(str, phe->h_name, sizeof(str));
03491 
03492    strlcpy(author, getparam("author"), sizeof(author));
03493    strlcat(author, "@", sizeof(author));
03494    strlcat(author, str, sizeof(author));
03495 
03496    tag[0] = 0;
03497    if (*getparam("edit"))
03498       strlcpy(tag, getparam("orig"), sizeof(tag));
03499 
03500    el_submit(atoi(getparam("run")), author, getparam("type"),
03501              getparam("system"), getparam("subject"), getparam("text"),
03502              getparam("orig"), *getparam("html") ? "HTML" : "plain",
03503              att_file[0], _attachment_buffer[0], _attachment_size[0],
03504              att_file[1], _attachment_buffer[1], _attachment_size[1],
03505              att_file[2], _attachment_buffer[2], _attachment_size[2], tag, sizeof(tag));
03506 
03507    /* supersede host name with "/Elog/Host name" */
03508    size = sizeof(host_name);
03509    db_get_value(hDB, 0, "/Elog/Host name", host_name, &size, TID_STRING, TRUE);
03510 
03511    if (tcp_port == 80)
03512       sprintf(mhttpd_full_url, "http://%s/", host_name);
03513    else
03514       sprintf(mhttpd_full_url, "http://%s:%d/", host_name, tcp_port);
03515 
03516    /* check for mail submissions */
03517    mail_param[0] = 0;
03518    n_mail = 0;
03519 
03520    for (index = 0; index <= 1; index++) {
03521       if (index == 0)
03522          sprintf(str, "/Elog/Email %s", getparam("type"));
03523       else
03524          sprintf(str, "/Elog/Email %s", getparam("system"));
03525 
03526       if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS) {
03527          size = sizeof(mail_list);
03528          db_get_data(hDB, hkey, mail_list, &size, TID_STRING);
03529 
03530          if (db_find_key(hDB, 0, "/Elog/SMTP host", &hkey) != DB_SUCCESS) {
03531             show_error("No SMTP host defined under /Elog/SMTP host");
03532             return;
03533          }
03534          size = sizeof(smtp_host);
03535          db_get_data(hDB, hkey, smtp_host, &size, TID_STRING);
03536 
03537          p = strtok(mail_list, ",");
03538          for (i = 0; p; i++) {
03539             strlcpy(mail_to, p, sizeof(mail_to));
03540 
03541             size = sizeof(str);
03542             str[0] = 0;
03543             db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
03544 
03545             sprintf(mail_from, "MIDAS %s <MIDAS@%s>", str, host_name);
03546 
03547             sprintf(mail_text, "A new entry has been submitted by %s:\n\n", author);
03548             sprintf(mail_text + strlen(mail_text), "Experiment : %s\n", str);
03549             sprintf(mail_text + strlen(mail_text), "Type       : %s\n", getparam("type"));
03550             sprintf(mail_text + strlen(mail_text), "System     : %s\n",
03551                     getparam("system"));
03552             sprintf(mail_text + strlen(mail_text), "Subject    : %s\n",
03553                     getparam("subject"));
03554 
03555             sprintf(mail_text + strlen(mail_text), "Link       : %sEL/%s\n",
03556                        mhttpd_full_url, tag);
03557 
03558             assert(strlen(mail_text) + 100 < sizeof(mail_text));        // bomb out on array overrun.
03559 
03560             strlcat(mail_text + strlen(mail_text), "\n", sizeof(mail_text));
03561             strlcat(mail_text + strlen(mail_text), getparam("text"),
03562                     sizeof(mail_text) - strlen(mail_text) - 50);
03563             strlcat(mail_text + strlen(mail_text), "\n", sizeof(mail_text));
03564 
03565             assert(strlen(mail_text) < sizeof(mail_text));      // bomb out on array overrun.
03566 
03567             sendmail(smtp_host, mail_from, mail_to, getparam("type"), mail_text);
03568 
03569             if (mail_param[0] == 0)
03570                strlcpy(mail_param, "?", sizeof(mail_param));
03571             else
03572                strlcat(mail_param, "&", sizeof(mail_param));
03573             sprintf(mail_param + strlen(mail_param), "mail%d=%s", n_mail++, mail_to);
03574 
03575             p = strtok(NULL, ",");
03576             if (!p)
03577                break;
03578             while (*p == ' ')
03579                p++;
03580          }
03581       }
03582    }
03583 
03584    for (i = 0; i < 3; i++)
03585       if (buffer[i])
03586          M_FREE(buffer[i]);
03587 
03588    rsprintf("HTTP/1.0 302 Found\r\n");
03589    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03590 
03591    if (mail_param[0])
03592       rsprintf("Location: ../EL/%s?%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
03593    else
03594       rsprintf("Location: ../EL/%s\n\n<html>redir</html>\r\n", tag);
03595 }
03596 
03597 /*------------------------------------------------------------------*/
03598 
03599 void submit_form()
03600 {
03601    char str[256], att_name[256];
03602    char text[10000];
03603    int i, n_att, size;
03604    HNDLE hDB, hkey, hkeyroot;
03605    KEY key;
03606 
03607    /* check for author */
03608    if (*getparam("author") == 0) {
03609       rsprintf("HTTP/1.0 200 Document follows\r\n");
03610       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03611       rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
03612 
03613       rsprintf("<html><head>\n");
03614       rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
03615       rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
03616       rsprintf("<title>ELog Error</title></head>\n");
03617       rsprintf("<i>Error: No author supplied.</i><p>\n");
03618       rsprintf("Please go back and enter your name in the <i>author</i> field.\n");
03619       rsprintf("<body></body></html>\n");
03620       return;
03621    }
03622 
03623    /* assemble text from form */
03624    cm_get_experiment_database(&hDB, NULL);
03625    sprintf(str, "/Elog/Forms/%s", getparam("form"));
03626    db_find_key(hDB, 0, str, &hkeyroot);
03627    text[0] = 0;
03628    n_att = 0;
03629    if (hkeyroot)
03630       for (i = 0;; i++) {
03631          db_enum_link(hDB, hkeyroot, i, &hkey);
03632          if (!hkey)
03633             break;
03634 
03635          db_get_key(hDB, hkey, &key);
03636 
03637          strlcpy(str, key.name, sizeof(str));
03638          if (str[0])
03639             str[strlen(str) - 1] = 0;
03640          if (equal_ustring(str, "attachment")) {
03641             /* generate attachments */
03642             size = sizeof(str);
03643             db_get_data(hDB, hkey, str, &size, TID_STRING);
03644             _attachment_size[n_att] = 0;
03645             sprintf(att_name, "attachment%d", n_att++);
03646 
03647             sprintf(str, "c%d", i);
03648             setparam(att_name, getparam(str));
03649          } else {
03650             sprintf(str, "x%d", i);
03651             sprintf(text + strlen(text), "%d %s : [%c]  ", i + 1, key.name,
03652                     *getparam(str) == '1' ? 'X' : ' ');
03653             sprintf(str, "c%d", i);
03654             sprintf(text + strlen(text), "%s\n", getparam(str));
03655          }
03656       }
03657 
03658    /* set parameters for submit_elog() */
03659    setparam("type", getparam("form"));
03660    setparam("system", "General");
03661    setparam("subject", getparam("form"));
03662    setparam("text", text);
03663    setparam("orig", "");
03664    setparam("html", "");
03665 
03666    submit_elog();
03667 }
03668 
03669 /*------------------------------------------------------------------*/
03670 
03671 void show_elog_page(char *path, int path_size)
03672 {
03673    int size, i, run, msg_status, status, fh, length, first_message, last_message, index,
03674       fsize;
03675    char str[256], orig_path[256], command[80], ref[256], file_name[256], dir[256], *fbuffer;
03676    char date[80], author[80], type[80], system[80], subject[256], text[10000],
03677        orig_tag[80], reply_tag[80], attachment[3][256], encoding[80], att[256], url[256];
03678    HNDLE hDB, hkey, hkeyroot, hkeybutton;
03679    KEY key;
03680    FILE *f;
03681    BOOL display_run_number, allow_delete;
03682    time_t now;
03683    struct tm *tms;
03684    char def_button[][NAME_LENGTH] = { "8h", "24h", "7d" };
03685 
03686    /* get flag for displaying run number and allow delete */
03687    cm_get_experiment_database(&hDB, NULL);
03688    display_run_number = TRUE;
03689    allow_delete = FALSE;
03690    size = sizeof(BOOL);
03691    db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL,
03692                 TRUE);
03693    db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
03694 
03695    /*---- interprete commands ---------------------------------------*/
03696 
03697    strlcpy(command, getparam("cmd"), sizeof(command));
03698 
03699    if (*getparam("form")) {
03700       if (*getparam("type")) {
03701          sprintf(str, "EL/?form=%s", getparam("form"));
03702          redirect(str);
03703          return;
03704       }
03705       if (equal_ustring(command, "submit"))
03706          submit_form();
03707       else
03708          show_form_query();
03709       return;
03710    }
03711 
03712    if (equal_ustring(command, "new")) {
03713       if (*getparam("file"))
03714          show_elog_new(NULL, FALSE, getparam("file"), NULL);
03715       else
03716          show_elog_new(NULL, FALSE, NULL, NULL);
03717       return;
03718    }
03719 
03720    if (equal_ustring(command, "Create ELog from this page")) {
03721 
03722       size = sizeof(url);
03723       if (db_get_value(hDB, 0, "/Elog/URL", url, &size, TID_STRING, FALSE) == DB_SUCCESS) {
03724 
03725          get_elog_url(url, sizeof(url));
03726 
03727          /*---- use external ELOG ----*/
03728          fsize = 100000;
03729          fbuffer = (char*)M_MALLOC(fsize);
03730          assert(fbuffer != NULL);
03731 
03732          /* write ODB contents to buffer */
03733          gen_odb_attachment(path, fbuffer);
03734          fsize = strlen(fbuffer);
03735 
03736          /* save temporary file */
03737          size = sizeof(dir);
03738          dir[0] = 0;
03739          db_get_value(hDB, 0, "/Elog/Logbook Dir", dir, &size, TID_STRING, TRUE);
03740          if (strlen(dir) > 0 && dir[strlen(dir)-1] != DIR_SEPARATOR)
03741             strlcat(dir, DIR_SEPARATOR_STR, sizeof(dir));
03742 
03743          time(&now);
03744          tms = localtime(&now);
03745 
03746          if (strchr(path, '/'))
03747             strlcpy(str, strrchr(path, '/') + 1, sizeof(str));
03748          else
03749             strlcpy(str, path, sizeof(str));
03750          sprintf(file_name, "%02d%02d%02d_%02d%02d%02d_%s.html",
03751                   tms->tm_year % 100, tms->tm_mon + 1, tms->tm_mday,
03752                   tms->tm_hour, tms->tm_min, tms->tm_sec, str);
03753          sprintf(str, "%s%s", dir, file_name);
03754 
03755          /* save attachment */
03756          fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
03757          if (fh < 0) {
03758             cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\"",
03759                      str);
03760          } else {
03761             write(fh, fbuffer, fsize);
03762             close(fh);
03763          }
03764 
03765          /* redirect to ELOG */
03766          if (strlen(url) > 1 && url[strlen(url)-1] != '/')
03767             strlcat(url, "/", sizeof(url));
03768          strlcat(url, "?cmd=New&fa=", sizeof(url));
03769          strlcat(url, file_name, sizeof(url));
03770          redirect(url);
03771 
03772          M_FREE(fbuffer);
03773          return;
03774       
03775       } else {
03776 
03777          char action_path[256];
03778 
03779          action_path[0] = 0;
03780 
03781          strlcpy(str, path, sizeof(str));
03782          while (strchr(path, '/')) {
03783             *strchr(path, '/') = '\\';
03784             strlcat(action_path, "../", sizeof(action_path));
03785          }
03786 
03787          strlcat(action_path, "EL/", sizeof(action_path));
03788 
03789          show_elog_new(NULL, FALSE, path, action_path);
03790          return;
03791       }
03792    }
03793 
03794    if (equal_ustring(command, "edit")) {
03795       show_elog_new(path, TRUE, NULL, NULL);
03796       return;
03797    }
03798 
03799    if (equal_ustring(command, "reply")) {
03800       show_elog_new(path, FALSE, NULL, NULL);
03801       return;
03802    }
03803 
03804    if (equal_ustring(command, "submit")) {
03805       submit_elog();
03806       return;
03807    }
03808 
03809    if (equal_ustring(command, "query")) {
03810       show_elog_query();
03811       return;
03812    }
03813 
03814    if (equal_ustring(command, "submit query")) {
03815       show_elog_submit_query(0);
03816       return;
03817    }
03818 
03819    if (strncmp(command, "Last ", 5) == 0) {
03820       if (command[strlen(command) - 1] == 'h')
03821          sprintf(str, "last%d", atoi(command + 5));
03822       else if (command[strlen(command) - 1] == 'd')
03823          sprintf(str, "last%d", atoi(command + 5) * 24);
03824 
03825       redirect(str);
03826       return;
03827    }
03828 
03829    if (equal_ustring(command, "delete")) {
03830       show_elog_delete(path);
03831       return;
03832    }
03833 
03834    if (strncmp(path, "last", 4) == 0) {
03835       show_elog_submit_query(atoi(path + 4));
03836       return;
03837    }
03838 
03839    if (equal_ustring(command, "runlog")) {
03840       sprintf(str, "runlog.txt");
03841       redirect(str);
03842       return;
03843    }
03844 
03845   /*---- check if file requested -----------------------------------*/
03846 
03847    if (strlen(path) > 13 && path[6] == '_' && path[13] == '_') {
03848       cm_get_experiment_database(&hDB, NULL);
03849       file_name[0] = 0;
03850       if (hDB > 0) {
03851          size = sizeof(file_name);
03852          memset(file_name, 0, size);
03853 
03854          status =
03855              db_get_value(hDB, 0, "/Logger/Elog dir", file_name, &size, TID_STRING,
03856                           FALSE);
03857          if (status != DB_SUCCESS)
03858             db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
03859 
03860          if (file_name[0] != 0)
03861             if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
03862                strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
03863       }
03864       strlcat(file_name, path, sizeof(file_name));
03865 
03866       fh = open(file_name, O_RDONLY | O_BINARY);
03867       if (fh > 0) {
03868          lseek(fh, 0, SEEK_END);
03869          length = TELL(fh);
03870          lseek(fh, 0, SEEK_SET);
03871 
03872          rsprintf("HTTP/1.0 200 Document follows\r\n");
03873          rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
03874          rsprintf("Accept-Ranges: bytes\r\n");
03875 
03876          /* return proper header for file type */
03877          for (i = 0; i < (int) strlen(path); i++)
03878             str[i] = toupper(path[i]);
03879          str[i] = 0;
03880 
03881          for (i = 0; filetype[i].ext[0]; i++)
03882             if (strstr(str, filetype[i].ext))
03883                break;
03884 
03885          if (filetype[i].ext[0])
03886             rsprintf("Content-Type: %s\r\n", filetype[i].type);
03887          else if (strchr(str, '.') == NULL)
03888             rsprintf("Content-Type: text/plain\r\n");
03889          else
03890             rsprintf("Content-Type: application/octet-stream\r\n");
03891 
03892          rsprintf("Content-Length: %d\r\n\r\n", length);
03893 
03894          /* return if file too big */
03895          if (length > (int) (sizeof(return_buffer) - strlen(return_buffer))) {
03896             printf("return buffer too small\n");
03897             close(fh);
03898             return;
03899          }
03900 
03901          return_length = strlen(return_buffer) + length;
03902          read(fh, return_buffer + strlen(return_buffer), length);
03903 
03904          close(fh);
03905       }
03906 
03907       return;
03908    }
03909 
03910   /*---- check if runlog is requested ------------------------------*/
03911 
03912    if (path[0] > '9') {
03913       show_rawfile(path);
03914       return;
03915    }
03916 
03917   /*---- check next/previous message -------------------------------*/
03918 
03919    last_message = first_message = FALSE;
03920    if (equal_ustring(command, "next") || equal_ustring(command, "previous")
03921        || equal_ustring(command, "last")) {
03922       strlcpy(orig_path, path, sizeof(orig_path));
03923 
03924       if (equal_ustring(command, "last"))
03925          path[0] = 0;
03926 
03927       do {
03928          strlcat(path, equal_ustring(command, "next") ? "+1" : "-1", path_size);
03929          status = el_search_message(path, &fh, TRUE);
03930          close(fh);
03931          if (status != EL_SUCCESS) {
03932             if (equal_ustring(command, "next"))
03933                last_message = TRUE;
03934             else
03935                first_message = TRUE;
03936             strlcpy(path, orig_path, path_size);
03937             break;
03938          }
03939 
03940          size = sizeof(text);
03941          el_retrieve(path, date, &run, author, type, system, subject,
03942                      text, &size, orig_tag, reply_tag, attachment[0], attachment[1],
03943                      attachment[2], encoding);
03944 
03945          if (strchr(author, '@'))
03946             *strchr(author, '@') = 0;
03947          if (*getparam("lauthor") == '1' && !equal_ustring(getparam("author"), author))
03948             continue;
03949          if (*getparam("ltype") == '1' && !equal_ustring(getparam("type"), type))
03950             continue;
03951          if (*getparam("lsystem") == '1' && !equal_ustring(getparam("system"), system))
03952             continue;
03953          if (*getparam("lsubject") == '1') {
03954             strlcpy(str, getparam("subject"), sizeof(str));
03955             for (i = 0; i < (int) strlen(str); i++)
03956                str[i] = toupper(str[i]);
03957             for (i = 0; i < (int) strlen(subject); i++)
03958                subject[i] = toupper(subject[i]);
03959 
03960             if (strstr(subject, str) == NULL)
03961                continue;
03962          }
03963 
03964          sprintf(str, "%s", path);
03965 
03966          if (*getparam("lauthor") == '1') {
03967             if (strchr(str, '?') == NULL)
03968                strlcat(str, "?lauthor=1", sizeof(str));
03969             else
03970                strlcat(str, "&lauthor=1", sizeof(str));
03971          }
03972 
03973          if (*getparam("ltype") == '1') {
03974             if (strchr(str, '?') == NULL)
03975                strlcat(str, "?ltype=1", sizeof(str));
03976             else
03977                strlcat(str, "&ltype=1", sizeof(str));
03978          }
03979 
03980          if (*getparam("lsystem") == '1') {
03981             if (strchr(str, '?') == NULL)
03982                strlcat(str, "?lsystem=1", sizeof(str));
03983             else
03984                strlcat(str, "&lsystem=1", sizeof(str));
03985          }
03986 
03987          if (*getparam("lsubject") == '1') {
03988             if (strchr(str, '?') == NULL)
03989                strlcat(str, "?lsubject=1", sizeof(str));
03990             else
03991                strlcat(str, "&lsubject=1", sizeof(str));
03992          }
03993 
03994          redirect(str);
03995          return;
03996 
03997       } while (TRUE);
03998    }
03999 
04000    /*---- get current message ---------------------------------------*/
04001 
04002    size = sizeof(text);
04003    strlcpy(str, path, sizeof(str));
04004    subject[0] = 0;
04005    msg_status = el_retrieve(str, date, &run, author, type, system, subject,
04006                             text, &size, orig_tag, reply_tag,
04007                             attachment[0], attachment[1], attachment[2], encoding);
04008 
04009    /* header */
04010    rsprintf("HTTP/1.0 200 Document follows\r\n");
04011    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
04012    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
04013 
04014    rsprintf("<html><head>\n");
04015    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
04016    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
04017    rsprintf("<title>MIDAS ELog - %s</title></head>\n", subject);
04018    rsprintf("<body><form method=\"GET\" action=\"../EL/%s\">\n", str);
04019 
04020    rsprintf("<table cols=2 border=2 cellpadding=2>\n");
04021 
04022    /*---- title row ----*/
04023 
04024    size = sizeof(str);
04025    str[0] = 0;
04026    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
04027 
04028    rsprintf("<tr><th bgcolor=#A0A0FF>MIDAS Electronic Logbook");
04029    if (elog_mode)
04030       rsprintf("<th bgcolor=#A0A0FF>Logbook \"%s\"</tr>\n", str);
04031    else
04032       rsprintf("<th bgcolor=#A0A0FF>Experiment \"%s\"</tr>\n", str);
04033 
04034    /*---- menu buttons ----*/
04035 
04036    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
04037    rsprintf("<input type=submit name=cmd value=New>\n");
04038    rsprintf("<input type=submit name=cmd value=Edit>\n");
04039    if (allow_delete)
04040       rsprintf("<input type=submit name=cmd value=Delete>\n");
04041    rsprintf("<input type=submit name=cmd value=Reply>\n");
04042    rsprintf("<input type=submit name=cmd value=Query>\n");
04043 
04044    /* check forms from ODB */
04045    db_find_key(hDB, 0, "/Elog/Forms", &hkeyroot);
04046    if (hkeyroot)
04047       for (i = 0;; i++) {
04048          db_enum_link(hDB, hkeyroot, i, &hkey);
04049          if (!hkey)
04050             break;
04051 
04052          db_get_key(hDB, hkey, &key);
04053 
04054          rsprintf("<input type=submit name=form value=\"%s\">\n", key.name);
04055       }
04056 
04057    rsprintf("<input type=submit name=cmd value=Runlog>\n");
04058 
04059    if (!elog_mode)
04060       rsprintf("<input type=submit name=cmd value=Status>\n");
04061    rsprintf("</tr>\n");
04062 
04063    /* "last x" button row */
04064    rsprintf("<tr><td colspan=2 bgcolor=#D0D0D0>\n");
04065 
04066    db_find_key(hDB, 0, "/Elog/Buttons", &hkeybutton);
04067    if (hkeybutton == 0) {
04068       /* create default buttons */
04069       db_create_key(hDB, 0, "/Elog/Buttons", TID_STRING);
04070       db_find_key(hDB, 0, "/Elog/Buttons", &hkeybutton);
04071       assert(hkeybutton);
04072       db_set_data(hDB, hkeybutton, def_button, sizeof(def_button), 3, TID_STRING);
04073    }
04074 
04075    db_get_key(hDB, hkeybutton, &key);
04076 
04077    for (i = 0; i < key.num_values; i++) {
04078       size = sizeof(str);
04079       db_get_data_index(hDB, hkeybutton, str, &size, i, TID_STRING);
04080       rsprintf("<input type=submit name=cmd value=\"Last %s\">\n", str);
04081    }
04082 
04083    rsprintf("</tr>\n");
04084 
04085    rsprintf("<tr><td colspan=2 bgcolor=#E0E0E0>");
04086    rsprintf("<input type=submit name=cmd value=Next>\n");
04087    rsprintf("<input type=submit name=cmd value=Previous>\n");
04088    rsprintf("<input type=submit name=cmd value=Last>\n");
04089    rsprintf("<i>Check a category to browse only entries from that category</i>\n");
04090    rsprintf("</tr>\n\n");
04091 
04092    if (msg_status != EL_FILE_ERROR && (reply_tag[0] || orig_tag[0])) {
04093       rsprintf("<tr><td colspan=2 bgcolor=#F0F0F0>");
04094       if (orig_tag[0]) {
04095          sprintf(ref, "/EL/%s", orig_tag);
04096          rsprintf("  <a href=\"%s\">Original message</a>  ", ref);
04097       }
04098       if (reply_tag[0]) {
04099          sprintf(ref, "/EL/%s", reply_tag);
04100          rsprintf("  <a href=\"%s\">Reply to this message</a>  ", ref);
04101       }
04102       rsprintf("</tr>\n");
04103    }
04104 
04105   /*---- message ----*/
04106 
04107    if (msg_status == EL_FILE_ERROR)
04108       rsprintf
04109           ("<tr><td bgcolor=#FF0000 colspan=2 align=center><h1>No message available</h1></tr>\n");
04110    else {
04111       if (last_message)
04112          rsprintf
04113              ("<tr><td bgcolor=#FF0000 colspan=2 align=center><b>This is the last message in the ELog</b></tr>\n");
04114 
04115       if (first_message)
04116          rsprintf
04117              ("<tr><td bgcolor=#FF0000 colspan=2 align=center><b>This is the first message in the ELog</b></tr>\n");
04118 
04119       /* check for mail submissions */
04120       for (i = 0;; i++) {
04121          sprintf(str, "mail%d", i);
04122          if (*getparam(str)) {
04123             if (i == 0)
04124                rsprintf("<tr><td colspan=2 bgcolor=#FFC020>");
04125             rsprintf("Mail sent to <b>%s</b><br>\n", getparam(str));
04126          } else
04127             break;
04128       }
04129       if (i > 0)
04130          rsprintf("</tr>\n");
04131 
04132 
04133       if (display_run_number) {
04134          rsprintf("<tr><td bgcolor=#FFFF00>Entry date: <b>%s</b>", date);
04135 
04136          rsprintf("<td bgcolor=#FFFF00>Run number: <b>%d</b></tr>\n\n", run);
04137       } else
04138          rsprintf("<tr><td colspan=2 bgcolor=#FFFF00>Entry date: <b>%s</b></tr>\n\n",
04139                   date);
04140 
04141 
04142       /* define hidded fields */
04143       strlcpy(str, author, sizeof(str));
04144       if (strchr(str, '@'))
04145          *strchr(str, '@') = 0;
04146       rsprintf("<input type=hidden name=author  value=\"%s\">\n", str);
04147       rsprintf("<input type=hidden name=type    value=\"%s\">\n", type);
04148       rsprintf("<input type=hidden name=system  value=\"%s\">\n", system);
04149       rsprintf("<input type=hidden name=subject value=\"%s\">\n\n", subject);
04150 
04151       if (*getparam("lauthor") == '1')
04152          rsprintf
04153              ("<tr><td bgcolor=#FFA0A0><input type=\"checkbox\" checked name=\"lauthor\" value=\"1\">");
04154       else
04155          rsprintf
04156              ("<tr><td bgcolor=#FFA0A0><input type=\"checkbox\" name=\"lauthor\" value=\"1\">");
04157       rsprintf("  Author: <b>%s</b>\n", author);
04158 
04159       if (*getparam("ltype") == '1')
04160          rsprintf
04161              ("<td bgcolor=#FFA0A0><input type=\"checkbox\" checked name=\"ltype\" value=\"1\">");
04162       else
04163          rsprintf
04164              ("<td bgcolor=#FFA0A0><input type=\"checkbox\" name=\"ltype\" value=\"1\">");
04165       rsprintf("  Type: <b>%s</b></tr>\n", type);
04166 
04167       if (*getparam("lsystem") == '1')
04168          rsprintf
04169              ("<tr><td bgcolor=#A0FFA0><input type=\"checkbox\" checked name=\"lsystem\" value=\"1\">");
04170       else
04171          rsprintf
04172              ("<tr><td bgcolor=#A0FFA0><input type=\"checkbox\" name=\"lsystem\" value=\"1\">");
04173 
04174       rsprintf("  System: <b>%s</b>\n", system);
04175 
04176       if (*getparam("lsubject") == '1')
04177          rsprintf
04178              ("<td bgcolor=#A0FFA0><input type=\"checkbox\" checked name=\"lsubject\" value=\"1\">");
04179       else
04180          rsprintf
04181              ("<td bgcolor=#A0FFA0><input type=\"checkbox\" name=\"lsubject\" value=\"1\">");
04182       rsprintf("  Subject: <b>%s</b></tr>\n", subject);
04183 
04184 
04185       /* message text */
04186       rsprintf("<tr><td colspan=2>\n");
04187       if (equal_ustring(encoding, "plain")) {
04188          rsputs("<pre>");
04189          rsputs2(text);
04190          rsputs("</pre>");
04191       } else
04192          rsputs(text);
04193       rsputs("</tr>\n");
04194 
04195       for (index = 0; index < 3; index++) {
04196          if (attachment[index][0]) {
04197             char ref1[256];
04198 
04199             for (i = 0; i < (int) strlen(attachment[index]); i++)
04200                att[i] = toupper(attachment[index][i]);
04201             att[i] = 0;
04202 
04203             strlcpy(ref1, attachment[index], sizeof(ref1));
04204             urlEncode(ref1, sizeof(ref1));
04205                   
04206             sprintf(ref, "/EL/%s", ref1);
04207 
04208             if (strstr(att, ".GIF") || strstr(att, ".PNG") || strstr(att, ".JPG")) {
04209                rsprintf
04210                    ("<tr><td colspan=2>Attachment: <a href=\"%s\"><b>%s</b></a><br>\n",
04211                     ref, attachment[index] + 14);
04212                rsprintf("<img src=\"%s\"></tr>", ref);
04213             } else {
04214                rsprintf
04215                    ("<tr><td colspan=2 bgcolor=#C0C0FF>Attachment: <a href=\"%s\"><b>%s</b></a>\n",
04216                     ref, attachment[index] + 14);
04217                if (strstr(att, ".TXT") || strstr(att, ".ASC") || strchr(att, '.') == NULL) {
04218                   /* display attachment */
04219                   rsprintf("<br>");
04220                   if (!strstr(att, ".HTML"))
04221                      rsprintf("<pre>");
04222 
04223                   file_name[0] = 0;
04224                   size = sizeof(file_name);
04225                   memset(file_name, 0, size);
04226                   db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING,
04227                                TRUE);
04228                   if (file_name[0] != 0)
04229                      if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
04230                         strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
04231                   strlcat(file_name, attachment[index], sizeof(file_name));
04232 
04233                   f = fopen(file_name, "rt");
04234                   if (f != NULL) {
04235                      while (!feof(f)) {
04236                         str[0] = 0;
04237                         fgets(str, sizeof(str), f);
04238                         if (!strstr(att, ".HTML"))
04239                            rsputs2(str);
04240                         else
04241                            rsputs(str);
04242                      }
04243                      fclose(f);
04244                   }
04245 
04246                   if (!strstr(att, ".HTML"))
04247                      rsprintf("</pre>");
04248                   rsprintf("\n");
04249                }
04250                rsprintf("</tr>\n");
04251             }
04252          }
04253       }
04254    }
04255 
04256    rsprintf("</table>\n");
04257    rsprintf("</body></html>\r\n");
04258 }
04259 
04260 /*------------------------------------------------------------------*/
04261 
04262 void get_elog_url(char *url, int len)
04263 {
04264    HNDLE hDB;
04265    char str[256], str2[256], *p;
04266    int size;
04267 
04268    /* redirect to external ELOG if URL present */
04269    cm_get_experiment_database(&hDB, NULL);
04270    size = sizeof(str);
04271    if (db_get_value(hDB, 0, "/Elog/URL", str, &size, TID_STRING, FALSE) == DB_SUCCESS) {
04272       if (str[0] == ':') {
04273          strcpy(str2, referer);
04274          while ((p = strrchr(str2, '/')) != NULL && p > str2 && *(p-1) != '/')
04275             *p = 0;
04276          if (strrchr(str2+5, ':'))
04277             *strrchr(str2+5, ':') = 0;
04278          if (str2[strlen(str2)-1] == '/')
04279             str2[strlen(str2)-1] = 0;
04280          sprintf(url, "%s%s", str2, str);
04281       } else
04282          strlcpy(url, str, len);
04283    } else
04284       strlcpy(url, "EL/", len);
04285 }
04286 
04287 /*------------------------------------------------------------------*/
04288 
04289 BOOL is_editable(char *eq_name, char *var_name)
04290 {
04291    HNDLE hDB, hkey;
04292    KEY key;
04293    char str[256];
04294    int i, size;
04295 
04296    cm_get_experiment_database(&hDB, NULL);
04297    sprintf(str, "/Equipment/%s/Settings/Editable", eq_name);
04298    db_find_key(hDB, 0, str, &hkey);
04299 
04300    /* if no editable entry found, use default */
04301    if (!hkey) {
04302       return (equal_ustring(var_name, "Demand") ||
04303               equal_ustring(var_name, "Output") || strncmp(var_name, "D_", 2) == 0);
04304    }
04305 
04306    db_get_key(hDB, hkey, &key);
04307    for (i = 0; i < key.num_values; i++) {
04308       size = sizeof(str);
04309       db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
04310       if (equal_ustring(var_name, str))
04311          return TRUE;
04312    }
04313    return FALSE;
04314 }
04315 
04316 void show_sc_page(char *path, int refresh)
04317 {
04318    int i, j, k, colspan, size, n_var, i_edit, i_set;
04319    char str[256], eq_name[32], group[32], name[32], ref[256];
04320    char group_name[MAX_GROUPS][32], data[256], back_path[256], *p;
04321    HNDLE hDB, hkey, hkeyeq, hkeyset, hkeynames, hkeyvar, hkeyroot;
04322    KEY eqkey, key, varkey;
04323    char data_str[256], hex_str[256];
04324 
04325    cm_get_experiment_database(&hDB, NULL);
04326 
04327    /* check if variable to edit */
04328    i_edit = -1;
04329    if (equal_ustring(getparam("cmd"), "Edit"))
04330       i_edit = atoi(getparam("index"));
04331 
04332    /* check if variable to set */
04333    i_set = -1;
04334    if (equal_ustring(getparam("cmd"), "Set"))
04335       i_set = atoi(getparam("index"));
04336 
04337    /* split path into equipment and group */
04338    strlcpy(eq_name, path, sizeof(eq_name));
04339    strlcpy(group, "All", sizeof(group));
04340    if (strchr(eq_name, '/')) {
04341       strlcpy(group, strchr(eq_name, '/') + 1, sizeof(group));
04342       *strchr(eq_name, '/') = 0;
04343    }
04344 
04345    back_path[0] = 0;
04346    for (p=path ; *p ; p++)
04347       if (*p == '/')
04348          strlcat(back_path, "../", sizeof(back_path));
04349 
04350    /* check for "names" in settings */
04351    if (eq_name[0]) {
04352       sprintf(str, "/Equipment/%s/Settings", eq_name);
04353       db_find_key(hDB, 0, str, &hkeyset);
04354       hkeynames = 0;
04355       if (hkeyset) {
04356          for (i = 0;; i++) {
04357             db_enum_link(hDB, hkeyset, i, &hkeynames);
04358 
04359             if (!hkeynames)
04360                break;
04361 
04362             db_get_key(hDB, hkeynames, &key);
04363 
04364             if (strncmp(key.name, "Names", 5) == 0)
04365                break;
04366          }
04367       }
04368 
04369       /* redirect if no names found */
04370       if (!hkeyset || !hkeynames) {
04371          /* redirect */
04372          sprintf(str, "../Equipment/%s/Variables", eq_name);
04373          redirect(str);
04374          return;
04375       }
04376    }
04377 
04378    sprintf(str, "%s", group);
04379    show_header(hDB, "MIDAS slow control", "GET", str, 8, i_edit == -1 ? refresh : 0);
04380 
04381    /*---- menu buttons ----*/
04382 
04383    rsprintf("<tr><td colspan=15 bgcolor=#C0C0C0>\n");
04384 
04385    if (equal_ustring(getparam("cmd"), "Edit"))
04386       rsprintf("<input type=submit name=cmd value=Set>\n");
04387    else {
04388       rsprintf("<input type=submit name=cmd value=ODB>\n");
04389       rsprintf("<input type=submit name=cmd value=Status>\n");
04390       rsprintf("<input type=submit name=cmd value=Help>\n");
04391    }
04392    rsprintf("</tr>\n\n");
04393 
04394    /*---- enumerate SC equipment ----*/
04395 
04396    rsprintf("<tr><td colspan=15 bgcolor=#FFFF00><i>Equipment:</i> &nbsp;&nbsp;\n");
04397 
04398    db_find_key(hDB, 0, "/Equipment", &hkey);
04399    if (hkey)
04400       for (i = 0;; i++) {
04401          db_enum_link(hDB, hkey, i, &hkeyeq);
04402 
04403          if (!hkeyeq)
04404             break;
04405 
04406          db_get_key(hDB, hkeyeq, &eqkey);
04407 
04408          db_find_key(hDB, hkeyeq, "Settings", &hkeyset);
04409          if (hkeyset) {
04410             for (j = 0;; j++) {
04411                db_enum_link(hDB, hkeyset, j, &hkeynames);
04412 
04413                if (!hkeynames)
04414                   break;
04415 
04416                db_get_key(hDB, hkeynames, &key);
04417 
04418                if (strncmp(key.name, "Names", 5) == 0) {
04419                   if (equal_ustring(eq_name, eqkey.name))
04420                      rsprintf("<b>%s</b> &nbsp;&nbsp;", eqkey.name);
04421                   else {
04422                      rsprintf("<a href=\"%s%s\">%s</a> &nbsp;&nbsp;", 
04423                                  back_path, eqkey.name, eqkey.name);
04424                   }
04425                   break;
04426                }
04427             }
04428          }
04429       }
04430    rsprintf("</tr>\n");
04431 
04432    if (!eq_name[0]) {
04433       rsprintf("</table>");
04434       return;
04435    }
04436 
04437    /*---- display SC ----*/
04438 
04439    n_var = 0;
04440    sprintf(str, "/Equipment/%s/Settings/Names", eq_name);
04441    db_find_key(hDB, 0, str, &hkey);
04442 
04443    if (hkey) {
04444 
04445       /*---- single name array ----*/
04446       rsprintf("<tr><td colspan=15 bgcolor=#FFFFA0><i>Groups:</i> &nbsp;&nbsp;");
04447 
04448       /* "all" group */
04449       if (equal_ustring(group, "All"))
04450          rsprintf("<b>All</b> &nbsp;&nbsp;");
04451       else
04452          rsprintf("<a href=\"%s%s/All\">All</a> &nbsp;&nbsp;", back_path, eq_name);
04453 
04454       /* collect groups */
04455 
04456       memset(group_name, 0, sizeof(group_name));
04457       db_get_key(hDB, hkey, &key);
04458 
04459       for (int level = 0; ; level++) {
04460          bool next_level = false;
04461          for (i = 0; i < key.num_values; i++) {
04462             size = sizeof(str);
04463             db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
04464             
04465             char *s = strchr(str, '%');
04466             for (int k=0; s && k<level; k++)
04467                s = strchr(s+1, '%');
04468 
04469             if (s) {
04470                *s = 0;
04471                if (strchr(s+1, '%'))
04472                    next_level = true;
04473 
04474                //printf("try group [%s] name [%s], level %d, %d\n", str, s+1, level, next_level);
04475 
04476                for (j = 0; j < MAX_GROUPS; j++) {
04477                   if (equal_ustring(group_name[j], str) || group_name[j][0] == 0)
04478                      break;
04479                }
04480                if (group_name[j][0] == 0)
04481                   strlcpy(group_name[j], str, sizeof(group_name[0]));
04482             }
04483          }
04484 
04485          if (!next_level)
04486             break;
04487       }
04488 
04489       for (i = 0; i < MAX_GROUPS && group_name[i][0]; i++) {
04490          if (equal_ustring(group_name[i], group))
04491             rsprintf("<b>%s</b> &nbsp;&nbsp;", group_name[i]);
04492          else {
04493             char s[256];
04494             strlcpy(s, group_name[i], sizeof(s));
04495             urlEncode(s, sizeof(s));
04496             rsprintf("<a href=\"%s%s/%s\">%s</a> &nbsp;&nbsp;", back_path, eq_name,
04497                         s, group_name[i]);
04498          }
04499       }
04500       rsprintf("</tr>\n");
04501 
04502       /* count variables */
04503       sprintf(str, "/Equipment/%s/Variables", eq_name);
04504       db_find_key(hDB, 0, str, &hkeyvar);
04505       if (!hkeyvar) {
04506          rsprintf("</table>");
04507          return;
04508       }
04509       for (i = 0;; i++) {
04510          db_enum_link(hDB, hkeyvar, i, &hkey);
04511          if (!hkey)
04512             break;
04513       }
04514 
04515       if (i == 0 || i > 15) {
04516          rsprintf("</table>");
04517          return;
04518       }
04519 
04520       /* title row */
04521       colspan = 15 - i;
04522       rsprintf("<tr><th colspan=%d>Names", colspan);
04523 
04524       /* display entries for this group */
04525       for (i = 0;; i++) {
04526          db_enum_link(hDB, hkeyvar, i, &hkey);
04527 
04528          if (!hkey)
04529             break;
04530 
04531          db_get_key(hDB, hkey, &key);
04532          rsprintf("<th>%s", key.name);
04533       }
04534 
04535       rsprintf("</tr>\n");
04536 
04537       /* data for current group */
04538       sprintf(str, "/Equipment/%s/Settings/Names", eq_name);
04539       db_find_key(hDB, 0, str, &hkeyset);
04540       assert(hkeyset);
04541       db_get_key(hDB, hkeyset, &key);
04542       for (i = 0; i < key.num_values; i++) {
04543          size = sizeof(str);
04544          db_get_data_index(hDB, hkeyset, str, &size, i, TID_STRING);
04545 
04546          strlcpy(name, str, sizeof(name));
04547 
04548          //printf("group [%s], name [%s], str [%s]\n", group, name, str);
04549 
04550          if (!equal_ustring(group, "All")) {
04551             // check if name starts with the name of the group we want to display
04552             char *s = strstr(name, group);
04553             if (s != name)
04554                continue;
04555             if (name[strlen(group)] != '%')
04556                continue;
04557          }
04558 
04559          if (strlen(name) < 1)
04560             sprintf(name, "[%d]", i);
04561 
04562          rsprintf("<tr><td colspan=%d>%s", colspan, name);
04563 
04564          for (j = 0;; j++) {
04565             db_enum_link(hDB, hkeyvar, j, &hkey);
04566             if (!hkey)
04567                break;
04568             db_get_key(hDB, hkey, &varkey);
04569 
04570             /* check if "variables" array is shorter than the "names" array */
04571             if (i >= varkey.num_values)
04572                continue;
04573 
04574             size = sizeof(data);
04575             db_get_data_index(hDB, hkey, data, &size, i, varkey.type);
04576             db_sprintf(str, data, varkey.item_size, 0, varkey.type);
04577 
04578             if (is_editable(eq_name, varkey.name)) {
04579                if (n_var == i_set) {
04580                   /* set value */
04581                   strlcpy(str, getparam("value"), sizeof(str));
04582                   db_sscanf(str, data, &size, 0, varkey.type);
04583                   db_set_data_index(hDB, hkey, data, size, i, varkey.type);
04584 
04585                   /* redirect (so that 'reload' does not reset value) */
04586                   strlen_retbuf = 0;
04587                   sprintf(str, "%s", group);
04588                   redirect(str);
04589                   return;
04590                }
04591                if (n_var == i_edit) {
04592                   rsprintf
04593                       ("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n",
04594                        str);
04595                   rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
04596                   rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
04597                   n_var++;
04598                } else {
04599                   sprintf(ref, "%s/%s?cmd=Edit&index=%d", eq_name, group, n_var);
04600 
04601                   rsprintf("<td align=center><a href=\"%s%s\">%s</a>", back_path, ref, str);
04602                   n_var++;
04603                }
04604             } else
04605                rsprintf("<td align=center>%s", str);
04606          }
04607 
04608          rsprintf("</tr>\n");
04609       }
04610    } else {
04611       /*---- multiple name arrays ----*/
04612       rsprintf("<tr><td colspan=15 bgcolor=#FFFFA0><i>Groups:</i> ");
04613 
04614       /* "all" group */
04615       if (equal_ustring(group, "All"))
04616          rsprintf("<b>All</b> &nbsp;&nbsp;");
04617       else
04618          rsprintf("<a href=\"%s%s\">All</a> &nbsp;&nbsp;\n", back_path, eq_name);
04619 
04620       /* groups from Variables tree */
04621 
04622       sprintf(str, "/Equipment/%s/Variables", eq_name);
04623       db_find_key(hDB, 0, str, &hkeyvar);
04624       assert(hkeyvar);
04625 
04626       for (i = 0;; i++) {
04627          db_enum_link(hDB, hkeyvar, i, &hkey);
04628 
04629          if (!hkey)
04630             break;
04631 
04632          db_get_key(hDB, hkey, &key);
04633 
04634          if (equal_ustring(key.name, group))
04635             rsprintf("<b>%s</b> &nbsp;&nbsp;", key.name);
04636          else
04637             rsprintf("<a href=\"%s%s/%s\">%s</a> &nbsp;&nbsp;\n", back_path, 
04638                         eq_name, key.name, key.name);
04639       }
04640 
04641       rsprintf("</tr>\n");
04642 
04643       /* enumerate variable arrays */
04644 
04645       for (i = 0;; i++) {
04646          db_enum_link(hDB, hkeyvar, i, &hkey);
04647 
04648          if (!hkey)
04649             break;
04650 
04651          db_get_key(hDB, hkey, &varkey);
04652 
04653          if (!equal_ustring(group, "All") && !equal_ustring(varkey.name, group))
04654             continue;
04655 
04656          /* title row */
04657          rsprintf("<tr><th colspan=9>Names<th>%s</tr>\n", varkey.name);
04658 
04659          if (varkey.type == TID_KEY) {
04660             hkeyroot = hkey;
04661 
04662             /* enumerate subkeys */
04663             for (j = 0;; j++) {
04664                db_enum_key(hDB, hkeyroot, j, &hkey);
04665                if (!hkey)
04666                   break;
04667                db_get_key(hDB, hkey, &key);
04668 
04669                if (key.type == TID_KEY) {
04670                   /* for keys, don't display data value */
04671                   rsprintf("<tr><td colspan=9>%s<br></tr>\n", key.name);
04672                } else {
04673                   /* display single value */
04674                   if (key.num_values == 1) {
04675                      size = sizeof(data);
04676                      db_get_data(hDB, hkey, data, &size, key.type);
04677                      db_sprintf(data_str, data, key.item_size, 0, key.type);
04678                      db_sprintfh(hex_str, data, key.item_size, 0, key.type);
04679 
04680                      if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
04681                         strcpy(data_str, "(empty)");
04682                         hex_str[0] = 0;
04683                      }
04684 
04685                      if (strcmp(data_str, hex_str) != 0 && hex_str[0])
04686                         rsprintf
04687                             ("<tr><td colspan=9>%s<td align=center>%s (%s)<br></tr>\n",
04688                              key.name, data_str, hex_str);
04689                      else
04690                         rsprintf("<tr><td colspan=9>%s<td align=center>%s<br></tr>\n",
04691                                  key.name, data_str);
04692                   } else {
04693                      /* display first value */
04694                      rsprintf("<tr><td colspan=9 rowspan=%d>%s\n", key.num_values,
04695                               key.name);
04696 
04697                      for (k = 0; k < key.num_values; k++) {
04698                         size = sizeof(data);
04699                         db_get_data_index(hDB, hkey, data, &size, k, key.type);
04700                         db_sprintf(data_str, data, key.item_size, 0, key.type);
04701                         db_sprintfh(hex_str, data, key.item_size, 0, key.type);
04702 
04703                         if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
04704                            strcpy(data_str, "(empty)");
04705                            hex_str[0] = 0;
04706                         }
04707 
04708                         if (k > 0)
04709                            rsprintf("<tr>");
04710 
04711                         if (strcmp(data_str, hex_str) != 0 && hex_str[0])
04712                            rsprintf("<td>[%d] %s (%s)<br></tr>\n", k, data_str, hex_str);
04713                         else
04714                            rsprintf("<td>[%d] %s<br></tr>\n", k, data_str);
04715                      }
04716                   }
04717                }
04718             }
04719          } else {
04720             /* data for current group */
04721             sprintf(str, "/Equipment/%s/Settings/Names %s", eq_name, varkey.name);
04722             db_find_key(hDB, 0, str, &hkeyset);
04723             if (hkeyset)
04724                db_get_key(hDB, hkeyset, &key);
04725 
04726             if (varkey.num_values > 1000)
04727                rsprintf("<tr><td colspan=9>%s<td align=center><i>... %d values ...</i>",
04728                         varkey.name, varkey.num_values);
04729             else {
04730                for (j = 0; j < varkey.num_values; j++) {
04731                   if (hkeyset && j<key.num_values) {
04732                      size = sizeof(name);
04733                      db_get_data_index(hDB, hkeyset, name, &size, j, TID_STRING);
04734                   } else
04735                      sprintf(name, "%s[%d]", varkey.name, j);
04736 
04737                   if (strlen(name) < 1)
04738                      sprintf(name, "%s[%d]", varkey.name, j);
04739 
04740                   rsprintf("<tr><td colspan=9>%s", name);
04741 
04742                   size = sizeof(data);
04743                   db_get_data_index(hDB, hkey, data, &size, j, varkey.type);
04744                   db_sprintf(str, data, varkey.item_size, 0, varkey.type);
04745 
04746                   if (is_editable(eq_name, varkey.name)) {
04747                      if (n_var == i_set) {
04748                         /* set value */
04749                         strlcpy(str, getparam("value"), sizeof(str));
04750                         db_sscanf(str, data, &size, 0, varkey.type);
04751                         db_set_data_index(hDB, hkey, data, size, j, varkey.type);
04752 
04753                         /* redirect (so that 'reload' does not reset value) */
04754                         strlen_retbuf = 0;
04755                         sprintf(str, "%s", group);
04756                         redirect(str);
04757                         return;
04758                      }
04759                      if (n_var == i_edit) {
04760                         rsprintf
04761                             ("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n",
04762                              str);
04763                         rsprintf("<input type=submit size=20 name=cmd value=Set></tr>\n");
04764                         rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
04765                         rsprintf("<input type=hidden name=cmd value=Set>\n");
04766                         n_var++;
04767                      } else {
04768                         sprintf(ref, "%s%s/%s?cmd=Edit&index=%d", back_path, 
04769                                 eq_name, group, n_var);
04770 
04771                         rsprintf("<td align=center><a href=\"%s\">%s</a>\n", ref, str);
04772                         n_var++;
04773                      }
04774 
04775                   } else
04776                      rsprintf("<td align=center>%s\n", str);
04777                }
04778             }
04779 
04780             rsprintf("</tr>\n");
04781          }
04782       }
04783    }
04784 
04785    rsprintf("</table></form>\r\n");
04786 }
04787 
04788 /*------------------------------------------------------------------*/
04789 
04790 char *find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
04791 {
04792    char str[256], *ps, *pt;
04793    BOOL in_script;
04794 
04795    *edit = 0;
04796    *tail = 0;
04797    *format = 0;
04798    pwd[0] = 0;
04799    in_script = FALSE;
04800    strcpy(type, "text");
04801    do {
04802       while (*p && *p != '<')
04803          p++;
04804 
04805       /* return if end of string reached */
04806       if (!*p)
04807          return NULL;
04808 
04809       p++;
04810       while (*p && ((*p == ' ') || iscntrl(*p)))
04811          p++;
04812 
04813       strncpy(str, p, 6);
04814       str[6] = 0;
04815       if (equal_ustring(str, "script"))
04816          in_script = TRUE;
04817 
04818       strncpy(str, p, 7);
04819       str[7] = 0;
04820       if (equal_ustring(str, "/script"))
04821          in_script = FALSE;
04822 
04823       strncpy(str, p, 4);
04824       str[4] = 0;
04825       if (equal_ustring(str, "odb ")) {
04826          ps = p - 1;
04827          p += 4;
04828          while (*p && ((*p == ' ') || iscntrl(*p)))
04829             p++;
04830 
04831          do {
04832             strncpy(str, p, 7);
04833             str[7] = 0;
04834             if (equal_ustring(str, "format=")) {
04835                p += 7;
04836                if (*p == '\"') {
04837                   p++;
04838                   while (*p && *p != '\"')
04839                      *format++ = *p++;
04840                   *format = 0;
04841                   if (*p == '\"')
04842                     p++;
04843                } else {
04844                   while (*p && *p != ' ' && *p != '>')
04845                      *format++ = *p++;
04846                   *format = 0;
04847                }
04848 
04849             } else {
04850 
04851             strncpy(str, p, 4);
04852             str[4] = 0;
04853             if (equal_ustring(str, "src=")) {
04854                p += 4;
04855                if (*p == '\"') {
04856                   p++;
04857                   while (*p && *p != '\"')
04858                      *path++ = *p++;
04859                   *path = 0;
04860                   if (*p == '\"')
04861                     p++;
04862                } else {
04863                   while (*p && *p != ' ' && *p != '>')
04864                      *path++ = *p++;
04865                   *path = 0;
04866                }
04867             } else {
04868 
04869                if (in_script)
04870                   break;
04871 
04872                strncpy(str, p, 5);
04873                str[5] = 0;
04874                if (equal_ustring(str, "edit=")) {
04875                   p += 5;
04876 
04877                   if (*p == '\"') {
04878                      p++;
04879                      *edit = atoi(p);
04880                      if (*p == '\"')
04881                        p++;
04882                   } else {
04883                      *edit = atoi(p);
04884                      while (*p && *p != ' ' && *p != '>')
04885                         p++;
04886                   }
04887 
04888                } else {
04889 
04890                   strncpy(str, p, 5);
04891                   str[5] = 0;
04892                   if (equal_ustring(str, "type=")) {
04893                      p += 5;
04894                      if (*p == '\"') {
04895                         p++;
04896                         while (*p && *p != '\"')
04897                            *type++ = *p++;
04898                         *type = 0;
04899                         if (*p == '\"')
04900                           p++;
04901                      } else {
04902                         while (*p && *p != ' ' && *p != '>')
04903                            *type++ = *p++;
04904                         *type = 0;
04905                      }
04906                   } else {
04907                      strncpy(str, p, 4);
04908                      str[4] = 0;
04909                      if (equal_ustring(str, "pwd=")) {
04910                         p += 4;
04911                         if (*p == '\"') {
04912                            p++;
04913                            while (*p && *p != '\"')
04914                               *pwd++ = *p++;
04915                            *pwd = 0;
04916                            if (*p == '\"')
04917                              p++;
04918                         } else {
04919                            while (*p && *p != ' ' && *p != '>')
04920                               *pwd++ = *p++;
04921                            *pwd = 0;
04922                         }
04923                      } else {
04924                         if (strchr(p, '=')) {
04925                            strlcpy(str, p, sizeof(str));
04926                            pt = strchr(str, '=')+1;
04927                            if (*pt == '\"') {
04928                               pt++;
04929                               while (*pt && *pt != '\"')
04930                                  pt++;
04931                               if (*pt == '\"')
04932                                  pt++;
04933                               *pt = 0;
04934                            } else {
04935                               while (*pt && *pt != ' ' && *pt != '>')
04936                                  pt++;
04937                               *pt = 0;
04938                            }
04939                            if (tail[0]) {
04940                               strlcat(tail, " ", 256);
04941                               strlcat(tail, str, 256);
04942                            } else {
04943                               strlcat(tail, str, 256);
04944                            }
04945                            p += strlen(str);
04946                         }
04947                      }
04948                   }
04949                }
04950             }
04951             }
04952 
04953             while (*p && ((*p == ' ') || iscntrl(*p)))
04954                p++;
04955 
04956             if (*p == '<') {
04957                cm_msg(MERROR, "find_odb_tag", "Invalid odb tag '%s'", ps);
04958                return NULL;
04959             }
04960          } while (*p != '>');
04961 
04962          return ps;
04963       }
04964 
04965       while (*p && *p != '>')
04966          p++;
04967 
04968    } while (1);
04969 
04970 }
04971 
04972 /*------------------------------------------------------------------*/
04973 
04974 void show_odb_tag(const char *path, const char *keypath1, const char *format, int n_var, int edit, char *type, char *pwd, char *tail)
04975 {
04976    int size, index, i_edit, i_set;
04977    char str[TEXT_SIZE], data[TEXT_SIZE], options[1000], full_keypath[256], keypath[256], *p;
04978    HNDLE hDB, hkey;
04979    KEY key;
04980 
04981    /* check if variable to edit */
04982    i_edit = -1;
04983    if (equal_ustring(getparam("cmd"), "Edit"))
04984       i_edit = atoi(getparam("index"));
04985 
04986    /* check if variable to set */
04987    i_set = -1;
04988    if (equal_ustring(getparam("cmd"), "Set"))
04989       i_set = atoi(getparam("index"));
04990 
04991    /* check if path contains index */
04992    strlcpy(full_keypath, keypath1, sizeof(full_keypath));
04993    strlcpy(keypath, keypath1, sizeof(keypath));
04994    index = 0;
04995 
04996    if (strchr(keypath, '[') && strchr(keypath, ']')) {
04997       for (p = strchr(keypath, '[') + 1; *p && *p != ']'; p++)
04998          if (!isdigit(*p))
04999             break;
05000 
05001       if (*p && *p == ']') {
05002          index = atoi(strchr(keypath, '[') + 1);
05003          *strchr(keypath, '[') = 0;
05004       }
05005    }
05006 
05007    cm_get_experiment_database(&hDB, NULL);
05008    db_find_key(hDB, 0, keypath, &hkey);
05009    if (!hkey)
05010       rsprintf("<b>Key \"%s\" not found in ODB</b>\n", keypath);
05011    else {
05012       db_get_key(hDB, hkey, &key);
05013       size = sizeof(data);
05014       db_get_data_index(hDB, hkey, data, &size, index, key.type);
05015 
05016       if (format && strlen(format)>0)
05017          db_sprintff(str, format, data, key.item_size, 0, key.type);
05018       else
05019          db_sprintf(str, data, key.item_size, 0, key.type);
05020 
05021       if (equal_ustring(type, "checkbox")) {
05022 
05023          if (isparam("cbi"))
05024             i_set = atoi(getparam("cbi"));
05025          if (n_var == i_set) {
05026             /* toggle state */
05027             if (key.type == TID_BOOL) {
05028                if (str[0] == 'y')
05029                   strcpy(str, "n");
05030                else
05031                   strcpy(str, "y");
05032             } else {
05033                if (atoi(str) > 0)
05034                   strcpy(str, "0");
05035                else
05036                   strcpy(str, "1");
05037             }
05038 
05039             db_sscanf(str, data, &size, 0, key.type);
05040             db_set_data_index(hDB, hkey, data, size, index, key.type);
05041          }
05042 
05043          options[0] = 0;
05044          if (str[0] == 'y' || atoi(str) > 0)
05045             strcat(options, "checked ");
05046          if (!edit)
05047             strcat(options, "disabled ");
05048          else {
05049             if (edit == 1) {
05050                strlcat(options, "onClick=\"o=document.createElement('input');o.type='hidden';o.name='cbi';o.value='", sizeof(options));
05051                sprintf(options+strlen(options), "%d", n_var);
05052                strlcat(options, "';document.form1.appendChild(o);", sizeof(options));
05053                strlcat(options, "document.form1.submit();\" ", sizeof(options));
05054             }
05055          }
05056 
05057          if (tail[0])
05058             strlcat(options, tail, sizeof(options));
05059 
05060          rsprintf("<input type=\"checkbox\" %s>\n", options);
05061       
05062       } else { // checkbox
05063       
05064          if (edit == 1) {
05065             if (n_var == i_set) {
05066                /* set value */
05067                strlcpy(str, getparam("value"), sizeof(str));
05068                db_sscanf(str, data, &size, 0, key.type);
05069                db_set_data_index(hDB, hkey, data, size, index, key.type);
05070 
05071                /* read back value */
05072                size = sizeof(data);
05073                db_get_data_index(hDB, hkey, data, &size, index, key.type);
05074                db_sprintf(str, data, key.item_size, 0, key.type);
05075             }
05076 
05077             if (n_var == i_edit) {
05078                rsprintf("<input type=text size=10 maxlength=80 name=value value=\"%s\">\n",
05079                         str);
05080                rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
05081                rsprintf("<input type=hidden name=index value=%d>\n", n_var);
05082                rsprintf("<input type=hidden name=cmd value=Set>\n");
05083             } else {
05084                if (edit == 2) {
05085                   /* edit handling through user supplied JavaScript */
05086                   rsprintf("<a href=\"#\" %s>", tail);
05087                } else {
05088                   /* edit handling through form submission */
05089                   if (pwd[0]) {
05090                      rsprintf("<a onClick=\"promptpwd('%s?cmd=Edit&index=%d&pnam=%s')\" href=\"#\">", path, n_var, pwd);
05091                   } else {
05092                      rsprintf("<a href=\"%s?cmd=Edit&index=%d\" %s>", path, n_var, tail);
05093                   }
05094                }
05095 
05096                rsputs(str);
05097                rsprintf("</a>");
05098             }
05099          } else if (edit == 2) {
05100             rsprintf("<a href=\"#\" onclick=\"ODBEdit('%s')\">\n", full_keypath);
05101             rsputs(str);
05102             rsprintf("</a>");
05103          }
05104            else
05105             rsputs(str);
05106       }
05107    }
05108 }
05109 
05110 /*------------------------------------------------------------------*/
05111 
05112 /* add labels using following syntax under /Custom/Images/<name.gif>/Labels/<name>:
05113    
05114    [Name]    [Description]                       [Example]
05115 
05116    Src       ODB path for vairable to display    /Equipment/Environment/Variables/Input[0]
05117    Format    Formt for float/double              %1.2f Deg. C
05118    Font      Font to use                         small | medium | giant
05119    X         X-position in pixel                 90
05120    Y         Y-position from top                 67
05121    Align     horizontal align left/center/right  left
05122    FGColor   Foreground color RRGGBB             000000
05123    BGColor   Background color RRGGBB             FFFFFF
05124 */
05125 
05126 const char *cgif_label_str[] = {
05127    "Src = STRING : [256] ",
05128    "Format = STRING : [32] %1.1f",
05129    "Font = STRING : [32] Medium",
05130    "X = INT : 0",
05131    "Y = INT : 0",
05132    "Align = INT : 0",
05133    "FGColor = STRING : [8] 000000",
05134    "BGColor = STRING : [8] FFFFFF",
05135    NULL
05136 };
05137 
05138 typedef struct {
05139    char src[256];
05140    char format[32];
05141    char font[32];
05142    int x, y, align;
05143    char fgcolor[8];
05144    char bgcolor[8];
05145 } CGIF_LABEL;
05146 
05147 /* add labels using following syntax under /Custom/Images/<name.gif>/Bars/<name>:
05148    
05149    [Name]    [Description]                       [Example]
05150 
05151    Src       ODB path for vairable to display    /Equipment/Environment/Variables/Input[0]
05152    X         X-position in pixel                 90
05153    Y         Y-position from top                 67
05154    Width     Width in pixel                      20
05155    Height    Height in pixel                     100
05156    Direction 0(vertical)/1(horiz.)               0
05157    Axis      Draw axis 0(none)/1(left)/2(right)  1
05158    Logscale  Draw logarithmic axis               n
05159    Min       Min value for axis                  0
05160    Max       Max value for axis                  10
05161    FGColor   Foreground color RRGGBB             000000
05162    BGColor   Background color RRGGBB             FFFFFF
05163    BDColor   Border color RRGGBB                 808080
05164 */
05165 
05166 const char *cgif_bar_str[] = {
05167    "Src = STRING : [256] ",
05168    "X = INT : 0",
05169    "Y = INT : 0",
05170    "Width = INT : 10",
05171    "Height = INT : 100",
05172    "Direction = INT : 0",
05173    "Axis = INT : 1",
05174    "Logscale = BOOL : n",
05175    "Min = DOUBLE : 0",
05176    "Max = DOUBLE : 10",
05177    "FGColor = STRING : [8] 000000",
05178    "BGColor = STRING : [8] FFFFFF",
05179    "BDColor = STRING : [8] 808080",
05180    NULL
05181 };
05182 
05183 typedef struct {
05184    char src[256];
05185    int x, y, width, height, direction, axis;
05186    BOOL logscale;
05187    double min, max;
05188    char fgcolor[8];
05189    char bgcolor[8];
05190    char bdcolor[8];
05191 } CGIF_BAR;
05192 
05193 /*------------------------------------------------------------------*/
05194 
05195 int evaluate_src(char *key, char *src, double *fvalue)
05196 {
05197    HNDLE hDB, hkeyval;
05198    KEY vkey;
05199    int i, n, size, status, ivalue;
05200    char str[256], data[256], value[256];
05201 
05202    cm_get_experiment_database(&hDB, NULL);
05203 
05204    /* separate source from operators */
05205    for (i=0 ; i<(int)strlen(src) ; i++)
05206       if (src[i] == '>' || src[i] == '&')
05207          break;
05208    strncpy(str, src, i);
05209    str[i] = 0;
05210 
05211    /* strip trailing blanks */
05212    while (strlen(str) > 0 && str[strlen(str)-1] == ' ')
05213       str[strlen(str)-1] = 0;
05214 
05215    db_find_key(hDB, 0, str, &hkeyval);
05216    if (!hkeyval) {
05217       cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for Fill \"%s\"",
05218              src, key);
05219       return 0;
05220    }
05221 
05222    db_get_key(hDB, hkeyval, &vkey);
05223    size = sizeof(data);
05224    status = db_get_value(hDB, 0, src, data, &size, vkey.type, FALSE);
05225    db_sprintf(value, data, size, 0, vkey.type);
05226    if (equal_ustring(value, "NAN"))
05227       return 0;
05228    
05229    if (vkey.type == TID_BOOL) {
05230       *fvalue = (value[0] == 'y');
05231    } else
05232       *fvalue = atof(value);
05233 
05234    /* evaluate possible operators */
05235    do {
05236       if (src[i] == '>' && src[i+1] == '>') {
05237          i+=2;
05238          n = atoi(src+i);
05239          while (src[i] == ' ' || isdigit(src[i]))
05240             i++;
05241          ivalue = (int)*fvalue;
05242          ivalue >>= n;
05243          *fvalue = ivalue;
05244       }
05245 
05246       if (src[i] == '&') {
05247          i+=1;
05248          while (src[i] == ' ')
05249             i++;
05250          if (src[i] == '0' && src[i+1] == 'x')
05251             sscanf(src+2+i, "%x", &n);
05252          else
05253             n = atoi(src+i);
05254          while (src[i] == ' ' || isxdigit(src[i]) || src[i] == 'x')
05255             i++;
05256          ivalue = (int)*fvalue;
05257          ivalue &= n;
05258          *fvalue = ivalue;
05259       }
05260 
05261    } while (src[i]);
05262 
05263    return 1;
05264 }
05265 
05266 /*------------------------------------------------------------------*/
05267 
05268 void show_custom_gif(const char *name)
05269 {
05270    char str[256], filename[256], data[256], value[256], src[256], custom_path[256],
05271       full_filename[256];
05272    int i, fh, index, length, status, size, width, height, bgcol, fgcol, bdcol, r, g, b, x, y;
05273    HNDLE hDB, hkeygif, hkeyroot, hkey, hkeyval;
05274    double fvalue, ratio;
05275    KEY key, vkey;
05276    gdImagePtr im;
05277    gdGifBuffer gb;
05278    gdFontPtr pfont;
05279    FILE *f;
05280    CGIF_LABEL label;
05281    CGIF_BAR bar;
05282 
05283    cm_get_experiment_database(&hDB, NULL);
05284 
05285    custom_path[0] = 0;
05286    size = sizeof(custom_path);
05287    db_get_value(hDB, 0, "/Custom/Path", custom_path, &size, TID_STRING, FALSE);
05288 
05289    /* find image description in ODB */
05290    sprintf(str, "/Custom/Images/%s", name);
05291    db_find_key(hDB, 0, str, &hkeygif);
05292    if (!hkeygif) {
05293 
05294       /* check for file */
05295       strlcpy(filename, custom_path, sizeof(str));
05296       if (filename[strlen(filename)-1] != DIR_SEPARATOR)
05297          strlcat(filename, DIR_SEPARATOR_STR, sizeof(filename));
05298       strlcat(filename, name, sizeof(filename));
05299       fh = open(filename, O_RDONLY | O_BINARY);
05300       if (fh < 0) {
05301          sprintf(str, "Cannot open file \"%s\" and cannot find ODB key \"/Custom/Images/%s\"", filename, name);
05302          show_error(str);
05303          return;
05304       }
05305 
05306       size = lseek(fh, 0, SEEK_END);
05307       lseek(fh, 0, SEEK_SET);
05308 
05309       /* return GIF image */
05310       rsprintf("HTTP/1.0 200 Document follows\r\n");
05311       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
05312 
05313       rsprintf("Content-Type: image/gif\r\n");
05314       rsprintf("Content-Length: %d\r\n", size);
05315       rsprintf("Pragma: no-cache\r\n");
05316       rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
05317 
05318       if (size > (int) (sizeof(return_buffer) - strlen(return_buffer))) {
05319          printf("return buffer too small\n");
05320          return;
05321       }
05322 
05323       return_length = strlen(return_buffer) + size;
05324       read(fh, return_buffer + strlen(return_buffer), size);
05325       close(fh);
05326       return;
05327    }
05328 
05329    /* load background image */
05330    size = sizeof(filename);
05331    db_get_value(hDB, hkeygif, "Background", filename, &size, TID_STRING, FALSE);
05332 
05333    strlcpy(full_filename, custom_path, sizeof(str));
05334    if (full_filename[strlen(full_filename)-1] != DIR_SEPARATOR)
05335       strlcat(full_filename, DIR_SEPARATOR_STR, sizeof(full_filename));
05336    strlcat(full_filename, filename, sizeof(full_filename));
05337 
05338    f = fopen(full_filename, "rb");
05339    if (f == NULL) {
05340       sprintf(str, "Cannot open file \"%s\"", full_filename);
05341       show_error(str);
05342       return;
05343    }
05344 
05345    im = gdImageCreateFromGif(f);
05346    fclose(f);
05347 
05348    if (im == NULL) {
05349       sprintf(str, "File \"%s\" is not a GIF image", filename);
05350       show_error(str);
05351       return;
05352    }
05353 
05354    /*---- draw labels ----------------------------------------------*/
05355 
05356    db_find_key(hDB, hkeygif, "Labels", &hkeyroot);
05357    if (hkeyroot) {
05358       for (index = 0;; index++) {
05359          db_enum_key(hDB, hkeyroot, index, &hkey);
05360          if (!hkey)
05361             break;
05362          db_get_key(hDB, hkey, &key);
05363 
05364          db_check_record(hDB, hkey, "", strcomb(cgif_label_str), TRUE);
05365          size = sizeof(label);
05366          status = db_get_record(hDB, hkey, &label, &size, 0);
05367          if (status != DB_SUCCESS) {
05368             cm_msg(MERROR, "show_custom_gif", "Cannot open data record for label \"%s\"",
05369                    key.name);
05370             continue;
05371          }
05372 
05373          if (label.src[0] == 0) {
05374             cm_msg(MERROR, "show_custom_gif", "Empty Src key for label \"%s\"", key.name);
05375             continue;
05376          }
05377 
05378          db_find_key(hDB, 0, label.src, &hkeyval);
05379          if (!hkeyval) {
05380             cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for label \"%s\"",
05381                    label.src, key.name);
05382             continue;
05383          }
05384 
05385          db_get_key(hDB, hkeyval, &vkey);
05386          size = sizeof(data);
05387          status = db_get_value(hDB, 0, label.src, data, &size, vkey.type, FALSE);
05388 
05389          if (label.format[0]) {
05390             if (vkey.type == TID_FLOAT)
05391                sprintf(value, label.format, *(((float *) data)));
05392             else if (vkey.type == TID_DOUBLE)
05393                sprintf(value, label.format, *(((double *) data)));
05394             else if (vkey.type == TID_INT)
05395                sprintf(value, label.format, *(((INT *) data)));
05396             else if (vkey.type == TID_BOOL) {
05397                if (strstr(label.format, "%c"))
05398                   sprintf(value, label.format, *(((INT *) data)) ? 'y' : 'n');
05399                else
05400                   sprintf(value, label.format, *(((INT *) data)));
05401             } else
05402                db_sprintf(value, data, size, 0, vkey.type);
05403          } else
05404             db_sprintf(value, data, size, 0, vkey.type);
05405 
05406          sscanf(label.fgcolor, "%02x%02x%02x", &r, &g, &b);
05407          fgcol = gdImageColorAllocate(im, r, g, b);
05408          if (fgcol == -1)
05409             fgcol = gdImageColorClosest(im, r, g, b);
05410 
05411          sscanf(label.bgcolor, "%02x%02x%02x", &r, &g, &b);
05412          bgcol = gdImageColorAllocate(im, r, g, b);
05413          if (bgcol == -1)
05414             bgcol = gdImageColorClosest(im, r, g, b);
05415 
05416          /* select font */
05417          if (equal_ustring(label.font, "Small"))
05418             pfont = gdFontSmall;
05419          else if (equal_ustring(label.font, "Medium"))
05420             pfont = gdFontMediumBold;
05421          else if (equal_ustring(label.font, "Giant"))
05422             pfont = gdFontGiant;
05423          else
05424             pfont = gdFontMediumBold;
05425 
05426          width = strlen(value) * pfont->w + 5 + 5;
05427          height = pfont->h + 2 + 2;
05428 
05429          if (label.align == 0) {
05430             /* left */
05431             gdImageFilledRectangle(im, label.x, label.y, label.x + width,
05432                                    label.y + height, bgcol);
05433             gdImageRectangle(im, label.x, label.y, label.x + width, label.y + height,
05434                              fgcol);
05435             gdImageString(im, pfont, label.x + 5, label.y + 2, value, fgcol);
05436          } else if (label.align == 1) {
05437             /* center */
05438             gdImageFilledRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
05439                                    label.y + height, bgcol);
05440             gdImageRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
05441                              label.y + height, fgcol);
05442             gdImageString(im, pfont, label.x + 5 - width / 2, label.y + 2, value, fgcol);
05443          } else {
05444             /* right */
05445             gdImageFilledRectangle(im, label.x - width, label.y, label.x,
05446                                    label.y + height, bgcol);
05447             gdImageRectangle(im, label.x - width, label.y, label.x, label.y + height,
05448                              fgcol);
05449             gdImageString(im, pfont, label.x - width + 5, label.y + 2, value, fgcol);
05450          }
05451       }
05452    }
05453 
05454    /*---- draw bars ------------------------------------------------*/
05455 
05456    db_find_key(hDB, hkeygif, "Bars", &hkeyroot);
05457    if (hkeyroot) {
05458       for (index = 0;; index++) {
05459          db_enum_key(hDB, hkeyroot, index, &hkey);
05460          if (!hkey)
05461             break;
05462          db_get_key(hDB, hkey, &key);
05463 
05464          db_check_record(hDB, hkey, "", strcomb(cgif_bar_str), TRUE);
05465          size = sizeof(bar);
05466          status = db_get_record(hDB, hkey, &bar, &size, 0);
05467          if (status != DB_SUCCESS) {
05468             cm_msg(MERROR, "show_custom_gif", "Cannot open data record for bar \"%s\"",
05469                    key.name);
05470             continue;
05471          }
05472 
05473          if (bar.src[0] == 0) {
05474             cm_msg(MERROR, "show_custom_gif", "Empty Src key for bar \"%s\"", key.name);
05475             continue;
05476          }
05477 
05478          db_find_key(hDB, 0, bar.src, &hkeyval);
05479          if (!hkeyval) {
05480             cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for bar \"%s\"",
05481                    bar.src, key.name);
05482             continue;
05483          }
05484 
05485          db_get_key(hDB, hkeyval, &vkey);
05486          size = sizeof(data);
05487          status = db_get_value(hDB, 0, bar.src, data, &size, vkey.type, FALSE);
05488          db_sprintf(value, data, size, 0, vkey.type);
05489          if (equal_ustring(value, "NAN"))
05490             continue;
05491 
05492          fvalue = atof(value);
05493 
05494          sscanf(bar.fgcolor, "%02x%02x%02x", &r, &g, &b);
05495          fgcol = gdImageColorAllocate(im, r, g, b);
05496          if (fgcol == -1)
05497             fgcol = gdImageColorClosest(im, r, g, b);
05498 
05499          sscanf(bar.bgcolor, "%02x%02x%02x", &r, &g, &b);
05500          bgcol = gdImageColorAllocate(im, r, g, b);
05501          if (bgcol == -1)
05502             bgcol = gdImageColorClosest(im, r, g, b);
05503 
05504          sscanf(bar.bdcolor, "%02x%02x%02x", &r, &g, &b);
05505          bdcol = gdImageColorAllocate(im, r, g, b);
05506          if (bdcol == -1)
05507             bdcol = gdImageColorClosest(im, r, g, b);
05508 
05509          if (bar.min == bar.max)
05510             bar.max += 1;
05511 
05512          if (bar.logscale) {
05513             if (fvalue < 1E-20)
05514                fvalue = 1E-20;
05515             ratio = (log(fvalue) - log(bar.min)) / (log(bar.max) - log(bar.min));
05516          } else
05517             ratio = (fvalue - bar.min) / (bar.max - bar.min);
05518          if (ratio < 0)
05519             ratio = 0;
05520          if (ratio > 1)
05521             ratio = 1;
05522 
05523          if (bar.direction == 0) {
05524             /* vertical */
05525             ratio = (bar.height - 2) - ratio * (bar.height - 2);
05526             r = (int) (ratio + 0.5);
05527 
05528             gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.width,
05529                                    bar.y + bar.height, bgcol);
05530             gdImageRectangle(im, bar.x, bar.y, bar.x + bar.width, bar.y + bar.height,
05531                              bdcol);
05532             gdImageFilledRectangle(im, bar.x + 1, bar.y + r + 1, bar.x + bar.width - 1,
05533                                    bar.y + bar.height - 1, fgcol);
05534 
05535             if (bar.axis == 1)
05536                vaxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.height, bar.height, -3,
05537                      -5, -7, -8, 0, bar.min, bar.max, bar.logscale);
05538             else if (bar.axis == 2)
05539                vaxis(im, gdFontSmall, bdcol, 0, bar.x + bar.width, bar.y + bar.height,
05540                      bar.height, 3, 5, 7, 10, 0, bar.min, bar.max, bar.logscale);
05541 
05542          } else {
05543             /* horizontal */
05544             ratio = ratio * (bar.height - 2);
05545             r = (int) (ratio + 0.5);
05546 
05547             gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.height,
05548                                    bar.y + bar.width, bgcol);
05549             gdImageRectangle(im, bar.x, bar.y, bar.x + bar.height, bar.y + bar.width,
05550                              bdcol);
05551             gdImageFilledRectangle(im, bar.x + 1, bar.y + 1, bar.x + r,
05552                                    bar.y + bar.width - 1, fgcol);
05553 
05554             if (bar.axis == 1)
05555                haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y, bar.height, -3, -5, -7, -18,
05556                      0, bar.min, bar.max);
05557             else if (bar.axis == 2)
05558                haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.width, bar.height, 3,
05559                      5, 7, 8, 0, bar.min, bar.max);
05560          }
05561       }
05562    }
05563 
05564    /*---- draw fills -----------------------------------------------*/
05565 
05566    db_find_key(hDB, hkeygif, "Fills", &hkeyroot);
05567    if (hkeyroot) {
05568       for (index = 0;; index++) {
05569          db_enum_key(hDB, hkeyroot, index, &hkey);
05570          if (!hkey)
05571             break;
05572          db_get_key(hDB, hkey, &key);
05573 
05574          size = sizeof(src);
05575          src[0] = 0;
05576          db_get_value(hDB, hkey, "Src", src, &size, TID_STRING, TRUE);
05577 
05578          if (src[0] == 0) {
05579             cm_msg(MERROR, "show_custom_gif", "Empty Src key for Fill \"%s\"", key.name);
05580             continue;
05581          }
05582 
05583          if (!evaluate_src(key.name, src, &fvalue))
05584             continue;
05585 
05586          x = y = 0;
05587          size = sizeof(x);
05588          db_get_value(hDB, hkey, "X", &x, &size, TID_INT, TRUE);
05589          db_get_value(hDB, hkey, "Y", &y, &size, TID_INT, TRUE);
05590 
05591          size = sizeof(data);
05592          status = db_get_value(hDB, hkey, "Limits", data, &size, TID_DOUBLE, FALSE);
05593          if (status != DB_SUCCESS) {
05594             cm_msg(MERROR, "show_custom_gif", "No \"Limits\" entry for Fill \"%s\"",
05595                    key.name);
05596             continue;
05597          }
05598          for (i = 0; i < size / (int) sizeof(double); i++)
05599             if (*((double *) data + i) > fvalue)
05600                break;
05601          if (i > 0)
05602             i--;
05603 
05604          db_find_key(hDB, hkey, "Fillcolors", &hkeyval);
05605          if (!hkeyval) {
05606             cm_msg(MERROR, "show_custom_gif", "No \"Fillcolors\" entry for Fill \"%s\"",
05607                    key.name);
05608             continue;
05609          }
05610 
05611          size = sizeof(data);
05612          strcpy(data, "FFFFFF");
05613          status = db_get_data_index(hDB, hkeyval, data, &size, i, TID_STRING);
05614          if (status == DB_SUCCESS) {
05615             sscanf(data, "%02x%02x%02x", &r, &g, &b);
05616             fgcol = gdImageColorAllocate(im, r, g, b);
05617             if (fgcol == -1)
05618                fgcol = gdImageColorClosest(im, r, g, b);
05619             gdImageFill(im, x, y, fgcol);
05620          }
05621       }
05622    }
05623 
05624    /* generate GIF */
05625    gdImageInterlace(im, 1);
05626    gdImageGif(im, &gb);
05627    gdImageDestroy(im);
05628    length = gb.size;
05629 
05630    rsprintf("HTTP/1.0 200 Document follows\r\n");
05631    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
05632 
05633    rsprintf("Content-Type: image/gif\r\n");
05634    rsprintf("Content-Length: %d\r\n", length);
05635    rsprintf("Pragma: no-cache\r\n");
05636    rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
05637 
05638    if (length > (int) (sizeof(return_buffer) - strlen(return_buffer))) {
05639       printf("return buffer too small\n");
05640       return;
05641    }
05642 
05643    return_length = strlen(return_buffer) + length;
05644    memcpy(return_buffer + strlen(return_buffer), gb.data, length);
05645 }
05646 
05647 /*------------------------------------------------------------------*/
05648 
05649 void do_jrpc_rev0()
05650 {
05651    static RPC_LIST rpc_list[] = {
05652       { 9999, "mhttpd_jrpc_rev0", {
05653             {TID_STRING, RPC_IN}, // arg0
05654             {TID_STRING, RPC_IN}, // arg1
05655             {TID_STRING, RPC_IN}, // arg2
05656             {TID_STRING, RPC_IN}, // arg3
05657             {TID_STRING, RPC_IN}, // arg4
05658             {TID_STRING, RPC_IN}, // arg5
05659             {TID_STRING, RPC_IN}, // arg6
05660             {TID_STRING, RPC_IN}, // arg7
05661             {TID_STRING, RPC_IN}, // arg8
05662             {TID_STRING, RPC_IN}, // arg9
05663             {0}} },
05664       { 0 }
05665    };
05666 
05667    int status, count = 0, substring = 0, rpc;
05668 
05669    const char *xname   = getparam("name");
05670    const char *srpc    = getparam("rpc");
05671 
05672    if (!srpc || !xname) {
05673       show_text_header();
05674       rsprintf("<INVALID_ARGUMENTS>");
05675       return;
05676    }
05677 
05678    char sname[256];
05679    strlcpy(sname, xname, sizeof(sname));
05680 
05681    if (sname[strlen(sname)-1]=='*') {
05682       sname[strlen(sname)-1] = 0;
05683       substring = 1;
05684    }
05685 
05686    rpc = atoi(srpc);
05687 
05688    if (rpc<RPC_MIN_ID || rpc>RPC_MAX_ID) {
05689       show_text_header();
05690       rsprintf("<INVALID_RPC_ID>");
05691       return;
05692    }
05693 
05694    rpc_list[0].id = rpc;
05695    status = rpc_register_functions(rpc_list, NULL);
05696 
05697    //printf("cm_register_functions() for format \'%s\' status %d\n", sformat, status);
05698 
05699    show_text_header();
05700    rsprintf("calling rpc %d | ", rpc);
05701 
05702    if (1) {
05703       int status, i;
05704       char str[256];
05705       HNDLE hDB, hrootkey, hsubkey, hkey;
05706 
05707       cm_get_experiment_database(&hDB, NULL);
05708       
05709       /* find client which exports FCNA function */
05710       status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
05711       if (status == DB_SUCCESS) {
05712          for (i=0; ; i++) {
05713             status = db_enum_key(hDB, hrootkey, i, &hsubkey);
05714             if (status == DB_NO_MORE_SUBKEYS)
05715                break;
05716             
05717             sprintf(str, "RPC/%d", rpc);
05718             status = db_find_key(hDB, hsubkey, str, &hkey);
05719             if (status == DB_SUCCESS) {
05720                char client_name[NAME_LENGTH];
05721                HNDLE hconn;
05722                int size;
05723 
05724                size = sizeof(client_name);
05725                status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
05726                if (status != DB_SUCCESS)
05727                   continue;
05728 
05729                if (strlen(sname) > 0) {
05730                   if (substring) {
05731                      if (strstr(client_name, sname) != client_name)
05732                         continue;
05733                   } else {
05734                      if (strcmp(sname, client_name) != 0)
05735                         continue;
05736                   }
05737                }
05738 
05739                count++;
05740 
05741                rsprintf("client %s", client_name);
05742 
05743                status = cm_connect_client(client_name, &hconn);
05744                rsprintf(" %d", status);
05745       
05746                if (status == RPC_SUCCESS) {
05747                   status = rpc_client_call(hconn, rpc,
05748                                            getparam("arg0"),
05749                                            getparam("arg1"),
05750                                            getparam("arg2"),
05751                                            getparam("arg3"),
05752                                            getparam("arg4"),
05753                                            getparam("arg5"),
05754                                            getparam("arg6"),
05755                                            getparam("arg7"),
05756                                            getparam("arg8"),
05757                                            getparam("arg9")
05758                                            );
05759                   rsprintf(" %d", status);
05760 
05761                   status = cm_disconnect_client(hconn, FALSE);
05762                   rsprintf(" %d", status);
05763                }
05764 
05765                rsprintf(" | ");
05766             }
05767          }
05768       }
05769    }
05770 
05771    rsprintf("rpc %d, called %d clients\n", rpc, count);
05772 }
05773 
05774 /*------------------------------------------------------------------*/
05775 
05776 void show_custom_page(const char *path, const char *cookie_cpwd)
05777 {
05778    int size, i, n_var, fh, index, edit;
05779    char str[TEXT_SIZE], keypath[256], type[32], *p, *ps, custom_path[256],
05780       filename[256], pwd[256], ppath[256], tail[256];
05781    HNDLE hDB, hkey;
05782    KEY key;
05783    char data[TEXT_SIZE];
05784 
05785    if (strstr(path, ".gif")) {
05786       show_custom_gif(path);
05787       return;
05788    }
05789 
05790    cm_get_experiment_database(&hDB, NULL);
05791 
05792    if (path[0] == 0) {
05793       show_error("Invalid custom page: NULL path");
05794       return;
05795    }
05796    sprintf(str, "/Custom/%s", path);
05797 
05798    custom_path[0] = 0;
05799    size = sizeof(custom_path);
05800    db_get_value(hDB, 0, "/Custom/Path", custom_path, &size, TID_STRING, FALSE);
05801    db_find_key(hDB, 0, str, &hkey);
05802    if (!hkey) {
05803       sprintf(str, "/Custom/%s&", path);
05804       db_find_key(hDB, 0, str, &hkey);
05805       if (!hkey) {
05806          sprintf(str, "/Custom/%s!", path);
05807          db_find_key(hDB, 0, str, &hkey);
05808       }
05809    }
05810 
05811    if (hkey) {
05812       char* ctext;
05813       int status;
05814 
05815       status = db_get_key(hDB, hkey, &key);
05816       assert(status == DB_SUCCESS);
05817       size = key.total_size;
05818       ctext = (char*)malloc(size);
05819       status = db_get_data(hDB, hkey, ctext, &size, TID_STRING);
05820       if (status != DB_SUCCESS) {
05821          sprintf(str, "Error: db_get_data() status %d", status);
05822          show_error(str);
05823          free(ctext);
05824          return;
05825       }
05826 
05827       /* check if filename */
05828       if (strchr(ctext, '\n') == 0) {
05829          strlcpy(filename, custom_path, sizeof(str));
05830          if (filename[strlen(filename)-1] != DIR_SEPARATOR)
05831             strlcat(filename, DIR_SEPARATOR_STR, sizeof(filename));
05832          strlcat(filename, ctext, sizeof(filename));
05833          fh = open(filename, O_RDONLY | O_BINARY);
05834          if (fh < 0) {
05835             sprintf(str, "Cannot open file \"%s\"", filename);
05836             show_error(str);
05837             free(ctext);
05838             return;
05839          }
05840          free(ctext);
05841          size = lseek(fh, 0, SEEK_END) + 1;
05842          lseek(fh, 0, SEEK_SET);
05843          ctext = (char*)malloc(size);
05844          memset(ctext, 0, size);
05845          read(fh, ctext, size);
05846          close(fh);
05847       }
05848 
05849       /* check for valid password */
05850       if (equal_ustring(getparam("cmd"), "Edit")) {
05851          p = ps = ctext;
05852          n_var = 0;
05853          do {
05854             char format[256];
05855 
05856             p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
05857             if (p == NULL)
05858                break;
05859             ps = strchr(p, '>') + 1;
05860 
05861             if (pwd[0] && n_var == atoi(getparam("index"))) {
05862                size = NAME_LENGTH;
05863                strlcpy(str, path, sizeof(str));
05864                if (strlen(str)>0 && str[strlen(str)-1] == '&')
05865                   str[strlen(str)-1] = 0;
05866                if (*getparam("pnam"))
05867                   sprintf(ppath, "/Custom/Pwd/%s", getparam("pnam"));
05868                else
05869                   sprintf(ppath, "/Custom/Pwd/%s", str);
05870                str[0] = 0;
05871                db_get_value(hDB, 0, ppath, str, &size, TID_STRING, TRUE);
05872                if (!equal_ustring(cookie_cpwd, str)) {
05873                   show_error("Invalid password!");
05874                   free(ctext);
05875                   return;
05876                } else
05877                   break;
05878             }
05879 
05880             n_var++;
05881          } while (p != NULL);
05882       }
05883 
05884       /* process toggle command */
05885       if (equal_ustring(getparam("cmd"), "Toggle")) {
05886 
05887          if (*getparam("pnam")) {
05888             sprintf(ppath, "/Custom/Pwd/%s", getparam("pnam"));
05889             str[0] = 0;
05890             db_get_value(hDB, 0, ppath, str, &size, TID_STRING, TRUE);
05891             if (!equal_ustring(cookie_cpwd, str)) {
05892                show_error("Invalid password!");
05893                free(ctext);
05894                return;
05895             }
05896          }
05897          strlcpy(str, getparam("odb"), sizeof(str));
05898          if (strchr(str, '[')) {
05899             index = atoi(strchr(str, '[')+1);
05900             *strchr(str, '[') = 0;
05901          } else
05902             index = 0;
05903 
05904          if (db_find_key(hDB, 0, str, &hkey)) {
05905             db_get_key(hDB, hkey, &key);
05906             memset(data, 0, sizeof(data));
05907             if (key.item_size <= (int)sizeof(data)) {
05908                size = sizeof(data);
05909                db_get_data_index(hDB, hkey, data, &size, index, key.type);
05910                db_sprintf(str, data, size, 0, key.type);
05911                if (atoi(str) == 0)
05912                   db_sscanf("1", data, &size, 0, key.type);
05913                else
05914                   db_sscanf("0", data, &size, 0, key.type);
05915                db_set_data_index(hDB, hkey, data, key.item_size, index, key.type);
05916             }
05917          }
05918 
05919          /* redirect (so that 'reload' does not toggle again) */
05920          redirect(path);
05921          free(ctext);
05922          return;
05923       }
05924 
05925       /* process "jset" command */
05926       if (equal_ustring(getparam("cmd"), "jset")) {
05927 
05928          if (*getparam("pnam")) {
05929             sprintf(ppath, "/Custom/Pwd/%s", getparam("pnam"));
05930             str[0] = 0;
05931             db_get_value(hDB, 0, ppath, str, &size, TID_STRING, TRUE);
05932             if (!equal_ustring(cookie_cpwd, str)) {
05933                show_text_header();
05934                rsprintf("Invalid password!");
05935                free(ctext);
05936                return;
05937             }
05938          }
05939          strlcpy(str, getparam("odb"), sizeof(str));
05940          if (strchr(str, '[')) {
05941             if (*(strchr(str, '[')+1) == '*')
05942                index = -1;
05943             else
05944                index = atoi(strchr(str, '[')+1);
05945             *strchr(str, '[') = 0;
05946          } else
05947             index = 0;
05948 
05949          if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS && isparam("value")) {
05950             db_get_key(hDB, hkey, &key);
05951             memset(data, 0, sizeof(data));
05952             if (key.item_size <= (int)sizeof(data)) {
05953                if (index == -1) {
05954                   const char* p = getparam("value");
05955                   for (i=0 ; p != NULL ; i++) {
05956                      size = sizeof(data);
05957                      db_sscanf(p, data, &size, 0, key.type);
05958                      db_set_data_index(hDB, hkey, data, key.item_size, i, key.type);
05959                      p = strchr(p, ',');
05960                      if (p != NULL)
05961                         p++;
05962                   } 
05963                } else {
05964                   size = sizeof(data);
05965                   db_sscanf(getparam("value"), data, &size, 0, key.type);
05966                   db_set_data_index(hDB, hkey, data, key.item_size, index, key.type);
05967                }
05968             }
05969          } else {
05970             if (isparam("value") && isparam("type") && isparam("len")) {
05971                int type = atoi(getparam("type"));
05972                if (type == 0) {
05973                   show_text_header();
05974                   rsprintf("Invalid type %d!", type);
05975                   free(ctext);
05976                   return;
05977                }
05978                db_create_key(hDB, 0, str, type);
05979                db_find_key(hDB, 0, str, &hkey);
05980                if (!hkey) {
05981                   show_text_header();
05982                   rsprintf("Cannot create \'%s\' type %d", str, type);
05983                   free(ctext);
05984                   return;
05985                }
05986                db_get_key(hDB, hkey, &key);
05987                memset(data, 0, sizeof(data));
05988                size = sizeof(data);
05989                db_sscanf(getparam("value"), data, &size, 0, key.type);
05990                if (key.type == TID_STRING)
05991                   db_set_data(hDB, hkey, data, atoi(getparam("len")), 1, TID_STRING);
05992                else {
05993                   for (i=0 ; i<atoi(getparam("len")) ; i++)
05994                      db_set_data_index(hDB, hkey, data, rpc_tid_size(key.type), i, key.type);
05995                }
05996             }
05997          }
05998 
05999          show_text_header();
06000          rsprintf("OK");
06001          free(ctext);
06002          return;
06003       }
06004 
06005       /* process "jget" command */
06006       if (equal_ustring(getparam("cmd"), "jget")) {
06007 
06008          strlcpy(str, getparam("odb"), sizeof(str));
06009          if (strchr(str, '[')) {
06010             if (*(strchr(str, '[')+1) == '*')
06011                index = -1;
06012             else
06013                index = atoi(strchr(str, '[')+1);
06014             *strchr(str, '[') = 0;
06015          } else
06016             index = 0;
06017 
06018          show_text_header();
06019 
06020          if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS) {
06021             db_get_key(hDB, hkey, &key);
06022             if (key.item_size <= (int)sizeof(data)) {
06023                size = sizeof(data);
06024                db_get_data(hDB, hkey, data, &size, key.type);
06025                if (index == -1) {
06026                   for (i=0 ; i<key.num_values ; i++) {
06027                      if (isparam("format"))
06028                         db_sprintff(str, getparam("format"), data, key.item_size, i, key.type);
06029                      else
06030                         db_sprintf(str, data, key.item_size, i, key.type);
06031                      rsputs(str);
06032                      if (i<key.num_values-1)
06033                         rsputs("\n");
06034                   }
06035                } else {
06036                   if (index >= key.num_values)
06037                      rsputs("<DB_OUT_OF_RANGE>");
06038                   else {
06039                      if (isparam("format"))
06040                         db_sprintff(str, getparam("format"), data, key.item_size, index, key.type);
06041                      else
06042                         db_sprintf(str, data, key.item_size, index, key.type);
06043                      rsputs(str);
06044                   }
06045                }
06046             }
06047          } else
06048             rsputs("<DB_NO_KEY>");
06049 
06050          free(ctext);
06051          return;
06052       }
06053 
06054       /* process "jkey" command */
06055       if (equal_ustring(getparam("cmd"), "jkey")) {
06056 
06057          show_text_header();
06058 
06059          if (isparam("odb") && db_find_key(hDB, 0, getparam("odb"), &hkey) == DB_SUCCESS) {
06060             db_get_key(hDB, hkey, &key);
06061             rsprintf("%s\n", key.name);
06062             rsprintf("TID_%s\n", rpc_tid_name(key.type));
06063             rsprintf("%d\n", key.num_values);
06064             rsprintf("%d", key.item_size);
06065          } else
06066             rsputs("<DB_NO_KEY>");
06067 
06068          free(ctext);
06069          return;
06070       }
06071 
06072       /* process "jmsg" command */
06073       if (equal_ustring(getparam("cmd"), "jmsg")) {
06074 
06075          i = 1;
06076          if (*getparam("n"))
06077             i = atoi(getparam("n"));
06078 
06079          show_text_header();
06080          cm_msg_retrieve(i, str, sizeof(str));
06081          rsputs(str);
06082          free(ctext);
06083          return;
06084       }
06085 
06086       /* process "jrpc" command */
06087       if (equal_ustring(getparam("cmd"), "jrpc_rev0")) {
06088          free(ctext);
06089          do_jrpc_rev0();
06090          return;
06091       }
06092 
06093       /* HTTP header */
06094       rsprintf("HTTP/1.0 200 Document follows\r\n");
06095       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
06096       rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
06097 
06098       /* interprete text, replace <odb> tags with ODB values */
06099       p = ps = ctext;
06100       n_var = 0;
06101       do {
06102          char format[256];
06103          p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
06104          if (p != NULL)
06105             *p = 0;
06106          rsputs(ps);
06107 
06108          if (p == NULL)
06109             break;
06110          ps = strchr(p + 1, '>') + 1;
06111 
06112          show_odb_tag(path, keypath, format, n_var, edit, type, pwd, tail);
06113          n_var++;
06114 
06115       } while (p != NULL);
06116 
06117       if (equal_ustring(getparam("cmd"), "Set") || isparam("cbi")) {
06118          /* redirect (so that 'reload' does not change value) */
06119          strlen_retbuf = 0;
06120          sprintf(str, "%s", path);
06121          redirect(str);
06122       }
06123 
06124       free(ctext);
06125    } else {
06126       show_error("Invalid custom page: Page not found in ODB");
06127       return;
06128    }
06129 }
06130 
06131 /*------------------------------------------------------------------*/
06132 
06133 void show_cnaf_page()
06134 {
06135    char str[256];
06136    int c, n, a, f, d, q, x, r, ia, id, w;
06137    int i, size, status;
06138    HNDLE hDB, hrootkey, hsubkey, hkey;
06139 
06140    static char client_name[NAME_LENGTH];
06141    static HNDLE hconn = 0;
06142 
06143    cm_get_experiment_database(&hDB, NULL);
06144 
06145    /* find FCNA server if not specified */
06146    if (hconn == 0) {
06147       /* find client which exports FCNA function */
06148       status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
06149       if (status == DB_SUCCESS) {
06150          for (i = 0;; i++) {
06151             status = db_enum_key(hDB, hrootkey, i, &hsubkey);
06152             if (status == DB_NO_MORE_SUBKEYS)
06153                break;
06154 
06155             sprintf(str, "RPC/%d", RPC_CNAF16);
06156             status = db_find_key(hDB, hsubkey, str, &hkey);
06157             if (status == DB_SUCCESS) {
06158                size = sizeof(client_name);
06159                db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
06160                break;
06161             }
06162          }
06163       }
06164 
06165       if (client_name[0]) {
06166          status = cm_connect_client(client_name, &hconn);
06167          if (status != RPC_SUCCESS)
06168             hconn = 0;
06169       }
06170    }
06171 
06172    /* header */
06173    rsprintf("HTTP/1.0 200 Document follows\r\n");
06174    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
06175    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
06176 
06177    rsprintf("<html><head>\n");
06178    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
06179    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
06180    rsprintf("<title>MIDAS CAMAC interface</title></head>\n");
06181    rsprintf("<body><form method=\"GET\" action=\"CNAF\">\n\n");
06182 
06183    /* title row */
06184 
06185    size = sizeof(str);
06186    str[0] = 0;
06187    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
06188 
06189    rsprintf("<table border=3 cellpadding=1>\n");
06190    rsprintf("<tr><th colspan=3 bgcolor=#A0A0FF>MIDAS experiment \"%s\"", str);
06191 
06192    if (client_name[0] == 0)
06193       rsprintf("<th colspan=3 bgcolor=#FF0000>No CAMAC server running</tr>\n");
06194    else if (hconn == 0)
06195       rsprintf("<th colspan=3 bgcolor=#FF0000>Cannot connect to %s</tr>\n", client_name);
06196    else
06197       rsprintf("<th colspan=3 bgcolor=#A0A0FF>CAMAC server: %s</tr>\n", client_name);
06198 
06199    /* default values */
06200    c = n = 1;
06201    a = f = d = q = x = 0;
06202    r = 1;
06203    ia = id = w = 0;
06204 
06205    /*---- menu buttons ----*/
06206 
06207    rsprintf("<tr><td colspan=3 bgcolor=#C0C0C0>\n");
06208    rsprintf("<input type=submit name=cmd value=Execute>\n");
06209 
06210    rsprintf("<td colspan=3 bgcolor=#C0C0C0>\n");
06211    rsprintf("<input type=submit name=cmd value=ODB>\n");
06212    rsprintf("<input type=submit name=cmd value=Status>\n");
06213    rsprintf("<input type=submit name=cmd value=Help>\n");
06214    rsprintf("</tr>\n\n");
06215 
06216    /* header */
06217    rsprintf("<tr><th bgcolor=#FFFF00>N");
06218    rsprintf("<th bgcolor=#FF8000>A");
06219    rsprintf("<th bgcolor=#00FF00>F");
06220    rsprintf("<th colspan=3 bgcolor=#8080FF>Data");
06221 
06222    /* execute commands */
06223    size = sizeof(d);
06224 
06225    const char* cmd = getparam("cmd");
06226    if (equal_ustring(cmd, "C cycle")) {
06227       rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
06228                       &q);
06229 
06230       rsprintf("<tr><td colspan=6 bgcolor=#00FF00>C cycle executed sucessfully</tr>\n");
06231    } else if (equal_ustring(cmd, "Z cycle")) {
06232       rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_ZINIT, 0, 0, 0, 0, 0, &d, &size, &x,
06233                       &q);
06234 
06235       rsprintf("<tr><td colspan=6 bgcolor=#00FF00>Z cycle executed sucessfully</tr>\n");
06236    } else if (equal_ustring(cmd, "Clear inhibit")) {
06237       rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
06238                       &q);
06239 
06240       rsprintf
06241           ("<tr><td colspan=6 bgcolor=#00FF00>Clear inhibit executed sucessfully</tr>\n");
06242    } else if (equal_ustring(cmd, "Set inhibit")) {
06243       rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_SET, 0, 0, 0, 0, 0, &d, &size, &x,
06244                       &q);
06245 
06246       rsprintf
06247           ("<tr><td colspan=6 bgcolor=#00FF00>Set inhibit executed sucessfully</tr>\n");
06248    } else if (equal_ustring(cmd, "Execute")) {
06249       c = atoi(getparam("C"));
06250       n = atoi(getparam("N"));
06251       a = atoi(getparam("A"));
06252       f = atoi(getparam("F"));
06253       r = atoi(getparam("R"));
06254       w = atoi(getparam("W"));
06255       id = atoi(getparam("ID"));
06256       ia = atoi(getparam("IA"));
06257 
06258       const char* pd = getparam("D");
06259       if (strncmp(pd, "0x", 2) == 0)
06260          sscanf(pd + 2, "%x", &d);
06261       else
06262          d = atoi(getparam("D"));
06263 
06264       /* limit repeat range */
06265       if (r == 0)
06266          r = 1;
06267       if (r > 100)
06268          r = 100;
06269       if (w > 1000)
06270          w = 1000;
06271 
06272       for (i = 0; i < r; i++) {
06273          status = SUCCESS;
06274 
06275          if (hconn) {
06276             size = sizeof(d);
06277             status =
06278                 rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x,
06279                                 &q);
06280 
06281             if (status == RPC_NET_ERROR) {
06282                /* try to reconnect */
06283                cm_disconnect_client(hconn, FALSE);
06284                status = cm_connect_client(client_name, &hconn);
06285                if (status != RPC_SUCCESS) {
06286                   hconn = 0;
06287                   client_name[0] = 0;
06288                }
06289 
06290                if (hconn)
06291                   status =
06292                       rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size,
06293                                       &x, &q);
06294             }
06295          }
06296 
06297          if (status != SUCCESS) {
06298             rsprintf
06299                 ("<tr><td colspan=6 bgcolor=#FF0000>Error executing function, code = %d</tr>",
06300                  status);
06301          } else {
06302             rsprintf("<tr align=center><td bgcolor=#FFFF00>%d", n);
06303             rsprintf("<td bgcolor=#FF8000>%d", a);
06304             rsprintf("<td bgcolor=#00FF00>%d", f);
06305             rsprintf("<td colspan=3 bgcolor=#8080FF>%d / 0x%04X  Q%d X%d", d, d, q, x);
06306          }
06307 
06308          d += id;
06309          a += ia;
06310 
06311          if (w > 0)
06312             ss_sleep(w);
06313       }
06314    }
06315 
06316    /* input fields */
06317    rsprintf
06318        ("<tr align=center><td bgcolor=#FFFF00><input type=text size=3 name=N value=%d>\n",
06319         n);
06320    rsprintf("<td bgcolor=#FF8000><input type=text size=3 name=A value=%d>\n", a);
06321    rsprintf("<td bgcolor=#00FF00><input type=text size=3 name=F value=%d>\n", f);
06322    rsprintf
06323        ("<td bgcolor=#8080FF colspan=3><input type=text size=8 name=D value=%d></tr>\n",
06324         d);
06325 
06326    /* control fields */
06327    rsprintf("<tr><td colspan=2 bgcolor=#FF8080>Repeat");
06328    rsprintf("<td bgcolor=#FF8080><input type=text size=3 name=R value=%d>\n", r);
06329 
06330    rsprintf
06331        ("<td align=center colspan=3 bgcolor=#FF0000><input type=submit name=cmd value=\"C cycle\">\n");
06332    rsprintf("<input type=submit name=cmd value=\"Z cycle\">\n");
06333 
06334    rsprintf("<tr><td colspan=2 bgcolor=#FF8080>Repeat delay [ms]");
06335    rsprintf("<td bgcolor=#FF8080><input type=text size=3 name=W value=%d>\n", w);
06336 
06337    rsprintf
06338        ("<td align=center colspan=3 bgcolor=#FF0000><input type=submit name=cmd value=\"Set inhibit\">\n");
06339    rsprintf("<input type=submit name=cmd value=\"Clear inhibit\">\n");
06340 
06341    rsprintf("<tr><td colspan=2 bgcolor=#FF8080>Data increment");
06342    rsprintf("<td bgcolor=#FF8080><input type=text size=3 name=ID value=%d>\n", id);
06343 
06344    rsprintf
06345        ("<td colspan=3 align=center bgcolor=#FFFF80>Branch <input type=text size=3 name=B value=0>\n");
06346 
06347    rsprintf("<tr><td colspan=2 bgcolor=#FF8080>A increment");
06348    rsprintf("<td bgcolor=#FF8080><input type=text size=3 name=IA value=%d>\n", ia);
06349 
06350    rsprintf
06351        ("<td colspan=3 align=center bgcolor=#FFFF80>Crate <input type=text size=3 name=C value=%d>\n",
06352         c);
06353 
06354    rsprintf("</table></body>\r\n");
06355 }
06356 
06357 /*------------------------------------------------------------------*/
06358 
06359 #ifdef HAVE_MSCB
06360 
06361 typedef struct {
06362    char id;
06363    char name[32];
06364 } NAME_TABLE;
06365 
06366 NAME_TABLE prefix_table[] = {
06367    {PRFX_PICO, "pico",},
06368    {PRFX_NANO, "nano",},
06369    {PRFX_MICRO, "micro",},
06370    {PRFX_MILLI, "milli",},
06371    {PRFX_NONE, "",},
06372    {PRFX_KILO, "kilo",},
06373    {PRFX_MEGA, "mega",},
06374    {PRFX_GIGA, "giga",},
06375    {PRFX_TERA, "tera",},
06376    {99}
06377 };
06378 
06379 NAME_TABLE unit_table[] = {
06380 
06381    {UNIT_METER, "meter",},
06382    {UNIT_GRAM, "gram",},
06383    {UNIT_SECOND, "second",},
06384    {UNIT_MINUTE, "minute",},
06385    {UNIT_HOUR, "hour",},
06386    {UNIT_AMPERE, "ampere",},
06387    {UNIT_KELVIN, "kelvin",},
06388    {UNIT_CELSIUS, "deg. celsius",},
06389    {UNIT_FARENHEIT, "deg. farenheit",},
06390 
06391    {UNIT_HERTZ, "hertz",},
06392    {UNIT_PASCAL, "pascal",},
06393    {UNIT_BAR, "bar",},
06394    {UNIT_WATT, "watt",},
06395    {UNIT_VOLT, "volt",},
06396    {UNIT_OHM, "ohm",},
06397    {UNIT_TESLA, "tesls",},
06398    {UNIT_LITERPERSEC, "liter/sec",},
06399    {UNIT_RPM, "RPM",},
06400    {UNIT_FARAD, "farad",},
06401 
06402    {UNIT_BOOLEAN, "boolean",},
06403    {UNIT_BYTE, "byte",},
06404    {UNIT_WORD, "word",},
06405    {UNIT_DWORD, "dword",},
06406    {UNIT_ASCII, "ascii",},
06407    {UNIT_STRING, "string",},
06408    {UNIT_BAUD, "baud",},
06409 
06410    {UNIT_PERCENT, "percent",},
06411    {UNIT_PPM, "RPM",},
06412    {UNIT_COUNT, "counts",},
06413    {UNIT_FACTOR, "factor",},
06414    {0}
06415 };
06416 
06417 /*------------------------------------------------------------------*/
06418 
06419 void print_mscb_var(char *value, char *evalue, char *unit, MSCB_INFO_VAR *info_chn, void *pdata)
06420 {
06421    char str[80];
06422    signed short sdata;
06423    unsigned short usdata;
06424    signed int idata;
06425    unsigned int uidata;
06426    float fdata;
06427    int i;
06428 
06429    value[0] = 0;
06430    evalue[0] = 0;
06431 
06432    if (info_chn->unit == UNIT_STRING) {
06433       memset(str, 0, sizeof(str));
06434       strncpy(str, (char *)pdata, info_chn->width);
06435       for (i = 0; i < (int) strlen(str); i++)
06436          switch (str[i]) {
06437          case 1:
06438             strcat(value, "\\001");
06439             break;
06440          case 2:
06441             strcat(value, "\\002");
06442             break;
06443          case 9:
06444             strcat(value, "\\t");
06445             break;
06446          case 10:
06447             strcat(value, "\\n");
06448             break;
06449          case 13:
06450             strcat(value, "\\r");
06451             break;
06452          default:
06453             value[strlen(value) + 1] = 0;
06454             value[strlen(value)] = str[i];
06455             break;
06456          }
06457       strlcpy(evalue, value, 256);
06458    } else {
06459       switch (info_chn->width) {
06460       case 0:
06461          strcpy(value, "0");
06462          strcpy(evalue, "0");
06463          break;
06464 
06465       case 1:
06466          if (info_chn->flags & MSCBF_SIGNED) {
06467             sprintf(value, "%d (0x%02X/", *((signed char *)pdata), *((signed char *)pdata));
06468             sprintf(evalue, "%d", *((signed char *)pdata));
06469          } else {
06470             sprintf(value, "%u (0x%02X/", *((unsigned char *)pdata), *((unsigned char *)pdata));
06471             sprintf(evalue, "%u", *((unsigned char *)pdata));
06472          }
06473 
06474          for (i = 0; i < 8; i++)
06475             if (*((unsigned char *)pdata) & (0x80 >> i))
06476                sprintf(value + strlen(value), "1");
06477             else
06478                sprintf(value + strlen(value), "0");
06479          sprintf(value + strlen(value), ")");
06480          break;
06481 
06482       case 2:
06483          if (info_chn->flags & MSCBF_SIGNED) {
06484             sdata = *((signed short *)pdata);
06485             WORD_SWAP(&sdata);
06486             sprintf(value, "%d (0x%04X)", sdata, sdata);
06487             sprintf(evalue, "%d", sdata);
06488          } else {
06489             usdata = *((unsigned short *)pdata);
06490             WORD_SWAP(&usdata);
06491             sprintf(value, "%u (0x%04X)", usdata, usdata);
06492             sprintf(evalue, "%u", usdata);
06493          }
06494          break;
06495 
06496       case 4:
06497          if (info_chn->flags & MSCBF_FLOAT) {
06498             fdata = *((float *)pdata);
06499             DWORD_SWAP(&fdata);
06500             sprintf(value, "%1.6lg", fdata);
06501             sprintf(evalue, "%1.6lg", fdata);
06502          } else {
06503             if (info_chn->flags & MSCBF_SIGNED) {
06504                idata = *((signed int *)pdata);
06505                DWORD_SWAP(&idata);
06506                sprintf(value, "%d (0x%08X)", idata, idata);
06507                sprintf(evalue, "%d", idata);
06508             } else {
06509                uidata = *((unsigned int *)pdata);
06510                DWORD_SWAP(&uidata);
06511                sprintf(value, "%u (0x%08X)", uidata, uidata);
06512                sprintf(evalue, "%u", uidata);
06513             }
06514          }
06515          break;
06516       }
06517    }
06518 
06519    /* evaluate prefix */
06520    unit[0] = 0;
06521    if (info_chn->prefix) {
06522       for (i = 0; prefix_table[i].id != 99; i++)
06523          if (prefix_table[i].id == info_chn->prefix)
06524             break;
06525       if (prefix_table[i].id)
06526          strcpy(unit, prefix_table[i].name);
06527    }
06528 
06529    /* evaluate unit */
06530    if (info_chn->unit && info_chn->unit != UNIT_STRING) {
06531       for (i = 0; unit_table[i].id; i++)
06532          if (unit_table[i].id == info_chn->unit)
06533             break;
06534       if (unit_table[i].id)
06535          strcat(unit, unit_table[i].name);
06536    }
06537 }
06538 
06539 static int cmp_int(const void *a, const void *b)
06540 {
06541   return *((int *)a) > *((int *)b);
06542 }
06543 
06544 /*------------------------------------------------------------------*/
06545 
06546 void create_mscb_tree()
06547 {
06548    HNDLE hDB, hKeySubm, hKeyEq, hKeyAdr, hKey, hKeyDev;
06549    KEY key;
06550    int i, j, k, l, size, address[1000], dev_badr[1000], dev_adr[1000], dev_chn[1000], 
06551       n_address, n_dev_adr;
06552    char mscb_dev[256], mscb_pwd[32], eq_name[32];
06553 
06554    cm_get_experiment_database(&hDB, NULL);
06555 
06556    db_create_key(hDB, 0, "MSCB/Submaster", TID_KEY);
06557    db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
06558    assert(hKeySubm);
06559 
06560    /*---- go through equipment list ----*/
06561    db_find_key(hDB, 0, "Equipment", &hKeyEq);
06562    assert(hKeyEq);
06563    for (i=0 ; ; i++) {
06564       db_enum_key(hDB, hKeyEq, i, &hKey);
06565       if (!hKey)
06566          break;
06567       db_get_key(hDB, hKey, &key);
06568       strcpy(eq_name, key.name);
06569       db_find_key(hDB, hKey, "Settings/Devices", &hKeyDev);
06570       if (hKeyDev) {
06571          for (j=0 ;; j++) {
06572             db_enum_key(hDB, hKeyDev, j, &hKey);
06573             if (!hKey)
06574                break;
06575 
06576             if (db_find_key(hDB, hKey, "MSCB Address", &hKeyAdr) == DB_SUCCESS) {
06577                /* mscbdev type of device */
06578                size = sizeof(mscb_dev);
06579                if (db_get_value(hDB, hKey, "Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
06580                    continue;
06581                size = sizeof(mscb_pwd);
06582                if (db_get_value(hDB, hKey, "Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
06583                    continue;
06584 
06585                size = sizeof(dev_adr);
06586                db_get_data(hDB, hKeyAdr, dev_adr, &size, TID_INT);
06587                n_dev_adr = size / sizeof(int);
06588             } else if (db_find_key(hDB, hKey, "Block Address", &hKeyAdr) == DB_SUCCESS) {
06589                /* mscbhvr type of device */
06590                size = sizeof(mscb_dev);
06591                if (db_get_value(hDB, hKey, "MSCB Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
06592                   continue;
06593                size = sizeof(mscb_pwd);
06594                if (db_get_value(hDB, hKey, "MSCB Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
06595                   continue;
06596 
06597                n_dev_adr = 0;
06598                size = sizeof(dev_badr);
06599                db_get_data(hDB, hKeyAdr, dev_badr, &size, TID_INT);
06600                size = sizeof(dev_chn);
06601                if (db_get_value(hDB, hKey, "Block Channels", dev_chn, &size, TID_INT, FALSE) == DB_SUCCESS) {
06602                   for (k=0 ; k<size/(int)sizeof(int) && n_dev_adr < (int)(sizeof(dev_adr)/sizeof(int)) ; k++) {
06603                      for (l=0 ; l<dev_chn[k] ; l++)
06604                         dev_adr[n_dev_adr++] = dev_badr[k]+l;
06605                   }
06606                }
06607             } else
06608                continue;
06609 
06610             /* create or open submaster entry */
06611             db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
06612             if (!hKey) {
06613                db_create_key(hDB, hKeySubm, mscb_dev, TID_KEY);
06614                db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
06615                assert(hKey);
06616             }
06617 
06618             /* get old address list */
06619             size = sizeof(address);
06620             if (db_get_value(hDB, hKey, "Address", address, &size, TID_INT, FALSE) == DB_SUCCESS)
06621                n_address = size / sizeof(int);
06622             else
06623                n_address = 0;
06624 
06625             /* merge with new address list */
06626             for (k=0 ; k<n_dev_adr ; k++) {
06627                for (l=0 ; l<n_address ; l++)
06628                   if (address[l] == dev_adr[k])
06629                      break;
06630 
06631                if (l == n_address)
06632                   address[n_address++] = dev_adr[k];
06633             }
06634 
06635             /* sort address list */
06636             qsort(address, n_address, sizeof(int), cmp_int);
06637 
06638             /* store new address list */
06639             db_set_value(hDB, hKey, "Pwd", mscb_pwd, 32, 1, TID_STRING);
06640             db_set_value(hDB, hKey, "Comment", eq_name, 32, 1, TID_STRING);
06641             db_set_value(hDB, hKey, "Address", address, n_address*sizeof(int), n_address, TID_INT);
06642          }
06643       }
06644    }
06645 }
06646 
06647 /*------------------------------------------------------------------*/
06648 
06649 void show_mscb_page(char *path, int refresh)
06650 {
06651    int i, j, fi, fd, status, size, cur_subm_index, cur_node, adr, show_hidden;
06652    unsigned int uptime;
06653    float fvalue;
06654    char str[256], comment[256], *pd, dbuf[256], value[256], evalue[256], unit[256], cur_subm_name[256];
06655    time_t now;
06656    HNDLE hDB, hKeySubm, hKeyCurSubm, hKey, hKeyAddr;
06657    KEY key;
06658    MSCB_INFO info;
06659    MSCB_INFO_VAR info_var;
06660 
06661    cm_get_experiment_database(&hDB, NULL);
06662 
06663    status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
06664    if (!hKeySubm)
06665       create_mscb_tree();
06666 
06667    if (strstr(path, "favicon") != NULL)
06668       return;
06669 
06670    if (isparam("subm") && isparam("node")) {
06671       strlcpy(cur_subm_name, getparam("subm"), sizeof(cur_subm_name));
06672       cur_node = atoi(getparam("node"));
06673 
06674       if (isparam("idx") && isparam("value")) {
06675          i = atoi(getparam("idx"));
06676          strlcpy(value, getparam("value"), sizeof(value));
06677 
06678          fd = mscb_init(cur_subm_name, 0, "", FALSE);
06679          if (fd) {
06680             status = mscb_info_variable(fd, 
06681                        (unsigned short) cur_node, (unsigned char) i, &info_var);
06682             if (status == MSCB_SUCCESS) {
06683                if (info_var.unit == UNIT_STRING) {
06684                   memset(str, 0, sizeof(str));
06685                   strncpy(str, value, info_var.width);
06686                   if (strlen(str) > 0 && str[strlen(str) - 1] == '\n')
06687                      str[strlen(str) - 1] = 0;
06688 
06689                   status = mscb_write(fd, (unsigned short) cur_node,
06690                                     (unsigned char) i, str, strlen(str) + 1);
06691                } else {
06692                   if (info_var.flags & MSCBF_FLOAT) {
06693                      fvalue = (float) atof(value);
06694                      memcpy(&dbuf, &fvalue, sizeof(float));
06695                   } else {
06696                      if (value[1] == 'x')
06697                         sscanf(value + 2, "%x", (int *)&dbuf);
06698                      else
06699                         *((int *)dbuf) = atoi(value);
06700                   }
06701 
06702                   status = mscb_write(fd, (unsigned short) cur_node,
06703                                     (unsigned char) i, dbuf, info_var.width);
06704                }
06705             }
06706          }
06707       }
06708 
06709       if (path[0])
06710          sprintf(str, "../%s/%d", cur_subm_name, cur_node);
06711       else
06712          sprintf(str, "%s/%d", cur_subm_name, cur_node);
06713       if (isparam("hidden"))
06714          strlcat(str, "h", sizeof(str));
06715       redirect(str);
06716       return;
06717    }
06718 
06719    if (path[0]) {
06720       strlcpy(cur_subm_name, path, sizeof(cur_subm_name));
06721       if (strchr(cur_subm_name, '/'))
06722          *strchr(cur_subm_name, '/') = 0;
06723       if (strchr(cur_subm_name, '?'))
06724          *strchr(cur_subm_name, '?') = 0;
06725       if (strchr(path, '/')) {
06726          cur_node = atoi(strchr(path, '/')+1);
06727       }
06728    } else {
06729       cur_subm_name[0] = 0;
06730       cur_node = 0;
06731    }
06732 
06733    if (path[0] && path[strlen(path)-1] == 'h')
06734       show_hidden = TRUE;
06735    else
06736       show_hidden = FALSE;
06737 
06738    /* header */
06739    rsprintf("HTTP/1.0 200 Document follows\r\n");
06740    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
06741    rsprintf("Pragma: no-cache\r\n");
06742    rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
06743    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
06744 
06745    rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
06746    rsprintf("<html><head>\n");
06747 
06748    /* style sheet */
06749    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
06750    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
06751    rsprintf("<style type=\"text/css\">\r\n");
06752    rsprintf("select { width:150px; background-color:#FFFFE0; font-size:12px; }\r\n");
06753    rsprintf(".subm {\r\n");
06754    rsprintf("  background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
06755    rsprintf("  padding:5px;\r\n");
06756    rsprintf("  vertical-align:top;\r\n");
06757    rsprintf("  font-size:16px;\r\n");
06758    rsprintf("  border-right:1px solid #808080;\r\n");
06759    rsprintf("}\r\n");
06760    rsprintf(".node {\r\n");
06761    rsprintf("  background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
06762    rsprintf("  padding:5px;\r\n");
06763    rsprintf("  vertical-align:top;\r\n");
06764    rsprintf("  font-size:16px;\r\n");
06765    rsprintf("  border-right:1px solid #808080;\r\n");
06766    rsprintf("}\r\n");
06767    rsprintf(".vars {\r\n");
06768    rsprintf("  background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
06769    rsprintf("  padding:5px;\r\n");
06770    rsprintf("  vertical-align:top;\r\n");
06771    rsprintf("  font-size:10px;\r\n");
06772    rsprintf("}\r\n");
06773    rsprintf(".v1 {\r\n");
06774    rsprintf("  padding:3px;\r\n");
06775    rsprintf("  font-weight:bold;\r\n");
06776    rsprintf("  font-size:12px;\r\n");
06777    rsprintf("}\r\n");
06778    rsprintf(".v2 {\r\n");
06779    rsprintf("  background-color:#F0F0F0;\r\n");
06780    rsprintf("  padding:3px;\r\n");
06781    rsprintf("  font-size:12px;\r\n");
06782    rsprintf("  border:1px solid #808080;\r\n");
06783    rsprintf("  border-right:1px solid #FFFFFF;\r\n");
06784    rsprintf("  border-bottom:1px solid #FFFFFF;\r\n");
06785    rsprintf("}\r\n");
06786    rsprintf(".v3 {\r\n");
06787    rsprintf("  padding:3px;\r\n");
06788    rsprintf("  font-size:12px;\r\n");
06789    rsprintf("}\r\n");
06790    rsprintf("</style>\r\n\r\n");
06791 
06792    /* javascript */
06793    rsprintf("<script type=\"text/javascript\">\r\n");
06794    rsprintf("function mscb_edit(index, value)\r\n");
06795    rsprintf("{\r\n");
06796    rsprintf("   var new_value = prompt('Please enter new value', value);\r\n");
06797    rsprintf("   if (new_value != undefined) {\r\n");
06798    rsprintf("     o = document.createElement('input');\r\n");
06799    rsprintf("     o.type = 'hidden';\r\n");
06800    rsprintf("     o.name = 'idx';\r\n");
06801    rsprintf("     o.value = index;\r\n");
06802    rsprintf("     document.form1.appendChild(o);\r\n");
06803    rsprintf("     o = document.createElement('input');\r\n");
06804    rsprintf("     o.type = 'hidden';\r\n");
06805    rsprintf("     o.name = 'value';\r\n");
06806    rsprintf("     o.value = new_value;\r\n");
06807    rsprintf("     document.form1.appendChild(o);\r\n");
06808    rsprintf("     document.form1.submit()\r\n");
06809    rsprintf("   }\n");
06810    rsprintf("}\r\n");
06811    rsprintf("</script>\r\n\r\n");
06812 
06813 
06814    /* auto refresh */
06815    if (refresh > 0)
06816       rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
06817 
06818    rsprintf("<title>MSCB Interface Page</title></head>\n");
06819 
06820    rsprintf("<body><form name=\"form1\" method=\"GET\" action=\".\">\n\n");
06821 
06822    /* title row */
06823    size = sizeof(str);
06824    str[0] = 0;
06825    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
06826    time(&now);
06827 
06828    rsprintf("<table border=3 cellpadding=2>\n");
06829    rsprintf("<tr><th bgcolor=\"#A0A0FF\">MIDAS experiment \"%s\"", str);
06830 
06831    rsprintf("<th bgcolor=\"#A0A0FF\">%s  &nbsp;&nbsp;Refr:%d</tr>\n", ctime(&now), refresh);
06832 
06833    /*---- menu buttons ----*/
06834 
06835    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
06836    rsprintf("<table width=100%%><tr><td>\n");
06837    rsprintf("<input type=submit name=cmd value=ODB>\n");
06838    rsprintf("<input type=submit name=cmd value=Status>\n");
06839    rsprintf("</td>\n");
06840    rsprintf("<td align=right width=10>");
06841    rsprintf("<button type=\"button\" onClick=\"document.form1.submit()\">\n");
06842    rsprintf("<img alt=\"Reload page\" title=\"Reload page\" ");
06843    rsprintf("src=\"reload.png\"></button></td></tr></table></td></tr>\n\n");
06844 
06845    rsprintf("<tr><td bgcolor=#E0E0E0 colspan=\"2\" cellpadding=\"0\" cellspacing=\"0\">\r\n");
06846 
06847    status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
06848    if (status != DB_SUCCESS) {
06849       rsprintf("<h1>No MSCB Submasters defined in ODB</h1>\r\n");
06850       rsprintf("</td></tr>\r\n");
06851       rsprintf("</table></body></html>\r\n");
06852       return;
06853    }
06854 
06855    rsprintf("<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"0\">");
06856 
06857    /*---- submaster list ----*/
06858    rsprintf("<tr><td class=\"subm\">\r\n");
06859    rsprintf("Submaster<hr>\r\n");
06860 
06861    rsprintf("<select name=\"subm\" size=20 onChange=\"document.form1.submit();\">\r\n");
06862    hKeyCurSubm = 0;
06863    for (i = 0;;i++) {
06864       db_enum_key(hDB, hKeySubm, i, &hKey);
06865       if (!hKey)
06866          break;
06867       db_get_key(hDB, hKey, &key);
06868       strcpy(str, key.name);
06869       size = sizeof(comment);
06870       if (db_get_value(hDB, hKey, "Comment", comment, &size, TID_STRING, FALSE) == DB_SUCCESS) {
06871          strcat(str, ": ");
06872          strlcat(str, comment, sizeof(str));
06873       }
06874 
06875       if ((cur_subm_name[0] && equal_ustring(cur_subm_name, key.name)) || 
06876           (cur_subm_name[0] == 0 && i == 0)) {
06877          cur_subm_index = i;
06878          rsprintf("<option value=\"%s\" selected>%s</option>\r\n", key.name, str);
06879          hKeyCurSubm = hKey;
06880       } else
06881          rsprintf("<option value=\"%s\">%s</option>\r\n", key.name, str);
06882    }
06883    rsprintf("</select>\r\n");
06884 
06885    /*---- node list ----*/
06886    rsprintf("<td class=\"node\">\r\n");
06887    rsprintf("Node<hr>\r\n");
06888 
06889    if (!hKeyCurSubm) {
06890       rsprintf("No submaster found in ODB\r\n");
06891       return;
06892    }
06893 
06894    rsprintf("<select name=\"node\" size=20 onChange=\"document.form1.submit();\">\r\n");
06895    db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
06896    assert(hKeyAddr);
06897    db_get_key(hDB, hKeyAddr, &key);
06898    size = sizeof(adr);
06899 
06900    /* check if current node is in list */
06901    for (i = 0; i<key.num_values ;i++) {
06902       size = sizeof(adr);
06903       db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
06904       if (adr == cur_node)
06905          break;
06906    }
06907    if (i == key.num_values) // if not found, use first one in list
06908       db_get_data_index(hDB, hKeyAddr, &cur_node, &size, 0, TID_INT);
06909 
06910    for (i = 0; i<key.num_values ;i++) {
06911       size = sizeof(adr);
06912       db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
06913       sprintf(str, "%d", adr);
06914       if (cur_node == 0 && i == 0)
06915          cur_node = adr;
06916       if (adr == cur_node)
06917          rsprintf("<option selected>%s</option>\r\n", str);
06918       else
06919          rsprintf("<option>%s</option>\r\n", str);
06920    }
06921    rsprintf("</select>\r\n");
06922 
06923    /*---- node contents ----*/
06924    rsprintf("<td class=\"vars\">\r\n");
06925    rsprintf("<table>\r\n");
06926    db_get_key(hDB, hKeyCurSubm, &key);
06927    rsprintf("<tr><td colspan=3 align=center><b>%s:%d</b>", key.name, cur_node);
06928    rsprintf("<hr></td></tr>\r\n");
06929    str[0] = 0;
06930    size = sizeof(str);
06931    db_get_value(hDB, hKeyCurSubm, "Pwd", str, &size, TID_STRING, TRUE);
06932 
06933    fd = mscb_init(key.name, 0, str, FALSE);
06934    if (fd < 0) {
06935       if (fd == EMSCB_WRONG_PASSWORD)
06936          rsprintf("<tr><td colspan=3><b>Invalid password</b></td>");
06937       else
06938          rsprintf("<tr><td colspan=3><b>Communication problem</b></td>");
06939       goto mscb_error;
06940    }
06941    mscb_set_eth_max_retry(fd, 3);
06942    mscb_set_max_retry(1);
06943 
06944    status = mscb_ping(fd, cur_node, TRUE);
06945    if (status != MSCB_SUCCESS) {
06946       rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
06947       goto mscb_error;
06948    }
06949    status = mscb_info(fd, (unsigned short) cur_node, &info);
06950    if (status != MSCB_SUCCESS) {
06951       rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
06952       goto mscb_error;
06953    }
06954    strncpy(str, info.node_name, sizeof(info.node_name));
06955    str[16] = 0;
06956    rsprintf("<tr><td class=\"v1\">Node name<td colspan=2 class=\"v2\">%s</tr>\n", str);
06957    rsprintf("<tr><td class=\"v1\">SVN revision<td colspan=2 class=\"v2\">%d</tr>\n", info.svn_revision);
06958 
06959    if (info.rtc[0] && info.rtc[0] != 0xFF) {
06960       for (i=0 ; i<6 ; i++)
06961          info.rtc[i] = (info.rtc[i] / 0x10) * 10 + info.rtc[i] % 0x10;
06962       rsprintf("<tr><td class=\"v1\">Real Time Clock<td colspan=2 class=\"v2\">%02d-%02d-%02d %02d:%02d:%02d</td>\n",
06963          info.rtc[0], info.rtc[1], info.rtc[2], 
06964          info.rtc[3], info.rtc[4], info.rtc[5]);
06965    }
06966 
06967    status = mscb_uptime(fd, (unsigned short) cur_node, &uptime);
06968     if (status == MSCB_SUCCESS)
06969       rsprintf("<tr><td class=\"v1\">Uptime<td colspan=2 class=\"v2\">%dd %02dh %02dm %02ds</tr>\n",
06970              uptime / (3600 * 24),
06971              (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
06972              (uptime % 60));
06973 
06974    rsprintf("<tr><td colspan=3><hr></td></tr>\r\n");
06975 
06976    /* check for hidden variables */
06977    for (i=0 ; i < info.n_variables ; i++) {
06978       mscb_info_variable(fd, cur_node, i, &info_var);
06979       if (info_var.flags & MSCBF_HIDDEN)
06980          break;
06981    }
06982    if (i < info.n_variables) {
06983       strcpy(str, show_hidden ? " checked" : "");
06984       rsprintf("<tr><td colspan=3><input type=checkbox%s name=\"hidden\" value=\"1\"", str);
06985       rsprintf("onChange=\"document.form1.submit();\">Display hidden variables<hr></td></tr>\r\n");
06986    }
06987 
06988    /* read variables in blocks of 100 bytes */
06989    for (fi=0 ; fi < info.n_variables ; ) {
06990       for (i=fi,size=0 ; i < info.n_variables && size < 100; i++) {
06991          mscb_info_variable(fd, cur_node, i, &info_var);
06992          size += info_var.width;
06993       }
06994 
06995       size = sizeof(dbuf);
06996       status = mscb_read_range(fd, cur_node, fi, i-1, dbuf, &size);
06997       if (status != MSCB_SUCCESS) {
06998          rsprintf("<tr><td colspan=3><b>Error reading data from node</b></td>");
06999          goto mscb_error;
07000       }
07001       pd = dbuf;
07002 
07003       for (j=fi ; j<i ; j++) {
07004          status = mscb_info_variable(fd, cur_node, j, &info_var);
07005          if ((info_var.flags & MSCBF_HIDDEN) == 0 || show_hidden) {
07006             memcpy(str, info_var.name, 8);
07007             str[8] = 0;
07008             rsprintf("<tr><td class=\"v1\">%s</td>\r\n", str);
07009             rsprintf("<td class=\"v2\">\r\n");
07010             print_mscb_var(value, evalue, unit, &info_var, pd);
07011             rsprintf("<a href=\"#\" onClick=\"mscb_edit(%d,'%s')\">%s</a>", 
07012                j, evalue, value);
07013             rsprintf("</td><td class=\"v3\">%s</td>", unit);
07014             rsprintf("</tr>\r\n");
07015          }
07016          pd += info_var.width;
07017       }
07018 
07019       fi = i;
07020    }
07021 
07022 mscb_error:
07023    rsprintf("</tr></table>\r\n");
07024    rsprintf("</td></tr>\r\n");
07025    rsprintf("</table></body></html>\r\n");
07026 }
07027 
07028 #endif // HAVE_MSCB
07029 
07030 /*------------------------------------------------------------------*/
07031 
07032 void show_password_page(const char *password, const char *experiment)
07033 {
07034    rsprintf("HTTP/1.0 200 Document follows\r\n");
07035    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
07036    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
07037 
07038    rsprintf("<html><head>\n");
07039    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
07040    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
07041    rsprintf("<title>Enter password</title></head><body>\n\n");
07042 
07043    rsprintf("<form method=\"GET\" action=\".\">\n\n");
07044 
07045    /* define hidden fields for current experiment */
07046    if (experiment[0])
07047       rsprintf("<input type=hidden name=exp value=\"%s\">\n", experiment);
07048 
07049    rsprintf("<table border=1 cellpadding=5>");
07050 
07051    if (password[0])
07052       rsprintf("<tr><th bgcolor=#FF0000>Wrong password!</tr>\n");
07053 
07054    rsprintf("<tr><th bgcolor=#A0A0FF>Please enter password</tr>\n");
07055    rsprintf("<tr><td align=center><input type=password name=pwd></tr>\n");
07056    rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
07057 
07058    rsprintf("</table>\n");
07059 
07060    rsprintf("</body></html>\r\n");
07061 }
07062 
07063 /*------------------------------------------------------------------*/
07064 
07065 BOOL check_web_password(const char *password, const char *redir, const char *experiment)
07066 {
07067    HNDLE hDB, hkey;
07068    INT size;
07069    char str[256];
07070 
07071    cm_get_experiment_database(&hDB, NULL);
07072 
07073    /* check for password */
07074    db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
07075    if (hkey) {
07076       size = sizeof(str);
07077       db_get_data(hDB, hkey, str, &size, TID_STRING);
07078       if (strcmp(password, str) == 0)
07079          return TRUE;
07080 
07081       /* show web password page */
07082       rsprintf("HTTP/1.0 200 Document follows\r\n");
07083       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
07084       rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
07085 
07086       rsprintf("<html><head>\n");
07087       rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
07088       rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
07089       rsprintf("<title>Enter password</title></head><body>\n\n");
07090 
07091       rsprintf("<form method=\"GET\" action=\".\">\n\n");
07092 
07093       /* define hidden fields for current experiment and destination */
07094       if (experiment[0])
07095          rsprintf("<input type=hidden name=exp value=\"%s\">\n", experiment);
07096       if (redir[0])
07097          rsprintf("<input type=hidden name=redir value=\"%s\">\n", redir);
07098 
07099       rsprintf("<table border=1 cellpadding=5>");
07100 
07101       if (password[0])
07102          rsprintf("<tr><th bgcolor=#FF0000>Wrong password!</tr>\n");
07103 
07104       rsprintf
07105           ("<tr><th bgcolor=#A0A0FF>Please enter password to obtain write access</tr>\n");
07106       rsprintf("<tr><td align=center><input type=password name=wpwd></tr>\n");
07107       rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
07108 
07109       rsprintf("</table>\n");
07110 
07111       rsprintf("</body></html>\r\n");
07112 
07113       return FALSE;
07114    } else
07115       return TRUE;
07116 }
07117 
07118 /*------------------------------------------------------------------*/
07119 
07120 void show_start_page(void)
07121 {
07122    int rn, i, j, n, size, status, maxlength;
07123    HNDLE hDB, hkey, hsubkey, hkeycomm, hkeyc;
07124    KEY key;
07125    char data[1000], str[32];
07126    char data_str[256], comment[1000];
07127 
07128    cm_get_experiment_database(&hDB, NULL);
07129 
07130    show_header(hDB, "Start run", "GET", "", 1, 0);
07131 
07132    rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Start new run</tr>\n");
07133    rsprintf("<tr><td>Run number");
07134 
07135    /* run number */
07136    size = sizeof(rn);
07137    status = db_get_value(hDB, 0, "/Runinfo/Run number", &rn, &size, TID_INT, TRUE);
07138    assert(status == SUCCESS);
07139 
07140    if (rn < 0) { // value "zero" is ok
07141       cm_msg(MERROR, "show_start_page",
07142              "aborting on attempt to use invalid run number %d", rn);
07143       abort();
07144    }
07145 
07146    size = sizeof(i);
07147    if (db_find_key(hDB, 0, "/Experiment/Edit on start/Edit Run number", &hkey) ==
07148        DB_SUCCESS && db_get_data(hDB, hkey, &i, &size, TID_BOOL) && i == 0)
07149       rsprintf("<td><input type=hidden name=value value=%d>%d</tr>\n", rn + 1, rn + 1);
07150    else
07151       rsprintf("<td><input type=text size=20 maxlength=80 name=value value=%d></tr>\n",
07152                rn + 1);
07153 
07154    /* run parameters */
07155    db_find_key(hDB, 0, "/Experiment/Edit on start", &hkey);
07156    db_find_key(hDB, 0, "/Experiment/Parameter Comments", &hkeycomm);
07157    if (hkey) {
07158       for (i = 0, n = 0;; i++) {
07159          db_enum_link(hDB, hkey, i, &hsubkey);
07160 
07161          if (!hsubkey)
07162             break;
07163 
07164          db_get_link(hDB, hsubkey, &key);
07165          strlcpy(str, key.name, sizeof(str));
07166 
07167          if (equal_ustring(str, "Edit run number"))
07168             continue;
07169 
07170          db_enum_key(hDB, hkey, i, &hsubkey);
07171          db_get_key(hDB, hsubkey, &key);
07172 
07173          size = sizeof(data);
07174          status = db_get_data(hDB, hsubkey, data, &size, key.type);
07175          if (status != DB_SUCCESS)
07176             continue;
07177 
07178          for (j = 0; j < key.num_values; j++) {
07179             if (key.num_values > 1)
07180                rsprintf("<tr><td>%s [%d]", str, j);
07181             else
07182                rsprintf("<tr><td>%s", str);
07183 
07184             if (j == 0 && hkeycomm) {
07185                /* look for comment */
07186                if (db_find_key(hDB, hkeycomm, key.name, &hkeyc) == DB_SUCCESS) {
07187                   size = sizeof(comment);
07188                   if (db_get_data(hDB, hkeyc, comment, &size, TID_STRING) == DB_SUCCESS)
07189                      rsprintf("<br>%s\n", comment);
07190                }
07191             }
07192 
07193             db_sprintf(data_str, data, key.item_size, j, key.type);
07194 
07195             maxlength = 80;
07196             if (key.type == TID_STRING)
07197                maxlength = key.item_size;
07198 
07199             if (key.type == TID_BOOL) {
07200                if (((DWORD*)data)[j])
07201                   rsprintf("<td><input type=checkbox checked name=x%d value=1></td></tr>\n", n++);
07202                else
07203                   rsprintf("<td><input type=checkbox name=x%d value=1></td></tr>\n", n++);
07204             } else
07205                rsprintf("<td><input type=text size=%d maxlength=%d name=x%d value=\"%s\"></tr>\n",
07206                         (maxlength<80)?maxlength:80, maxlength-1, n++, data_str);
07207          }
07208       }
07209    }
07210 
07211    rsprintf("<tr><td align=center colspan=2>\n");
07212    rsprintf("<input type=submit name=cmd value=Start>\n");
07213    rsprintf("<input type=submit name=cmd value=Cancel>\n");
07214    rsprintf("</tr>\n");
07215    rsprintf("</table>\n");
07216 
07217    if (isparam("redir"))
07218       rsprintf("<input type=hidden name=\"redir\" value=\"%s\">\n", getparam("redir"));
07219 
07220    rsprintf("</body></html>\r\n");
07221 }
07222 
07223 /*------------------------------------------------------------------*/
07224 
07225 void show_odb_page(char *enc_path, int enc_path_size, char *dec_path)
07226 {
07227    int i, j, size, status;
07228    char str[256], tmp_path[256], url_path[256], data_str[TEXT_SIZE], 
07229       hex_str[256], ref[256], keyname[32], link_name[256], link_ref[256],
07230       full_path[256], root_path[256];
07231    char *p, *pd;
07232    char data[TEXT_SIZE];
07233    HNDLE hDB, hkey, hkeyroot;
07234    KEY key;
07235 
07236    cm_get_experiment_database(&hDB, NULL);
07237 
07238    if (strcmp(enc_path, "root") == 0) {
07239       strcpy(enc_path, "");
07240       strcpy(dec_path, "");
07241    }
07242 
07243    strlcpy(str, dec_path, sizeof(str));
07244    if (strrchr(str, '/'))
07245       strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07246    show_header(hDB, "MIDAS online database", "GET", str, 1, 0);
07247 
07248    /* find key via path */
07249    status = db_find_key(hDB, 0, dec_path, &hkeyroot);
07250    if (status != DB_SUCCESS) {
07251       rsprintf("Error: cannot find key %s<P>\n", dec_path);
07252       rsprintf("</body></html>\r\n");
07253       return;
07254    }
07255 
07256    /* if key is not of type TID_KEY, cut off key name */
07257    db_get_key(hDB, hkeyroot, &key);
07258    if (key.type != TID_KEY) {
07259       /* strip variable name from path */
07260       p = dec_path + strlen(dec_path) - 1;
07261       while (*p && *p != '/')
07262          *p-- = 0;
07263       if (*p == '/')
07264          *p = 0;
07265 
07266       strlcpy(enc_path, dec_path, enc_path_size);
07267       urlEncode(enc_path, enc_path_size);
07268 
07269       status = db_find_key(hDB, 0, dec_path, &hkeyroot);
07270       if (status != DB_SUCCESS) {
07271          rsprintf("Error: cannot find key %s<P>\n", dec_path);
07272          rsprintf("</body></html>\r\n");
07273          return;
07274       }
07275    }
07276 
07277    /*---- menu buttons ----*/
07278 
07279    rsprintf("<tr><td colspan=2 bgcolor=#A0A0A0>\n");
07280    if (elog_mode) {
07281       rsprintf("<input type=submit name=cmd value=ELog>\n");
07282       rsprintf("</tr>\n");
07283    } else {
07284       rsprintf("<input type=submit name=cmd value=Find>\n");
07285       rsprintf("<input type=submit name=cmd value=Create>\n");
07286       rsprintf("<input type=submit name=cmd value=Delete>\n");
07287       rsprintf("<input type=submit name=cmd value=Alarms>\n");
07288       rsprintf("<input type=submit name=cmd value=Programs>\n");
07289       rsprintf("<input type=submit name=cmd value=Status>\n");
07290       rsprintf("<input type=submit name=cmd value=Help>\n");
07291       rsprintf("</tr>\n");
07292 
07293       rsprintf("<tr><td colspan=2 bgcolor=#A0A0A0>\n");
07294       rsprintf("<input type=submit name=cmd value=\"Create Elog from this page\">\n");
07295       rsprintf("</tr>\n");
07296    }
07297 
07298    /*---- ODB display -----------------------------------------------*/
07299 
07300    /* add one "../" for each level */
07301    tmp_path[0] = 0;
07302    for (p = dec_path ; *p ; p++)
07303       if (*p == '/')
07304          strlcat(tmp_path, "../", sizeof(tmp_path));
07305 
07306    p = dec_path;
07307    if (*p == '/')
07308       p++;
07309 
07310    /* display root key */
07311    rsprintf("<tr><td colspan=2 align=center><b>");
07312    rsprintf("<a href=\"%sroot\">/</a> \n", tmp_path);
07313    strlcpy(root_path, tmp_path, sizeof(root_path));
07314 
07315    /*---- display path ----*/
07316    while (*p) {
07317       pd = str;
07318       while (*p && *p != '/')
07319          *pd++ = *p++;
07320       *pd = 0;
07321 
07322       strlcat(tmp_path, str, sizeof(tmp_path));
07323       strlcpy(url_path, tmp_path, sizeof(url_path));
07324       urlEncode(url_path, sizeof(url_path));
07325 
07326       rsprintf("<a href=\"%s\">%s</a>\n / ", url_path, str);
07327 
07328       strlcat(tmp_path, "/", sizeof(tmp_path));
07329       if (*p == '/')
07330          p++;
07331    }
07332    rsprintf("</b></tr>\n");
07333 
07334    rsprintf("<tr><th>Key<th>Value</tr>\n");
07335 
07336    /* enumerate subkeys */
07337    for (i = 0;; i++) {
07338       db_enum_link(hDB, hkeyroot, i, &hkey);
07339       if (!hkey)
07340          break;
07341       db_get_link(hDB, hkey, &key);
07342 
07343       if (strrchr(dec_path, '/'))
07344          strlcpy(str, strrchr(dec_path, '/')+1, sizeof(str));
07345       else
07346          strlcpy(str, dec_path, sizeof(str));
07347       if (str[0] && str[strlen(str) - 1] != '/')
07348          strlcat(str, "/", sizeof(str));
07349       strlcat(str, key.name, sizeof(str));
07350       strlcpy(full_path, str, sizeof(full_path));
07351       urlEncode(full_path, sizeof(full_path));
07352       strlcpy(keyname, key.name, sizeof(keyname));
07353 
07354       /* resolve links */
07355       link_name[0] = 0;
07356       status = DB_SUCCESS;
07357       if (key.type == TID_LINK) {
07358          size = sizeof(link_name);
07359          db_get_link_data(hDB, hkey, link_name, &size, TID_LINK);
07360          status = db_enum_key(hDB, hkeyroot, i, &hkey);
07361          db_get_key(hDB, hkey, &key);
07362       }
07363 
07364       if (link_name[0]) {
07365          if (root_path[strlen(root_path)-1] == '/' && link_name[0] == '/')
07366             sprintf(ref, "%s%s?cmd=Set", root_path, link_name+1);
07367          else
07368             sprintf(ref, "%s%s?cmd=Set", root_path, link_name);
07369          sprintf(link_ref, "%s?cmd=Set", full_path);
07370       } else
07371          sprintf(ref, "%s?cmd=Set", full_path);
07372 
07373       if (status != DB_SUCCESS) {
07374          rsprintf("<tr><td bgcolor=#FFFF00>");
07375          rsprintf("%s <i>-> <a href=\"%s\">%s</a></i><td><b><font color=\"red\">&lt;cannot resolve link&gt;</font><b></tr>\n",
07376               keyname, link_ref, link_name);
07377       } else {
07378          if (key.type == TID_KEY) {
07379             /* for keys, don't display data value */
07380             rsprintf("<tr><td colspan=2 bgcolor=#FFD000><a href=\"%s\">%s</a><br></tr>\n",
07381                     full_path, keyname);
07382          } else {
07383             /* display single value */
07384             if (key.num_values == 1) {
07385                size = sizeof(data);
07386                db_get_data(hDB, hkey, data, &size, key.type);
07387                db_sprintf(data_str, data, key.item_size, 0, key.type);
07388 
07389                if (key.type != TID_STRING)
07390                   db_sprintfh(hex_str, data, key.item_size, 0, key.type);
07391                else
07392                   hex_str[0] = 0;
07393 
07394                if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
07395                   strcpy(data_str, "(empty)");
07396                   hex_str[0] = 0;
07397                }
07398 
07399                if (strcmp(data_str, hex_str) != 0 && hex_str[0]) {
07400                   if (link_name[0]) {
07401                      rsprintf("<tr><td bgcolor=#FFFF00>");
07402                      rsprintf("%s <i>-> <a href=\"%s\">%s</a></i><td><a href=\"%s\">%s (%s)</a><br></tr>\n",
07403                           keyname, link_ref, link_name, ref, data_str, hex_str);
07404                   } else {
07405                      rsprintf("<tr><td bgcolor=#FFFF00>");
07406                      rsprintf("%s<td><a href=\"%s\">%s (%s)</a><br></tr>\n",
07407                               keyname, ref, data_str, hex_str);
07408                   }
07409                } else {
07410                   if (strchr(data_str, '\n')) {
07411                      if (link_name[0]) {
07412                         rsprintf("<tr><td bgcolor=#FFFF00>");
07413                         rsprintf("%s <i>-> <a href=\"%s\">%s</a></i><td>", keyname, link_ref, link_name);
07414                      } else
07415                         rsprintf("<tr><td bgcolor=#FFFF00>%s<td>", keyname);
07416                      rsprintf("\n<pre>");
07417                      strencode3(data_str);
07418                      rsprintf("</pre>");
07419                      if (strlen(data) > strlen(data_str))
07420                         rsprintf("<i>... (%d bytes total)<p>\n", strlen(data));
07421 
07422                      rsprintf("<a href=\"%s\">Edit</a></tr>\n", ref);
07423                   } else {
07424                      if (link_name[0]) {
07425                         rsprintf("<tr><td bgcolor=#FFFF00>");
07426                         rsprintf("%s <i>-> <a href=\"%s\">%s</a></i><td><a href=\"%s\">",
07427                              keyname, link_ref, link_name, ref);
07428                      } else
07429                         rsprintf("<tr><td bgcolor=#FFFF00>%s<td><a href=\"%s\">", keyname,
07430                                  ref);
07431                      strencode(data_str);
07432                      rsprintf("</a><br></tr>\n");
07433                   }
07434                }
07435             } else {
07436                /* check for exceeding length */
07437                if (key.num_values > 1000)
07438                   rsprintf("<tr><td bgcolor=#FFFF00>%s<td><i>... %d values ...</i>\n",
07439                            keyname, key.num_values);
07440                else {
07441                   /* display first value */
07442                   if (link_name[0])
07443                      rsprintf("<tr><td  bgcolor=#FFFF00 rowspan=%d>%s<br><i>-> %s</i>\n",
07444                               key.num_values, keyname, link_name);
07445                   else
07446                      rsprintf("<tr><td  bgcolor=#FFFF00 rowspan=%d>%s\n", key.num_values,
07447                               keyname);
07448 
07449                   for (j = 0; j < key.num_values; j++) {
07450                      size = sizeof(data);
07451                      db_get_data_index(hDB, hkey, data, &size, j, key.type);
07452                      db_sprintf(data_str, data, key.item_size, 0, key.type);
07453                      db_sprintfh(hex_str, data, key.item_size, 0, key.type);
07454 
07455                      if (data_str[0] == 0 || equal_ustring(data_str, "<NULL>")) {
07456                         strcpy(data_str, "(empty)");
07457                         hex_str[0] = 0;
07458                      }
07459 
07460                      sprintf(ref, "%s?cmd=Set&index=%d", full_path, j);
07461 
07462                      if (j > 0)
07463                         rsprintf("<tr>");
07464 
07465                      if (strcmp(data_str, hex_str) != 0 && hex_str[0])
07466                         rsprintf("<td><a href=\"%s\">[%d] %s (%s)</a><br></tr>\n", ref, j,
07467                                  data_str, hex_str);
07468                      else
07469                         rsprintf("<td><a href=\"%s\">[%d] %s</a><br></tr>\n", ref, j,
07470                                  data_str);
07471                   }
07472                }
07473             }
07474          }
07475       }
07476    }
07477 
07478    rsprintf("</table>\n");
07479    rsprintf("</body></html>\r\n");
07480 }
07481 
07482 /*------------------------------------------------------------------*/
07483 
07484 void show_set_page(char *enc_path, int enc_path_size, char *dec_path, const char *group,
07485                    int index, const char *value)
07486 {
07487    int status, size;
07488    HNDLE hDB, hkey;
07489    KEY key;
07490    char data_str[TEXT_SIZE], str[256], *p, eq_name[NAME_LENGTH];
07491    char data[TEXT_SIZE];
07492 
07493    cm_get_experiment_database(&hDB, NULL);
07494 
07495    /* show set page if no value is given */
07496    if (!isparam("value") && !*getparam("text")) {
07497       status = db_find_link(hDB, 0, dec_path, &hkey);
07498       if (status != DB_SUCCESS) {
07499          rsprintf("Error: cannot find key %s<P>\n", dec_path);
07500          return;
07501       }
07502       db_get_key(hDB, hkey, &key);
07503 
07504       strlcpy(str, dec_path, sizeof(str));
07505       if (strrchr(str, '/'))
07506          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07507       show_header(hDB, "Set value", "POST", str, 1, 0);
07508 
07509       if (index > 0)
07510          rsprintf("<input type=hidden name=index value=\"%d\">\n", index);
07511       else
07512          index = 0;
07513 
07514       if (group[0])
07515          rsprintf("<input type=hidden name=group value=\"%s\">\n", group);
07516 
07517       strlcpy(data_str, rpc_tid_name(key.type), sizeof(data_str));
07518       if (key.num_values > 1) {
07519          sprintf(str, "[%d]", key.num_values);
07520          strlcat(data_str, str, sizeof(data_str));
07521 
07522          sprintf(str, "%s[%d]", dec_path, index);
07523       } else
07524          strlcpy(str, dec_path, sizeof(str));
07525 
07526       rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Set new value - type = %s</tr>\n",
07527                data_str);
07528       rsprintf("<tr><td bgcolor=#FFFF00>%s<td>\n", str);
07529 
07530       /* set current value as default */
07531       size = sizeof(data);
07532       db_get_data(hDB, hkey, data, &size, key.type);
07533       db_sprintf(data_str, data, key.item_size, index, key.type);
07534 
07535       if (equal_ustring(data_str, "<NULL>"))
07536          data_str[0] = 0;
07537 
07538       if (strchr(data_str, '\n') != NULL) {
07539          rsprintf("<textarea rows=20 cols=80 name=\"text\">\n");
07540          strencode3(data);
07541          rsprintf("</textarea>\n");
07542       } else {
07543          size = 20;
07544          if ((int) strlen(data_str) > size)
07545             size = strlen(data_str) + 3;
07546          if (size > 80)
07547             size = 80;
07548 
07549          rsprintf("<input type=\"text\" size=%d maxlength=256 name=\"value\" value=\"", size);
07550          strencode(data_str);
07551          rsprintf("\">\n");
07552       }
07553 
07554       rsprintf("</tr>\n");
07555 
07556       rsprintf("<tr><td align=center colspan=2>");
07557       rsprintf("<input type=submit name=cmd value=Set>");
07558       rsprintf("<input type=submit name=cmd value=Cancel>");
07559       rsprintf("</tr>");
07560       rsprintf("</table>");
07561 
07562       rsprintf("<input type=hidden name=cmd value=Set>\n");
07563 
07564       rsprintf("</body></html>\r\n");
07565       return;
07566    } else {
07567       /* set value */
07568 
07569       status = db_find_link(hDB, 0, dec_path, &hkey);
07570       if (status != DB_SUCCESS) {
07571          rsprintf("Error: cannot find key %s<P>\n", dec_path);
07572          return;
07573       }
07574       db_get_key(hDB, hkey, &key);
07575 
07576       memset(data, 0, sizeof(data));
07577 
07578       if (*getparam("text"))
07579          strlcpy(data, getparam("text"), sizeof(data));
07580       else
07581          db_sscanf(value, data, &size, 0, key.type);
07582 
07583       if (index < 0)
07584          index = 0;
07585 
07586       /* extend data size for single string if necessary */
07587       if ((key.type == TID_STRING || key.type == TID_LINK)
07588           && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
07589          key.item_size = strlen(data) + 1;
07590 
07591       if (key.item_size == 0)
07592          key.item_size = rpc_tid_size(key.type);
07593 
07594       if (key.num_values > 1)
07595          status = db_set_link_data_index(hDB, hkey, data, key.item_size, index, key.type);
07596       else
07597          status = db_set_link_data(hDB, hkey, data, key.item_size, 1, key.type);
07598 
07599       if (status == DB_NO_ACCESS)
07600          rsprintf("<h2>Write access not allowed</h2>\n");
07601 
07602       /* strip variable name from path */
07603       p = dec_path + strlen(dec_path) - 1;
07604       while (*p && *p != '/')
07605          *p-- = 0;
07606       if (*p == '/')
07607          *p = 0;
07608 
07609       //strlcpy(enc_path, dec_path, enc_path_size);
07610       //urlEncode(enc_path, enc_path_size);
07611       enc_path[0] = 0;
07612 
07613       /* redirect */
07614 
07615       if (group[0]) {
07616          /* extract equipment name */
07617          eq_name[0] = 0;
07618          if (strncmp(enc_path, "Equipment/", 10) == 0) {
07619             strlcpy(eq_name, enc_path + 10, sizeof(eq_name));
07620             if (strchr(eq_name, '/'))
07621                *strchr(eq_name, '/') = 0;
07622          }
07623 
07624          /* back to SC display */
07625          sprintf(str, "SC/%s/%s", eq_name, group);
07626          redirect(str);
07627       } else
07628          redirect(enc_path);
07629 
07630       return;
07631    }
07632 
07633 }
07634 
07635 /*------------------------------------------------------------------*/
07636 
07637 void show_find_page(const char *enc_path, const char *value)
07638 {
07639    HNDLE hDB, hkey;
07640    char str[256];
07641 
07642    cm_get_experiment_database(&hDB, NULL);
07643 
07644    if (value[0] == 0) {
07645       /* without value, show find dialog */
07646       str[0] = 0;
07647       for (const char* p=enc_path ; *p ; p++)
07648          if (*p == '/')
07649             strlcat(str, "../", sizeof(str));
07650       show_header(hDB, "Find value", "GET", str, 1, 0);
07651 
07652       rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Find string in Online Database</tr>\n");
07653       rsprintf("<tr><td>Enter substring (case insensitive)\n");
07654 
07655       rsprintf("<td><input type=\"text\" size=\"20\" maxlength=\"80\" name=\"value\">\n");
07656       rsprintf("</tr>");
07657 
07658       rsprintf("<tr><td align=center colspan=2>");
07659       rsprintf("<input type=submit name=cmd value=Find>");
07660       rsprintf("<input type=submit name=cmd value=Cancel>");
07661       rsprintf("</tr>");
07662       rsprintf("</table>");
07663 
07664       rsprintf("<input type=hidden name=cmd value=Find>");
07665 
07666       rsprintf("</body></html>\r\n");
07667    } else {
07668       strlcpy(str, enc_path, sizeof(str));
07669       if (strrchr(str, '/'))
07670          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07671       show_header(hDB, "Search results", "GET", str, 1, 0);
07672 
07673       rsprintf("<tr><td colspan=2 bgcolor=#A0A0A0>\n");
07674       rsprintf("<input type=submit name=cmd value=Find>\n");
07675       rsprintf("<input type=submit name=cmd value=ODB>\n");
07676       rsprintf("<input type=submit name=cmd value=Help>\n");
07677       rsprintf("</tr>\n\n");
07678 
07679       rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>");
07680       rsprintf("Results of search for substring \"%s\"</tr>\n", value);
07681       rsprintf("<tr><th>Key<th>Value</tr>\n");
07682 
07683       /* start from root */
07684       db_find_key(hDB, 0, "", &hkey);
07685       assert(hkey);
07686 
07687       /* scan tree, call "search_callback" for each key */
07688       db_scan_tree(hDB, hkey, 0, search_callback, (void *) value);
07689 
07690       rsprintf("</table>");
07691       rsprintf("</body></html>\r\n");
07692    }
07693 }
07694 
07695 /*------------------------------------------------------------------*/
07696 
07697 void show_create_page(const char *enc_path, const char *dec_path, const char *value, int index, int type)
07698 {
07699    char str[256], link[256], error[256], *p;
07700    char data[10000];
07701    int status;
07702    HNDLE hDB, hkey;
07703    KEY key;
07704 
07705    cm_get_experiment_database(&hDB, NULL);
07706 
07707    if (value[0] == 0) {
07708       /* without value, show create dialog */
07709 
07710       strlcpy(str, enc_path, sizeof(str));
07711       if (strrchr(str, '/'))
07712          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07713       show_header(hDB, "Create ODB entry", "GET", str, 1, 0);
07714 
07715       rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Create ODB entry</tr>\n");
07716 
07717       rsprintf("<tr><td>Type");
07718       rsprintf("<td><select type=text size=1 name=type>\n");
07719 
07720       rsprintf("<option value=7> Integer (32-bit)\n");
07721       rsprintf("<option value=9> Float (4 Bytes)\n");
07722       rsprintf("<option value=12> String\n");
07723       rsprintf("<option value=13> Multi-line String\n");
07724       rsprintf("<option value=15> Subdirectory\n");
07725 
07726       rsprintf("<option value=1> Byte\n");
07727       rsprintf("<option value=2> Signed byte\n");
07728       rsprintf("<option value=3> Character (8-bit)\n");
07729       rsprintf("<option value=4> Word (16-bit)\n");
07730       rsprintf("<option value=5> Short integer(16-bit)\n");
07731       rsprintf("<option value=6> Double Word (32-bit)\n");
07732       rsprintf("<option value=8> Boolean\n");
07733       rsprintf("<option value=10> Double float(8 Bytes)\n");
07734       rsprintf("<option value=16> Symbolic link\n");
07735 
07736       rsprintf("</select></tr>\n");
07737 
07738       rsprintf("<tr><td>Name");
07739       rsprintf("<td><input type=text size=20 maxlength=80 name=value>\n");
07740       rsprintf("</tr>");
07741 
07742       rsprintf("<tr><td>Array size");
07743       rsprintf("<td><input type=text size=20 maxlength=80 name=index value=1>\n");
07744       rsprintf("</tr>");
07745 
07746       rsprintf("<tr><td align=center colspan=2>");
07747       rsprintf("<input type=submit name=cmd value=Create>");
07748       rsprintf("<input type=submit name=cmd value=Cancel>");
07749       rsprintf("</tr>");
07750       rsprintf("</table>");
07751 
07752       rsprintf("</body></html>\r\n");
07753    } else {
07754       if (type == TID_LINK) {
07755          /* check if destination exists */
07756          status = db_find_key(hDB, 0, value, &hkey);
07757          if (status != DB_SUCCESS) {
07758             rsprintf("<h1>Error: Link destination \"%s\" does not exist!</h1>", value);
07759             return;
07760          }
07761 
07762          /* extract key name from destination */
07763          strlcpy(str, value, sizeof(str));
07764          p = str + strlen(str) - 1;
07765          while (*p && *p != '/')
07766             p--;
07767          p++;
07768 
07769          /* use it as link name */
07770          strlcpy(link, p, sizeof(link));
07771 
07772          strlcpy(str, dec_path, sizeof(str));
07773          if (str[strlen(str) - 1] != '/')
07774             strlcat(str, "/", sizeof(str));
07775          strlcat(str, link, sizeof(str));
07776 
07777          status = db_create_link(hDB, 0, str, value);
07778          if (status != DB_SUCCESS) {
07779             sprintf(error, "Cannot create key %s</h1>\n", str);
07780             show_error(error);
07781             return;
07782          }
07783 
07784       } else {
07785          if (dec_path[0] != '/')
07786             strcpy(str, "/");
07787          else
07788             str[0] = 0;
07789          strlcat(str, dec_path, sizeof(str));
07790          if (str[strlen(str) - 1] != '/')
07791             strlcat(str, "/", sizeof(str));
07792          strlcat(str, value, sizeof(str));
07793 
07794          if (type == TID_ARRAY)
07795             /* multi-line string */
07796             status = db_create_key(hDB, 0, str, TID_STRING);
07797          else
07798             status = db_create_key(hDB, 0, str, type);
07799          if (status != DB_SUCCESS) {
07800             sprintf(error, "Cannot create key %s</h1>\n", str);
07801             show_error(error);
07802             return;
07803          }
07804 
07805          db_find_key(hDB, 0, str, &hkey);
07806          assert(hkey);
07807          db_get_key(hDB, hkey, &key);
07808          memset(data, 0, sizeof(data));
07809          if (key.type == TID_STRING || key.type == TID_LINK)
07810             key.item_size = NAME_LENGTH;
07811          if (type == TID_ARRAY)
07812             strcpy(data, "\n");
07813 
07814          if (index > 1)
07815             db_set_data_index(hDB, hkey, data, key.item_size, index - 1, key.type);
07816          else if (key.type == TID_STRING || key.type == TID_LINK)
07817             db_set_data(hDB, hkey, data, key.item_size, 1, key.type);
07818       }
07819 
07820       /* redirect */
07821       strlcpy(str, enc_path, sizeof(str));
07822       if (strrchr(str, '/'))
07823          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07824       redirect(str);
07825       return;
07826    }
07827 }
07828 
07829 /*------------------------------------------------------------------*/
07830 
07831 void show_delete_page(const char *enc_path, const char *dec_path, const char *value, int index)
07832 {
07833    char str[256];
07834    int i, status;
07835    HNDLE hDB, hkeyroot, hkey;
07836    KEY key;
07837 
07838    cm_get_experiment_database(&hDB, NULL);
07839 
07840    if (value[0] == 0) {
07841       /* without value, show delete dialog */
07842 
07843       strlcpy(str, enc_path, sizeof(str));
07844       if (strrchr(str, '/'))
07845          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07846       show_header(hDB, "Delete ODB entry", "GET", str, 1, 0);
07847 
07848       rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Delete ODB entry</tr>\n");
07849 
07850       /* find key via from */
07851       status = db_find_key(hDB, 0, dec_path, &hkeyroot);
07852       if (status != DB_SUCCESS) {
07853          rsprintf("Error: cannot find key %s<P>\n", dec_path);
07854          rsprintf("</body></html>\r\n");
07855          return;
07856       }
07857 
07858       /* count keys */
07859       for (i = 0;; i++) {
07860          db_enum_key(hDB, hkeyroot, i, &hkey);
07861          if (!hkey)
07862             break;
07863       }
07864 
07865       rsprintf("<tr><td align=center colspan=2><select type=text size=%d name=value>\n",
07866                i);
07867 
07868       /* enumerate subkeys */
07869       for (i = 0;; i++) {
07870          db_enum_link(hDB, hkeyroot, i, &hkey);
07871          if (!hkey)
07872             break;
07873          db_get_link(hDB, hkey, &key);
07874          rsprintf("<option> %s\n", key.name);
07875       }
07876 
07877       rsprintf("</select></tr>\n");
07878 
07879       rsprintf("<tr><td align=center colspan=2>");
07880       rsprintf("<input type=submit name=cmd value=Delete>");
07881       rsprintf("<input type=submit name=cmd value=Cancel>");
07882       rsprintf("</tr>");
07883       rsprintf("</table>");
07884 
07885       rsprintf("</body></html>\r\n");
07886    } else {
07887       strlcpy(str, dec_path, sizeof(str));
07888       if (str[strlen(str) - 1] != '/')
07889          strlcat(str, "/", sizeof(str));
07890       strlcat(str, value, sizeof(str));
07891 
07892       status = db_find_link(hDB, 0, str, &hkey);
07893       if (status != DB_SUCCESS) {
07894          rsprintf("<h1>Cannot find key %s</h1>\n", str);
07895          return;
07896       }
07897 
07898       status = db_delete_key(hDB, hkey, FALSE);
07899       if (status != DB_SUCCESS) {
07900          rsprintf("<h1>Cannot delete key %s</h1>\n", str);
07901          return;
07902       }
07903 
07904       /* redirect */
07905       strlcpy(str, enc_path, sizeof(str));
07906       if (strrchr(str, '/'))
07907          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
07908       redirect(str);
07909       return;
07910    }
07911 }
07912 
07913 /*------------------------------------------------------------------*/
07914 
07915 void show_alarm_page()
07916 {
07917    INT i, size, triggered, type, index, ai;
07918    BOOL active;
07919    HNDLE hDB, hkeyroot, hkey;
07920    KEY key;
07921    char str[256], ref[256], condition[256], value[256];
07922    time_t now, last, interval;
07923    INT al_list[] = { AT_EVALUATED, AT_PROGRAM, AT_INTERNAL, AT_PERIODIC };
07924 
07925    cm_get_experiment_database(&hDB, NULL);
07926 
07927    /* header */
07928    rsprintf("HTTP/1.0 200 Document follows\r\n");
07929    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
07930    rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
07931 
07932    rsprintf("<html><head>\n");
07933    rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
07934    rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
07935    rsprintf("<title>Alarms</title></head>\n");
07936    rsprintf("<body>\n");
07937 
07938    /* title row */
07939    size = sizeof(str);
07940    str[0] = 0;
07941    db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
07942    time(&now);
07943 
07944    rsprintf("<form method=\"GET\" action=\".\">\n");
07945 
07946    rsprintf("<table border=3 cellpadding=2>\n");
07947    rsprintf("<tr><th colspan=4 bgcolor=#A0A0FF>MIDAS experiment \"%s\"", str);
07948    rsprintf("<th colspan=3 bgcolor=#A0A0FF>%s</tr>\n", ctime(&now));
07949 
07950    /*---- menu buttons ----*/
07951 
07952    rsprintf("<tr>\n");
07953    rsprintf("<td colspan=7 bgcolor=#C0C0C0>\n");
07954 
07955    rsprintf("<input type=submit name=cmd value=\"Reset all alarms\">\n");
07956    rsprintf("<input type=submit name=cmd value=\"Alarms on/off\">\n");
07957    rsprintf("<input type=submit name=cmd value=Status>\n");
07958 
07959    rsprintf("</tr></form>\n\n");
07960 
07961    /*---- global flag ----*/
07962 
07963    active = TRUE;
07964    size = sizeof(active);
07965    db_get_value(hDB, 0, "/Alarms/Alarm System active", &active, &size, TID_BOOL, TRUE);
07966    if (!active) {
07967       sprintf(ref, "Alarms/Alarm System active?cmd=set");
07968       rsprintf("<tr><td align=center colspan=7 bgcolor=#FFC0C0><a href=\"%s\"><h1>Alarm system disabled</h1></a></tr>",
07969            ref);
07970    }
07971 
07972    /*---- alarms ----*/
07973 
07974    for (ai = 0; ai < AT_LAST; ai++) {
07975       index = al_list[ai];
07976 
07977       if (index == AT_EVALUATED) {
07978          rsprintf
07979              ("<tr><th align=center colspan=7 bgcolor=#C0C0C0>Evaluated alarms</tr>\n");
07980          rsprintf
07981              ("<tr><th>Alarm<th>State<th>First triggered<th>Class<th>Condition<th>Current value<th></tr>\n");
07982       } else if (index == AT_PROGRAM) {
07983          rsprintf("<tr><th align=center colspan=7 bgcolor=#C0C0C0>Program alarms</tr>\n");
07984          rsprintf
07985              ("<tr><th>Alarm<th>State<th>First triggered<th>Class<th colspan=2>Condition<th></tr>\n");
07986       } else if (index == AT_INTERNAL) {
07987          rsprintf
07988              ("<tr><th align=center colspan=7 bgcolor=#C0C0C0>Internal alarms</tr>\n");
07989          rsprintf
07990              ("<tr><th>Alarm<th>State<th>First triggered<th>Class<th colspan=2>Condition/Message<th></tr>\n");
07991       } else if (index == AT_PERIODIC) {
07992          rsprintf
07993              ("<tr><th align=center colspan=7 bgcolor=#C0C0C0>Periodic alarms</tr>\n");
07994          rsprintf
07995              ("<tr><th>Alarm<th>State<th>First triggered<th>Class<th colspan=2>Time/Message<th></tr>\n");
07996       }
07997 
07998       /* go through all alarms */
07999       db_find_key(hDB, 0, "/Alarms/Alarms", &hkeyroot);
08000       if (hkeyroot) {
08001          for (i = 0;; i++) {
08002             db_enum_link(hDB, hkeyroot, i, &hkey);
08003 
08004             if (!hkey)
08005                break;
08006 
08007             db_get_key(hDB, hkey, &key);
08008 
08009             /* type */
08010             size = sizeof(INT);
08011             db_get_value(hDB, hkey, "Type", &type, &size, TID_INT, TRUE);
08012             if (type != index)
08013                continue;
08014 
08015             /* start form for each alarm to make "reset" button work */
08016             sprintf(ref, "%s", key.name);
08017 
08018             rsprintf("<form method=\"GET\" action=\"%s\">\n", ref);
08019 
08020             /* alarm name */
08021             sprintf(ref, "Alarms/Alarms/%s", key.name);
08022             rsprintf("<tr><td bgcolor=#C0C0FF><a href=\"%s\"><b>%s</b></a>", ref,
08023                      key.name);
08024 
08025             /* state */
08026             size = sizeof(BOOL);
08027             db_get_value(hDB, hkey, "Active", &active, &size, TID_BOOL, TRUE);
08028             size = sizeof(INT);
08029             db_get_value(hDB, hkey, "Triggered", &triggered, &size, TID_INT, TRUE);
08030             if (!active)
08031                rsprintf("<td bgcolor=#FFFF00 align=center>Disabled");
08032             else {
08033                if (!triggered)
08034                   rsprintf("<td bgcolor=#00FF00 align=center>OK");
08035                else
08036                   rsprintf("<td bgcolor=#FF0000 align=center>Triggered");
08037             }
08038 
08039             /* time */
08040             size = sizeof(str);
08041             db_get_value(hDB, hkey, "Time triggered first", str, &size, TID_STRING, TRUE);
08042             if (!triggered)
08043                strcpy(str, "-");
08044             rsprintf("<td align=center>%s", str);
08045 
08046             /* class */
08047             size = sizeof(str);
08048             db_get_value(hDB, hkey, "Alarm Class", str, &size, TID_STRING, TRUE);
08049 
08050             sprintf(ref, "Alarms/Classes/%s", str);
08051             rsprintf("<td align=center><a href=\"%s\">%s</a>", ref, str);
08052 
08053             /* condition */
08054             size = sizeof(condition);
08055             db_get_value(hDB, hkey, "Condition", condition, &size, TID_STRING, TRUE);
08056 
08057             if (index == AT_EVALUATED) {
08058                /* print condition */
08059                rsprintf("<td>");
08060                strencode(condition);
08061 
08062                /* retrieve value */
08063                al_evaluate_condition(condition, value);
08064                rsprintf("<td align=center bgcolor=#C0C0FF>%s", value);
08065             } else if (index == AT_PROGRAM) {
08066                /* print condition */
08067                rsprintf("<td colspan=2>");
08068                strencode(condition);
08069             } else if (index == AT_INTERNAL) {
08070                size = sizeof(str);
08071                if (triggered)
08072                   db_get_value(hDB, hkey, "Alarm message", str, &size, TID_STRING, TRUE);
08073                else
08074                   db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
08075 
08076                rsprintf("<td colspan=2>%s", str);
08077             } else if (index == AT_PERIODIC) {
08078                size = sizeof(str);
08079                if (triggered)
08080                   db_get_value(hDB, hkey, "Alarm message", str, &size, TID_STRING, TRUE);
08081                else {
08082                   size = sizeof(last);
08083                   db_get_value(hDB, hkey, "Checked last", &last, &size, TID_DWORD, TRUE);
08084                   if (last == 0) {
08085                      last = ss_time();
08086                      db_set_value(hDB, hkey, "Checked last", &last, size, 1, TID_DWORD);
08087                   }
08088 
08089                   size = sizeof(interval);
08090                   db_get_value(hDB, hkey, "Check interval", &interval, &size, TID_INT,
08091                                TRUE);
08092                   last += interval;
08093                   
08094                   if (ctime(&last) == NULL)
08095                      strcpy(value, "<invalid>");
08096                   else
08097                      strcpy(value, ctime(&last));
08098                   value[16] = 0;
08099 
08100                   sprintf(str, "Alarm triggers at %s", value);
08101                }
08102 
08103                rsprintf("<td colspan=2>%s", str);
08104             }
08105 
08106             rsprintf("<td>\n");
08107             if (triggered)
08108                rsprintf("<input type=submit name=cmd value=\"Reset\">\n");
08109             else
08110                rsprintf(" &nbsp;&nbsp;&nbsp;&nbsp;");
08111 
08112             rsprintf("</tr>\n");
08113             rsprintf("</form>\n");
08114          }
08115       }
08116    }
08117 
08118    rsprintf("</table>\n");
08119    rsprintf("</body></html>\r\n");
08120 }
08121 
08122 /*------------------------------------------------------------------*/
08123 
08124 void show_programs_page()
08125 {
08126    INT i, j, k, size, count, status;
08127    BOOL restart, first, required, client;
08128    HNDLE hDB, hkeyroot, hkey, hkey_rc, hkeycl;
08129    KEY key, keycl;
08130    char str[256], ref[256], command[256], name[80], name_addon[80];
08131 
08132    cm_get_experiment_database(&hDB, NULL);
08133 
08134    /* stop command */
08135    if (*getparam("Stop")) {
08136       status = cm_shutdown(getparam("Stop") + 5, FALSE);
08137 
08138       if (status == CM_SUCCESS)
08139          redirect("./?cmd=programs");
08140       else {
08141          sprintf(str,
08142                  "Cannot shut down client \"%s\", please kill manually and do an ODB cleanup",
08143                  getparam("Stop") + 5);
08144          show_error(str);
08145       }
08146 
08147       return;
08148    }
08149 
08150    /* start command */
08151    if (*getparam("Start")) {
08152       /* for NT: close reply socket before starting subprocess */
08153       redirect2("./?cmd=programs");
08154 
08155       strlcpy(name, getparam("Start") + 6, sizeof(name));
08156       if (strchr(name, '?'))
08157          *strchr(name, '?') = 0;
08158       strlcpy(str, "/Programs/", sizeof(str));
08159       strlcat(str, name, sizeof(str));
08160       strlcat(str, "/Start command", sizeof(str));
08161       command[0] = 0;
08162       size = sizeof(command);
08163       db_get_value(hDB, 0, str, command, &size, TID_STRING, FALSE);
08164       if (command[0]) {
08165          ss_system(command);
08166          for (i = 0; i < 50; i++) {
08167             if (cm_exist(name, FALSE) == CM_SUCCESS)
08168                break;
08169             ss_sleep(100);
08170          }
08171       }
08172 
08173       return;
08174    }
08175 
08176    show_header(hDB, "Programs", "GET", "", 3, 0);
08177 
08178    /*---- menu buttons ----*/
08179 
08180    rsprintf("<tr><td colspan=6 bgcolor=#C0C0C0>\n");
08181 
08182    rsprintf("<input type=submit name=cmd value=Alarms>\n");
08183    rsprintf("<input type=submit name=cmd value=Status>\n");
08184    rsprintf("</tr>\n\n");
08185 
08186    rsprintf("<input type=hidden name=cmd value=Programs>\n");
08187 
08188    /*---- programs ----*/
08189 
08190    rsprintf("<tr><th>Program<th>Running on host<th>Alarm class<th>Autorestart</tr>\n");
08191 
08192    /* go through all programs */
08193    db_find_key(hDB, 0, "/Programs", &hkeyroot);
08194    if (hkeyroot) {
08195       for (i = 0;; i++) {
08196          db_enum_key(hDB, hkeyroot, i, &hkey);
08197 
08198          if (!hkey)
08199             break;
08200 
08201          db_get_key(hDB, hkey, &key);
08202 
08203          /* skip "execute on xxxx" */
08204          if (key.type != TID_KEY)
08205             continue;
08206 
08207          sprintf(ref, "Programs/%s", key.name);
08208 
08209          /* required? */
08210          size = sizeof(required);
08211          db_get_value(hDB, hkey, "Required", &required, &size, TID_BOOL, TRUE);
08212 
08213          /* running */
08214          count = 0;
08215          if (db_find_key(hDB, 0, "/System/Clients", &hkey_rc) == DB_SUCCESS) {
08216             first = TRUE;
08217             for (j = 0;; j++) {
08218                db_enum_key(hDB, hkey_rc, j, &hkeycl);
08219                if (!hkeycl)
08220                   break;
08221 
08222                size = sizeof(name);
08223                memset(name, 0, size);
08224                db_get_value(hDB, hkeycl, "Name", name, &size, TID_STRING, TRUE);
08225 
08226                db_get_key(hDB, hkeycl, &keycl);
08227                
08228                // check if client name is longer than the program name
08229                // necessary for multiple started processes which will have names
08230                // as client_name, client_name1, ...
08231                client = TRUE;
08232                if (strlen(name) > strlen(key.name)) {
08233                   size = strlen(name)-strlen(key.name);
08234                   memcpy(name_addon, name+strlen(key.name), size);
08235                   name_addon[size] = 0;
08236                   for (k=0; k<size; k++) {
08237                      if (!isdigit(name_addon[k])) {
08238                         client = FALSE;
08239                         break;
08240                      }
08241                   }  
08242                }
08243                name[strlen(key.name)] = 0;
08244 
08245                if (equal_ustring(name, key.name) && client) {
08246                   size = sizeof(str);
08247                   db_get_value(hDB, hkeycl, "Host", str, &size, TID_STRING, TRUE);
08248 
08249                   if (first) {
08250                      rsprintf("<tr><td bgcolor=#C0C0FF><a href=\"%s\"><b>%s</b></a>", ref,
08251                               key.name);
08252                      rsprintf("<td align=center bgcolor=#00FF00>");
08253                   }
08254                   if (!first)
08255                      rsprintf("<br>");
08256                   rsprintf(str);
08257 
08258                   first = FALSE;
08259                   count++;
08260                }
08261             }
08262          }
08263 
08264          if (count == 0 && required) {
08265             rsprintf("<tr><td bgcolor=#C0C0FF><a href=\"%s\"><b>%s</b></a>", ref,
08266                      key.name);
08267             rsprintf("<td align=center bgcolor=#FF0000>Not running");
08268          }
08269 
08270          /* dont display non-running programs which are not required */
08271          if (count == 0 && !required)
08272             continue;
08273 
08274          /* Alarm */
08275          size = sizeof(str);
08276          db_get_value(hDB, hkey, "Alarm Class", str, &size, TID_STRING, TRUE);
08277          if (str[0]) {
08278             sprintf(ref, "Alarms/Classes/%s", str);
08279             rsprintf("<td bgcolor=#FFFF00 align=center><a href=\"%s\">%s</a>", ref, str);
08280          } else
08281             rsprintf("<td align=center>-");
08282 
08283          /* auto restart */
08284          size = sizeof(restart);
08285          db_get_value(hDB, hkey, "Auto restart", &restart, &size, TID_BOOL, TRUE);
08286 
08287          if (restart)
08288             rsprintf("<td align=center>Yes\n");
08289          else
08290             rsprintf("<td align=center>No\n");
08291 
08292          /* start/stop button */
08293          size = sizeof(str);
08294          db_get_value(hDB, hkey, "Start Command", str, &size, TID_STRING, TRUE);
08295          if (str[0] && count == 0) {
08296             sprintf(str, "Start %s", key.name);
08297             rsprintf("<td align=center><input type=submit name=\"Start\" value=\"%s\">\n",
08298                      str);
08299          }
08300 
08301          if (count > 0 && strncmp(key.name, "mhttpd", 6) != 0) {
08302             sprintf(str, "Stop %s", key.name);
08303             rsprintf("<td align=center><input type=submit name=\"Stop\" value=\"%s\">\n",
08304                      str);
08305          }
08306 
08307          rsprintf("</tr>\n");
08308       }
08309    }
08310 
08311 
08312    rsprintf("</table>\n");
08313    rsprintf("</body></html>\r\n");
08314 }
08315 
08316 /*------------------------------------------------------------------*/
08317 
08318 void show_config_page(int refresh)
08319 {
08320    char str[80];
08321    HNDLE hDB;
08322 
08323    cm_get_experiment_database(&hDB, NULL);
08324 
08325    show_header(hDB, "Configure", "GET", "", 1, 0);
08326 
08327    rsprintf("<tr><th bgcolor=#A0A0FF colspan=2>Configure</tr>\n");
08328 
08329    rsprintf("<tr><td bgcolor=#FFFF00>Update period\n");
08330 
08331    sprintf(str, "5");
08332    rsprintf("<td><input type=text size=5 maxlength=5 name=refr value=%d>\n", refresh);
08333    rsprintf("</tr>\n");
08334 
08335    rsprintf("<tr><td align=center colspan=2>\n");
08336    rsprintf("<input type=submit name=cmd value=Accept>\n");
08337    rsprintf("<input type=submit name=cmd value=Cancel>\n");
08338    rsprintf("<input type=hidden name=cmd value=Accept>\n");
08339    rsprintf("</tr>\n");
08340    rsprintf("</table>\n");
08341 
08342    rsprintf("</body></html>\r\n");
08343 }
08344 
08345 /*------------------------------------------------------------------*/
08346 
08347 #define LN10 2.302585094
08348 #define LOG2 0.301029996
08349 #define LOG5 0.698970005
08350 
08351 void haxis(gdImagePtr im, gdFont * font, int col, int gcol,
08352            int x1, int y1, int width,
08353            int minor, int major, int text, int label, int grid, double xmin, double xmax)
08354 {
08355    double dx, int_dx, frac_dx, x_act, label_dx, major_dx, x_screen, maxwidth;
08356    int tick_base, major_base, label_base, n_sig1, n_sig2, xs;
08357    char str[80];
08358    double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
08359 
08360    if (xmax <= xmin || width <= 0)
08361       return;
08362 
08363    /* use 5 as min tick distance */
08364    dx = (xmax - xmin) / (double) (width / 5);
08365 
08366    frac_dx = modf(log(dx) / LN10, &int_dx);
08367    if (frac_dx < 0) {
08368       frac_dx += 1;
08369       int_dx -= 1;
08370    }
08371 
08372    tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
08373    major_base = label_base = tick_base + 1;
08374 
08375    /* rounding up of dx, label_dx */
08376    dx = pow(10, int_dx) * base[tick_base];
08377    major_dx = pow(10, int_dx) * base[major_base];
08378    label_dx = major_dx;
08379 
08380    /* number of significant digits */
08381    if (xmin == 0)
08382       n_sig1 = 0;
08383    else
08384       n_sig1 =
08385           (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) +
08386           1;
08387 
08388    if (xmax == 0)
08389       n_sig2 = 0;
08390    else
08391       n_sig2 =
08392           (int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) +
08393           1;
08394 
08395    n_sig1 = MAX(n_sig1, n_sig2);
08396    n_sig1 = MAX(n_sig1, 4);
08397 
08398    /* determination of maximal width of labels */
08399    sprintf(str, "%1.*lG", n_sig1, floor(xmin / dx) * dx);
08400    maxwidth = font->h / 2 * strlen(str);
08401    sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx);
08402    maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
08403    sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx + label_dx);
08404    maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
08405 
08406    /* increasing label_dx, if labels would overlap */
08407    while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
08408       label_base++;
08409       label_dx = pow(10, int_dx) * base[label_base];
08410       if (label_base % 3 == 2 && major_base % 3 == 1) {
08411          major_base++;
08412          major_dx = pow(10, int_dx) * base[major_base];
08413       }
08414    }
08415 
08416    x_act = floor(xmin / dx) * dx;
08417 
08418    gdImageLine(im, x1, y1, x1 + width, y1, col);
08419 
08420    do {
08421       x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
08422       xs = (int) (x_screen + 0.5);
08423 
08424       if (x_screen > x1 + width + 0.001)
08425          break;
08426 
08427       if (x_screen >= x1) {
08428          if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
08429              dx / major_dx / 10.0) {
08430 
08431             if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
08432                 dx / label_dx / 10.0) {
08433                /* label tick mark */
08434                gdImageLine(im, xs, y1, xs, y1 + text, col);
08435 
08436                /* grid line */
08437                if (grid != 0 && xs > x1 && xs < x1 + width)
08438                   gdImageLine(im, xs, y1, xs, y1 + grid, col);
08439 
08440                /* label */
08441                if (label != 0) {
08442                   sprintf(str, "%1.*lG", n_sig1, x_act);
08443                   gdImageString(im, font, (int) xs - font->w * strlen(str) / 2,
08444                                 y1 + label, str, col);
08445                }
08446             } else {
08447                /* major tick mark */
08448                gdImageLine(im, xs, y1, xs, y1 + major, col);
08449 
08450                /* grid line */
08451                if (grid != 0 && xs > x1 && xs < x1 + width)
08452                   gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
08453             }
08454 
08455          } else
08456             /* minor tick mark */
08457             gdImageLine(im, xs, y1, xs, y1 + minor, col);
08458 
08459       }
08460 
08461       x_act += dx;
08462 
08463       /* supress 1.23E-17 ... */
08464       if (fabs(x_act) < dx / 100)
08465          x_act = 0;
08466 
08467    } while (1);
08468 }
08469 
08470 /*------------------------------------------------------------------*/
08471 
08472 void sec_to_label(char *result, int sec, int base, int force_date)
08473 {
08474    char mon[80];
08475    struct tm *tms;
08476    time_t t_sec;
08477 
08478    t_sec = (time_t) sec;
08479    tms = localtime(&t_sec);
08480    strcpy(mon, mname[tms->tm_mon]);
08481    mon[3] = 0;
08482 
08483    if (force_date) {
08484       if (base < 600)
08485          sprintf(result, "%02d %s %02d %02d:%02d:%02d",
08486                  tms->tm_mday, mon, tms->tm_year % 100, tms->tm_hour, tms->tm_min,
08487                  tms->tm_sec);
08488       else if (base < 3600 * 24)
08489          sprintf(result, "%02d %s %02d %02d:%02d",
08490                  tms->tm_mday, mon, tms->tm_year % 100, tms->tm_hour, tms->tm_min);
08491       else
08492          sprintf(result, "%02d %s %02d", tms->tm_mday, mon, tms->tm_year % 100);
08493    } else {
08494       if (base < 600)
08495          sprintf(result, "%02d:%02d:%02d", tms->tm_hour, tms->tm_min, tms->tm_sec);
08496       else if (base < 3600 * 3)
08497          sprintf(result, "%02d:%02d", tms->tm_hour, tms->tm_min);
08498       else if (base < 3600 * 24)
08499          sprintf(result, "%02d %s %02d %02d:%02d",
08500                  tms->tm_mday, mon, tms->tm_year % 100, tms->tm_hour, tms->tm_min);
08501       else
08502          sprintf(result, "%02d %s %02d", tms->tm_mday, mon, tms->tm_year % 100);
08503    }
08504 }
08505 
08506 void taxis(gdImagePtr im, gdFont * font, int col, int gcol,
08507            int x1, int y1, int width, int xr,
08508            int minor, int major, int text, int label, int grid, double xmin, double xmax)
08509 {
08510    int dx, x_act, label_dx, major_dx, x_screen, maxwidth;
08511    int tick_base, major_base, label_base, xs, xl;
08512    char str[80];
08513    int base[] = { 1, 5, 10, 60, 300, 600, 1800, 3600, 3600 * 6, 3600 * 12, 3600 * 24, 0 };
08514    time_t ltime;
08515    int force_date, d1, d2;
08516    struct tm *ptms;
08517 
08518    if (xmax <= xmin || width <= 0)
08519       return;
08520 
08521    /* force date display if xmax not today */
08522    ltime = ss_time();
08523    ptms = localtime(&ltime);
08524    d1 = ptms->tm_mday;
08525    ltime = (time_t) xmax;
08526    ptms = localtime(&ltime);
08527    d2 = ptms->tm_mday;
08528    force_date = (d1 != d2);
08529 
08530    /* use 5 pixel as min tick distance */
08531    dx = (int) ((xmax - xmin) / (double) (width / 5) + 0.5);
08532 
08533    for (tick_base = 0; base[tick_base]; tick_base++) {
08534       if (base[tick_base] > dx)
08535          break;
08536    }
08537    if (!base[tick_base])
08538       tick_base--;
08539    dx = base[tick_base];
08540 
08541    if (base[tick_base + 1])
08542       major_base = tick_base + 1;
08543    else
08544       major_base = tick_base;
08545    major_dx = base[major_base];
08546 
08547    if (base[major_base + 1])
08548       label_base = major_base + 1;
08549    else
08550       label_base = major_base;
08551    label_dx = base[label_base];
08552 
08553    do {
08554       sec_to_label(str, (int) (xmin + 0.5), label_dx, force_date);
08555       maxwidth = font->h / 2 * strlen(str);
08556 
08557       /* increasing label_dx, if labels would overlap */
08558       if (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
08559          if (base[label_base + 1])
08560             label_dx = base[++label_base];
08561          else
08562             label_dx += 3600 * 24;
08563       } else
08564          break;
08565    } while (1);
08566 
08567    x_act =
08568        (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
08569 
08570    gdImageLine(im, x1, y1, x1 + width, y1, col);
08571 
08572    do {
08573       x_screen = (int) ((x_act - xmin) / (xmax - xmin) * width + x1 + 0.5);
08574       xs = (int) (x_screen + 0.5);
08575 
08576       if (x_screen > x1 + width + 0.001)
08577          break;
08578 
08579       if (x_screen >= x1) {
08580          if ((x_act - ss_timezone()) % major_dx == 0) {
08581             if ((x_act - ss_timezone()) % label_dx == 0) {
08582                /* label tick mark */
08583                gdImageLine(im, xs, y1, xs, y1 + text, col);
08584 
08585                /* grid line */
08586                if (grid != 0 && xs > x1 && xs < x1 + width)
08587                   gdImageLine(im, xs, y1, xs, y1 + grid, col);
08588 
08589                /* label */
08590                if (label != 0) {
08591                   sec_to_label(str, x_act, label_dx, force_date);
08592 
08593                   /* if labels at edge, shift them in */
08594                   xl = (int) xs - font->w * strlen(str) / 2;
08595                   if (xl < 0)
08596                      xl = 0;
08597                   if (xl + font->w * (int) strlen(str) > xr)
08598                      xl = xr - font->w * strlen(str);
08599                   gdImageString(im, font, xl, y1 + label, str, col);
08600                }
08601             } else {
08602                /* major tick mark */
08603                gdImageLine(im, xs, y1, xs, y1 + major, col);
08604 
08605                /* grid line */
08606                if (grid != 0 && xs > x1 && xs < x1 + width)
08607                   gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
08608             }
08609 
08610          } else
08611             /* minor tick mark */
08612             gdImageLine(im, xs, y1, xs, y1 + minor, col);
08613 
08614       }
08615 
08616       x_act += dx;
08617 
08618       /* supress 1.23E-17 ... */
08619       if (fabs((double)x_act) < dx / 100)
08620          x_act = 0;
08621 
08622    } while (1);
08623 }
08624 
08625 /*------------------------------------------------------------------*/
08626 
08627 int vaxis(gdImagePtr im, gdFont * font, int col, int gcol,
08628           int x1, int y1, int width,
08629           int minor, int major, int text, int label, int grid, double ymin, double ymax,
08630           BOOL logaxis)
08631 {
08632    double dy, int_dy, frac_dy, y_act, label_dy, major_dy, y_screen, y_next;
08633    int tick_base, major_base, label_base, n_sig1, n_sig2, ys, max_width;
08634    int last_label_y;
08635    char str[80];
08636    double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
08637 
08638    if (ymax <= ymin || width <= 0)
08639       return 0;
08640 
08641    if (logaxis) {
08642       dy = pow(10, floor(log(ymin) / LN10));
08643       label_dy = dy;
08644       major_dy = dy * 10;
08645       n_sig1 = 4;
08646    } else {
08647       dy = (ymax - ymin) / (double) (width / 5);
08648 
08649       frac_dy = modf(log(dy) / LN10, &int_dy);
08650       if (frac_dy < 0) {
08651          frac_dy += 1;
08652          int_dy -= 1;
08653       }
08654 
08655       tick_base = frac_dy < LOG2 ? 1 : frac_dy < LOG5 ? 2 : 3;
08656       major_base = label_base = tick_base + 1;
08657 
08658       /* rounding up of dy, label_dy */
08659       dy = pow(10, int_dy) * base[tick_base];
08660       major_dy = pow(10, int_dy) * base[major_base];
08661       label_dy = major_dy;
08662 
08663       /* number of significant digits */
08664       if (ymin == 0)
08665          n_sig1 = 0;
08666       else
08667          n_sig1 =
08668              (int) floor(log(fabs(ymin)) / LN10) -
08669              (int) floor(log(fabs(label_dy)) / LN10) + 1;
08670 
08671       if (ymax == 0)
08672          n_sig2 = 0;
08673       else
08674          n_sig2 =
08675              (int) floor(log(fabs(ymax)) / LN10) -
08676              (int) floor(log(fabs(label_dy)) / LN10) + 1;
08677 
08678       n_sig1 = MAX(n_sig1, n_sig2);
08679       n_sig1 = MAX(n_sig1, 4);
08680 
08681       /* increasing label_dy, if labels would overlap */
08682       while (label_dy / (ymax - ymin) * width < 1.5 * font->h) {
08683          label_base++;
08684          label_dy = pow(10, int_dy) * base[label_base];
08685          if (label_base % 3 == 2 && major_base % 3 == 1) {
08686             major_base++;
08687             major_dy = pow(10, int_dy) * base[major_base];
08688          }
08689       }
08690    }
08691 
08692    max_width = 0;
08693    y_act = floor(ymin / dy) * dy;
08694 
08695    if (x1 != 0 || y1 != 0)
08696       gdImageLine(im, x1, y1, x1, y1 - width, col);
08697 
08698    last_label_y = y1 + 2 * font->h;
08699 
08700    do {
08701       if (logaxis)
08702          y_screen = y1 - (log(y_act) - log(ymin)) / (log(ymax) - log(ymin)) * width;
08703       else
08704          y_screen = y1 - (y_act - ymin) / (ymax - ymin) * width;
08705       ys = (int) (y_screen + 0.5);
08706 
08707       if (y_screen < y1 - width - 0.001)
08708          break;
08709 
08710       if (y_screen <= y1 + 0.001) {
08711          if (fabs(floor(y_act / major_dy + 0.5) - y_act / major_dy) <
08712              dy / major_dy / 10.0) {
08713             if (fabs(floor(y_act / label_dy + 0.5) - y_act / label_dy) <
08714                 dy / label_dy / 10.0) {
08715                if (x1 != 0 || y1 != 0) {
08716                   /* label tick mark */
08717                   gdImageLine(im, x1, ys, x1 + text, ys, col);
08718 
08719                   /* grid line */
08720                   if (grid != 0 && y_screen < y1 && y_screen > y1 - width) {
08721                      if (grid > 0)
08722                         gdImageLine(im, x1 + 1, ys, x1 + grid, ys, gcol);
08723                      else
08724                         gdImageLine(im, x1 - 1, ys, x1 + grid, ys, gcol);
08725                   }
08726 
08727                   /* label */
08728                   if (label != 0) {
08729                      sprintf(str, "%1.*lG", n_sig1, y_act);
08730                      if (label < 0)
08731                         gdImageString(im, font, x1 + label - font->w * strlen(str),
08732                                       ys - font->h / 2, str, col);
08733                      else
08734                         gdImageString(im, font, x1 + label, ys - font->h / 2, str, col);
08735 
08736                      last_label_y = ys - font->h / 2;
08737                   }
08738                } else {
08739                   sprintf(str, "%1.*lG", n_sig1, y_act);
08740                   max_width = MAX(max_width, (int) (font->w * strlen(str)));
08741                }
08742             } else {
08743                if (x1 != 0 || y1 != 0) {
08744                   /* major tick mark */
08745                   gdImageLine(im, x1, ys, x1 + major, ys, col);
08746 
08747                   /* grid line */
08748                   if (grid != 0 && y_screen < y1 && y_screen > y1 - width)
08749                      gdImageLine(im, x1, ys, x1 + grid, ys, col);
08750                }
08751             }
08752             if (logaxis) {
08753                dy *= 10;
08754                major_dy *= 10;
08755                label_dy *= 10;
08756             }
08757 
08758          } else {
08759             if (x1 != 0 || y1 != 0) {
08760                /* minor tick mark */
08761                gdImageLine(im, x1, ys, x1 + minor, ys, col);
08762             }
08763 
08764             /* for logaxis, also put labes on minor tick marks */
08765             if (logaxis) {
08766                if (label != 0) {
08767                   if (x1 != 0 || y1 != 0) {
08768                      /* calculate position of next major label */
08769                      y_next = pow(10, floor(log(y_act) / LN10) + 1);
08770                      y_screen =
08771                          (int) (y1 -
08772                                 (log(y_next) - log(ymin)) / (log(ymax) -
08773                                                              log(ymin)) * width + 0.5);
08774 
08775                      if (ys + font->h / 2 < last_label_y
08776                          && ys - font->h / 2 > y_screen + font->h / 2) {
08777                         sprintf(str, "%1.*lG", n_sig1, y_act);
08778                         if (label < 0)
08779                            gdImageString(im, font, x1 + label - font->w * strlen(str),
08780                                          ys - font->h / 2, str, col);
08781                         else
08782                            gdImageString(im, font, x1 + label, ys - font->h / 2, str,
08783                                          col);
08784                      }
08785 
08786                      last_label_y = ys - font->h / 2;
08787                   } else {
08788                      sprintf(str, "%1.*lG", n_sig1, y_act);
08789                      max_width = MAX(max_width, (int) (font->w * strlen(str)));
08790                   }
08791                }
08792             }
08793          }
08794       }
08795 
08796       y_act += dy;
08797 
08798       /* supress 1.23E-17 ... */
08799       if (fabs(y_act) < dy / 100)
08800          y_act = 0;
08801 
08802    } while (1);
08803 
08804    return max_width + abs(label);
08805 }
08806 
08807 /*------------------------------------------------------------------*/
08808 
08809 int time_to_sec(const char *str)
08810 {
08811    double s;
08812 
08813    s = atof(str);
08814    switch (str[strlen(str) - 1]) {
08815    case 'm':
08816    case 'M':
08817       s *= 60;
08818       break;
08819    case 'h':
08820    case 'H':
08821       s *= 3600;
08822       break;
08823    case 'd':
08824    case 'D':
08825       s *= 3600 * 24;
08826       break;
08827    }
08828 
08829    return (int) s;
08830 }
08831 
08832 /*------------------------------------------------------------------*/
08833 
08834 static MidasHistoryInterface* mh = NULL;
08835 static bool using_odbc = 0;
08836 
08837 static void set_history_path()
08838 {
08839    int status;
08840    HNDLE hDB;
08841 
08842    cm_get_experiment_database(&hDB, NULL);
08843 
08844 #ifdef HAVE_ODBC
08845    /* check ODBC connection */
08846    char str[256];
08847    int size = sizeof(str);
08848    str[0] = 0;
08849    status = db_get_value(hDB, 0, "/History/ODBC_DSN", str, &size, TID_STRING, TRUE);
08850    if ((status==DB_SUCCESS || status==DB_TRUNCATED) && str[0]!=0 && str[0]!='#') {
08851 
08852       if (!using_odbc)
08853          if (mh) {
08854             delete mh;
08855             mh = NULL;
08856          }
08857 
08858       if (!mh)
08859          mh = MakeMidasHistoryODBC();
08860 
08861       using_odbc = true;
08862 
08863       int debug = 0;
08864       size = sizeof(debug);
08865       status = db_get_value(hDB, 0, "/History/ODBC_Debug", &debug, &size, TID_INT, TRUE);
08866       assert(status==DB_SUCCESS);
08867 
08868       mh->hs_set_debug(debug);
08869 
08870       status = mh->hs_connect(str);
08871 
08872       if (status != HS_SUCCESS) {
08873          cm_msg(MERROR, "set_history_path", "Cannot connect to history database, hs_connect() status %d", status);
08874       }
08875 
08876    } else {
08877       if (using_odbc)
08878          if (mh) {
08879             delete mh;
08880             mh = NULL;
08881 
08882          }
08883       using_odbc = false;
08884    }
08885 #endif
08886 
08887    if (!using_odbc) {
08888       if (!mh)
08889          mh = MakeMidasHistory();
08890 
08891       status = mh->hs_connect(NULL);
08892 
08893       if (status != HS_SUCCESS) {
08894          cm_msg(MERROR, "set_history_path", "Cannot connect to midas history, hs_connect() status %d", status);
08895       }
08896    }
08897 }
08898 
08899 /*------------------------------------------------------------------*/
08900 
08901 void generate_hist_graph(const char *path, char *buffer, int *buffer_size,
08902                          int width, int height, int scale, int toffset, int index,
08903                          int labels, char *bgcolor, char *fgcolor, char *gridcolor)
08904 {
08905    HNDLE hDB, hkey, hkeypanel, hkeyeq, hkeydvar, hkeyvars, hkeyroot, hkeynames;
08906    KEY key;
08907    gdImagePtr im;
08908    gdGifBuffer gb;
08909    int i, j, k, l, n_vars, size, status, row, x_marker, n_vp, r, g, b;
08910    int length, aoffset;
08911    int flag, x1, y1, x2, y2, xs, xs_old, ys, xold, yold, xmaxm;
08912    int white, black, grey, ltgrey, red, green, blue, fgcol, bgcol, gridcol,
08913        curve_col[MAX_VARS], state_col[3];
08914    char str[256], panel[256], *p, odbpath[256];
08915    INT var_index[MAX_VARS];
08916    char event_name[MAX_VARS][NAME_LENGTH];
08917    char tag_name[MAX_VARS][64], var_name[MAX_VARS][NAME_LENGTH], varname[64],
08918        key_name[256];
08919 #define MAX_POINTS 1000
08920    DWORD n_point[MAX_VARS];
08921    int x[MAX_VARS][MAX_POINTS];
08922    double y[MAX_VARS][MAX_POINTS];
08923    float factor[MAX_VARS], offset[MAX_VARS];
08924    BOOL logaxis, runmarker;
08925    double xmin, xmax, ymin, ymax;
08926    gdPoint poly[3];
08927    double upper_limit[MAX_VARS], lower_limit[MAX_VARS];
08928    double yb1, yb2, yf1, yf2, ybase;
08929    float minvalue = (float) -HUGE_VAL;
08930    float maxvalue = (float) +HUGE_VAL;
08931    int show_values = 0;
08932    int sort_vars = 0;
08933    char var_status[MAX_VARS][256];
08934    double tstart, tend;
08935 
08936    static char *ybuffer;
08937    static DWORD *tbuffer;
08938    static int hbuffer_size = 0;
08939 
08940    if (hbuffer_size == 0) {
08941       hbuffer_size = 1000 * sizeof(DWORD);
08942       tbuffer = (DWORD*)malloc(hbuffer_size);
08943       ybuffer = (char*)malloc(hbuffer_size);
08944    }
08945 
08946    cm_get_experiment_database(&hDB, NULL);
08947 
08948    /* generate image */
08949    im = gdImageCreate(width, height);
08950 
08951    /* allocate standard colors */
08952    sscanf(bgcolor, "%02x%02x%02x", &r, &g, &b);
08953    bgcol = gdImageColorAllocate(im, r, g, b);
08954    sscanf(fgcolor, "%02x%02x%02x", &r, &g, &b);
08955    fgcol = gdImageColorAllocate(im, r, g, b);
08956    sscanf(gridcolor, "%02x%02x%02x", &r, &g, &b);
08957    gridcol = gdImageColorAllocate(im, r, g, b);
08958 
08959    grey = gdImageColorAllocate(im, 192, 192, 192);
08960    ltgrey = gdImageColorAllocate(im, 208, 208, 208);
08961    white = gdImageColorAllocate(im, 255, 255, 255);
08962    black = gdImageColorAllocate(im, 0, 0, 0);
08963    red = gdImageColorAllocate(im, 255, 0, 0);
08964    green = gdImageColorAllocate(im, 0, 255, 0);
08965    blue = gdImageColorAllocate(im, 0, 0, 255);
08966 
08967    curve_col[0] = gdImageColorAllocate(im, 0, 0, 255);
08968    curve_col[1] = gdImageColorAllocate(im, 0, 192, 0);
08969    curve_col[2] = gdImageColorAllocate(im, 255, 0, 0);
08970    curve_col[3] = gdImageColorAllocate(im, 0, 192, 192);
08971    curve_col[4] = gdImageColorAllocate(im, 255, 0, 255);
08972    curve_col[5] = gdImageColorAllocate(im, 192, 192, 0);
08973    curve_col[6] = gdImageColorAllocate(im, 128, 128, 128);
08974    curve_col[7] = gdImageColorAllocate(im, 128, 255, 128);
08975    curve_col[8] = gdImageColorAllocate(im, 255, 128, 128);
08976    curve_col[9] = gdImageColorAllocate(im, 128, 128, 255);
08977    for (i=10; i<MAX_VARS; i++)
08978       curve_col[i] = gdImageColorAllocate(im, 128, 128, 128);
08979 
08980    state_col[0] = gdImageColorAllocate(im, 255, 0, 0);
08981    state_col[1] = gdImageColorAllocate(im, 255, 255, 0);
08982    state_col[2] = gdImageColorAllocate(im, 0, 255, 0);
08983 
08984    /* Set transparent color. */
08985    gdImageColorTransparent(im, grey);
08986 
08987    /* Title */
08988    strlcpy(panel, path, sizeof(panel));
08989    if (strstr(panel, ".gif"))
08990       *strstr(panel, ".gif") = 0;
08991    gdImageString(im, gdFontGiant, width / 2 - (strlen(panel) * gdFontGiant->w) / 2, 2,
08992                  panel, fgcol);
08993 
08994    /* connect to history */
08995    set_history_path();
08996 
08997    /* check panel name in ODB */
08998    sprintf(str, "/History/Display/%s", panel);
08999    db_find_key(hDB, 0, str, &hkeypanel);
09000    if (!hkeypanel) {
09001       sprintf(str, "Cannot find /History/Display/%s in ODB", panel);
09002       gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09003                     height / 2, str, red);
09004       goto error;
09005    }
09006 
09007    db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
09008    if (!hkeydvar) {
09009       sprintf(str, "Cannot find /History/Display/%s/Variables in ODB", panel);
09010       gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09011                     height / 2, str, red);
09012       goto error;
09013    }
09014 
09015    db_get_key(hDB, hkeydvar, &key);
09016    n_vars = key.num_values;
09017 
09018    if (n_vars > MAX_VARS) {
09019       sprintf(str, "Too many variables in panel %s", panel);
09020       gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09021                     height / 2, str, red);
09022       goto error;
09023    }
09024 
09025    ymin = ymax = 0;
09026    logaxis = runmarker = 0;
09027 
09028    tstart = ss_millitime();
09029 
09030    for (i = 0; i < n_vars; i++) {
09031       if (index != -1 && index != i)
09032          continue;
09033 
09034       size = sizeof(str);
09035       status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
09036       if (status != DB_SUCCESS) {
09037          sprintf(str, "Cannot read tag %d in panel %s, status %d", i, panel, status);
09038          gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09039                        height / 2, str, red);
09040          goto error;
09041       }
09042 
09043       strlcpy(tag_name[i], str, sizeof(tag_name[0]));
09044 
09045       /* split varname in event, variable and index */
09046       if (strchr(tag_name[i], ':')) {
09047          strlcpy(event_name[i], tag_name[i], sizeof(event_name[0]));
09048          *strchr(event_name[i], ':') = 0;
09049          strlcpy(var_name[i], strchr(tag_name[i], ':') + 1, sizeof(var_name[0]));
09050          var_index[i] = 0;
09051          if (strchr(var_name[i], '[')) {
09052             var_index[i] = atoi(strchr(var_name[i], '[') + 1);
09053             *strchr(var_name[i], '[') = 0;
09054          }
09055       } else {
09056          sprintf(str, "Tag \"%s\" has wrong format in panel \"%s\"", tag_name[i], panel);
09057          gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09058                        height / 2, str, red);
09059          goto error;
09060       }
09061 
09062       db_find_key(hDB, hkeypanel, "Colour", &hkey);
09063       if (hkey) {
09064          size = sizeof(str);
09065          status = db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
09066          if (status == DB_SUCCESS) {
09067             if (str[0] == '#') {
09068                char sss[3];
09069                int r, g, b;
09070 
09071                sss[0] = str[1];
09072                sss[1] = str[2];
09073                sss[2] = 0;
09074                r = strtoul(sss, NULL, 16);
09075                sss[0] = str[3];
09076                sss[1] = str[4];
09077                sss[2] = 0;
09078                g = strtoul(sss, NULL, 16);
09079                sss[0] = str[5];
09080                sss[1] = str[6];
09081                sss[2] = 0;
09082                b = strtoul(sss, NULL, 16);
09083 
09084                curve_col[i] = gdImageColorAllocate(im, r, g, b);
09085             }
09086          }
09087       }
09088 
09089       /* get timescale */
09090       if (scale == 0) {
09091          strlcpy(str, "1h", sizeof(str));
09092          size = NAME_LENGTH;
09093          status = db_get_value(hDB, hkeypanel, "Timescale", str, &size, TID_STRING, TRUE);
09094          if (status != DB_SUCCESS) {
09095             /* delete old integer key */
09096             db_find_key(hDB, hkeypanel, "Timescale", &hkey);
09097             if (hkey)
09098                db_delete_key(hDB, hkey, FALSE);
09099 
09100             strcpy(str, "1h");
09101             size = NAME_LENGTH;
09102             status =
09103                 db_get_value(hDB, hkeypanel, "Timescale", str, &size, TID_STRING, TRUE);
09104          }
09105 
09106          scale = time_to_sec(str);
09107       }
09108 
09109       for (j = 0; j < MAX_VARS; j++) {
09110          factor[j] = 1;
09111          offset[j] = 0;
09112       }
09113 
09114       /* get factors */
09115       size = sizeof(float) * n_vars;
09116       db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
09117 
09118       /* get offsets */
09119       size = sizeof(float) * n_vars;
09120       db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
09121 
09122       /* get axis type */
09123       size = sizeof(logaxis);
09124       logaxis = 0;
09125       db_get_value(hDB, hkeypanel, "Log axis", &logaxis, &size, TID_BOOL, TRUE);
09126 
09127       /* get show_values type */
09128       size = sizeof(show_values);
09129       show_values = 0;
09130       db_get_value(hDB, hkeypanel, "Show values", &show_values, &size, TID_BOOL, TRUE);
09131 
09132       /* get sort_vars type */
09133       size = sizeof(sort_vars);
09134       sort_vars = 0;
09135       db_get_value(hDB, hkeypanel, "Show values", &sort_vars, &size, TID_BOOL, TRUE);
09136 
09137       /* get min value */
09138       size = sizeof(minvalue);
09139       minvalue = (float) -HUGE_VAL;
09140       db_get_value(hDB, hkeypanel, "Minimum", &minvalue, &size, TID_FLOAT, TRUE);
09141 
09142       /* get max value */
09143       size = sizeof(maxvalue);
09144       maxvalue = (float) +HUGE_VAL;
09145       db_get_value(hDB, hkeypanel, "Maximum", &maxvalue, &size, TID_FLOAT, TRUE);
09146 
09147       if ((minvalue == 0) && (maxvalue == 0)) {
09148          minvalue = (float) -HUGE_VAL;
09149          maxvalue = (float) +HUGE_VAL;
09150       }
09151 
09152       /* get runmarker flag */
09153       size = sizeof(runmarker);
09154       runmarker = 1;
09155       db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
09156 
09157       /* make ODB path from tag name */
09158       odbpath[0] = 0;
09159       db_find_key(hDB, 0, "/Equipment", &hkeyroot);
09160       if (hkeyroot) {
09161          for (j = 0;; j++) {
09162             db_enum_key(hDB, hkeyroot, j, &hkeyeq);
09163 
09164             if (!hkeyeq)
09165                break;
09166 
09167             db_get_key(hDB, hkeyeq, &key);
09168             if (equal_ustring(key.name, event_name[i])) {
09169                /* check if variable is individual key under variables/ */
09170                sprintf(str, "Variables/%s", var_name[i]);
09171                db_find_key(hDB, hkeyeq, str, &hkey);
09172                if (hkey) {
09173                   sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[i],
09174                           var_name[i]);
09175                   break;
09176                }
09177 
09178                /* check if variable is in setttins/names array */
09179                db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
09180                if (hkeynames) {
09181                   /* extract variable name and Variables/<key> */
09182                   strlcpy(str, var_name[i], sizeof(str));
09183                   p = str + strlen(str) - 1;
09184                   while (p > str && *p != ' ')
09185                      p--;
09186                   strlcpy(key_name, p + 1, sizeof(key_name));
09187                   *p = 0;
09188                   strlcpy(varname, str, sizeof(varname));
09189 
09190                   /* find key in single name array */
09191                   db_get_key(hDB, hkeynames, &key);
09192                   for (k = 0; k < key.num_values; k++) {
09193                      size = sizeof(str);
09194                      db_get_data_index(hDB, hkeynames, str, &size, k, TID_STRING);
09195                      if (equal_ustring(str, varname)) {
09196                         sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i],
09197                                 key_name, k);
09198                         break;
09199                      }
09200                   }
09201                } else {
09202                   /* go through /variables/<name> entries */
09203                   db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
09204                   if (hkeyvars) {
09205                      for (k = 0;; k++) {
09206                         db_enum_key(hDB, hkeyvars, k, &hkey);
09207 
09208                         if (!hkey)
09209                            break;
09210 
09211                         /* find "settins/names <key>" for this key */
09212                         db_get_key(hDB, hkey, &key);
09213 
09214                         /* find key in key_name array */
09215                         strlcpy(key_name, key.name, sizeof(key_name));
09216                         sprintf(str, "Settings/Names %s", key_name);
09217 
09218                         db_find_key(hDB, hkeyeq, str, &hkeynames);
09219                         if (hkeynames) {
09220                            db_get_key(hDB, hkeynames, &key);
09221                            for (l = 0; l < key.num_values; l++) {
09222                               size = sizeof(str);
09223                               db_get_data_index(hDB, hkeynames, str, &size, l,
09224                                                 TID_STRING);
09225                               if (equal_ustring(str, var_name[i])) {
09226                                  sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]",
09227                                          event_name[i], key_name, l);
09228                                  break;
09229                               }
09230                            }
09231                         }
09232                      }
09233                   }
09234                }
09235 
09236                break;
09237             }
09238          }
09239 
09240          if (!hkeyeq) {
09241             db_find_key(hDB, 0, "/History/Links", &hkeyroot);
09242             if (hkeyroot) {
09243                for (j = 0;; j++) {
09244                   db_enum_link(hDB, hkeyroot, j, &hkey);
09245 
09246                   if (!hkey)
09247                      break;
09248 
09249                   db_get_key(hDB, hkey, &key);
09250                   if (equal_ustring(key.name, event_name[i])) {
09251                      db_enum_key(hDB, hkeyroot, j, &hkey);
09252                      db_find_key(hDB, hkey, var_name[i], &hkey);
09253                      if (hkey) {
09254                         db_get_key(hDB, hkey, &key);
09255                         db_get_path(hDB, hkey, odbpath, sizeof(odbpath));
09256                         if (key.num_values > 1)
09257                            sprintf(odbpath + strlen(odbpath), "[%d]", var_index[i]);
09258                         break;
09259                      }
09260                   }
09261                }
09262             }
09263          }
09264       }
09265 
09266       /* search alarm limits */
09267       upper_limit[i] = lower_limit[i] = -12345;
09268       db_find_key(hDB, 0, "Alarms/Alarms", &hkeyroot);
09269       if (odbpath[0] && hkeyroot) {
09270          for (j = 0;; j++) {
09271             db_enum_key(hDB, hkeyroot, j, &hkey);
09272 
09273             if (!hkey)
09274                break;
09275 
09276             size = sizeof(str);
09277             db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
09278 
09279             if (strstr(str, odbpath)) {
09280                if (strchr(str, '<')) {
09281                   p = strchr(str, '<') + 1;
09282                   if (*p == '=')
09283                      p++;
09284                   lower_limit[i] = (factor[i] * atof(p) + offset[i]);
09285                }
09286                if (strchr(str, '>')) {
09287                   p = strchr(str, '>') + 1;
09288                   if (*p == '=')
09289                      p++;
09290                   upper_limit[i] = (factor[i] * atof(p) + offset[i]);
09291                }
09292             }
09293          }
09294       }
09295    } // loop over variables
09296 
09297    if (1) {
09298       time_t now = ss_time();
09299 
09300       int num_entries[MAX_VARS];
09301       time_t *times[MAX_VARS];
09302       double *datas[MAX_VARS];
09303       int st[MAX_VARS];
09304 
09305       const char* xevent_name[MAX_VARS];
09306       const char* xvar_name[MAX_VARS];
09307 
09308       for (i = 0; i < n_vars; i++) {
09309          if (index != -1 && index != i) {
09310             var_status[i][0] = 0;
09311             xevent_name[i] = NULL;
09312             xvar_name[i] = NULL;
09313             continue;
09314          }
09315 
09316          var_status[i][0] = 0;
09317          xevent_name[i] = event_name[i];
09318          xvar_name[i] = var_name[i];
09319          
09320          //printf("event [%s][%s] tag [%s][%s] index [%d]\n", event_name[i], xevent_name[i], var_name[i], xvar_name[i], var_index[i]);
09321       }
09322 
09323       for (i=0 ; i<MAX_VARS ; i++) {
09324          times[i] = NULL;
09325          datas[i] = NULL;
09326       }
09327 
09328       status = mh->hs_read(now - scale + toffset, now + toffset, scale / 1000 + 1,
09329                            n_vars,
09330                            xevent_name, xvar_name, var_index,
09331                            num_entries,
09332                            times, datas,
09333                            st);
09334      
09335       if (status != HS_SUCCESS) {
09336          sprintf(str, "Complete history failure, hs_read() status %d, see messages", status);
09337          gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2,
09338                        height / 2, str, red);
09339          goto error;
09340       }
09341 
09342       for (i = 0; i < n_vars; i++) {
09343          var_status[i][0] = 0;
09344 
09345          if (st[i] == HS_UNDEFINED_VAR) {
09346             sprintf(var_status[i], "not found in history");
09347             num_entries[i] = 0;
09348          } else if (st[i] != HS_SUCCESS) {
09349             sprintf(var_status[i], "hs_read() error %d, see messages", st[i]);
09350             num_entries[i] = 0;
09351          }
09352       }
09353      
09354       for (i = 0; i < n_vars; i++) {
09355          if (index != -1 && index != i)
09356             continue;
09357        
09358          for (j = n_vp = 0; j < num_entries[i]; j++) {
09359             x[i][n_vp] = (int)(times[i][j] - now);
09360             y[i][n_vp] = datas[i][j];
09361          
09362             /* skip NaNs */
09363             if (ss_isnan(y[i][n_vp]))
09364                continue;
09365          
09366             /* skip INFs */
09367             if (!ss_isfin(y[i][n_vp]))
09368                continue;
09369          
09370             /* avoid overflow */
09371             if (y[i][n_vp] > 1E30)
09372                y[i][n_vp] = 1E30f;
09373          
09374             /* apply factor and offset */
09375             y[i][n_vp] = y[i][n_vp] * factor[i] + offset[i];
09376          
09377             /* calculate ymin and ymax */
09378             if ((i == 0 || index != -1) && n_vp == 0)
09379                ymin = ymax = y[i][0];
09380             else {
09381                if (y[i][n_vp] > ymax)
09382                   ymax = y[i][n_vp];
09383                if (y[i][n_vp] < ymin)
09384                   ymin = y[i][n_vp];
09385             }
09386          
09387             /* increment number of valid points */
09388             n_vp++;
09389 
09390          } // loop over data
09391 
09392          n_point[i] = n_vp;
09393 
09394          assert(n_point[i]<=MAX_POINTS);
09395 
09396          if (times[i])
09397             free(times[i]);
09398          if (datas[i])
09399             free(datas[i]);
09400       } // loop over variables
09401    }
09402 
09403    tend = ss_millitime();
09404 
09405    if (ymin < minvalue)
09406       ymin = minvalue;
09407 
09408    if (ymax > maxvalue)
09409       ymax = maxvalue;
09410 
09411    /* check if ylow = 0 */
09412    if (index == -1) {
09413       flag = 0;
09414       size = sizeof(flag);
09415       db_get_value(hDB, hkeypanel, "Zero ylow", &flag, &size, TID_BOOL, TRUE);
09416       if (flag && ymin > 0)
09417          ymin = 0;
09418    }
09419 
09420    /* if min and max too close together, switch to linear axis */
09421    if (logaxis && ymin > 0 && ymax > 0) {
09422       yb1 = pow(10, floor(log(ymin) / LN10));
09423       yf1 = floor(ymin / yb1);
09424       yb2 = pow(10, floor(log(ymax) / LN10));
09425       yf2 = floor(ymax / yb2);
09426 
09427       if (yb1 == yb2 && yf1 == yf2)
09428          logaxis = 0;
09429       else {
09430          /* round down and up ymin and ymax */
09431          ybase = pow(10, floor(log(ymin) / LN10));
09432          ymin = (float) (floor(ymin / ybase) * ybase);
09433          ybase = pow(10, floor(log(ymax) / LN10));
09434          ymax = (float) ((floor(ymax / ybase) + 1) * ybase);
09435       }
09436    }
09437 
09438    /* avoid negative limits for log axis */
09439    if (logaxis) {
09440       if (ymax <= 0)
09441          ymax = 1;
09442       if (ymin <= 0)
09443          ymin = 1E-12f;
09444    }
09445 
09446    /* increase limits by 5% */
09447    if (ymin == 0 && ymax == 0) {
09448       ymin = -1;
09449       ymax = 1;
09450    } else {
09451       if (!logaxis) {
09452          ymax += (ymax - ymin) / 20.f;
09453 
09454          if (ymin != 0)
09455             ymin -= (ymax - ymin) / 20.f;
09456       }
09457    }
09458 
09459    /* avoid ymin == ymax */
09460    if (ymax == ymin) {
09461       if (logaxis) {
09462          ymax *= 2;
09463          ymin /= 2;
09464       } else {
09465          ymax += 10;
09466          ymin -= 10;
09467       }
09468    }
09469 
09470    /* calculate X limits */
09471    xmin = (float) (-scale / 3600.0 + toffset / 3600.0);
09472    xmax = (float) (toffset / 3600.0);
09473 
09474    /* caluclate required space for Y-axis */
09475    aoffset =
09476        vaxis(im, gdFontSmall, fgcol, gridcol, 0, 0, height, -3, -5, -7, -8, 0, ymin, ymax,
09477              logaxis);
09478    aoffset += 2;
09479 
09480    x1 = aoffset;
09481    y1 = height - 20;
09482    x2 = width - 20;
09483    y2 = 20;
09484 
09485    gdImageFilledRectangle(im, x1, y2, x2, y1, bgcol);
09486 
09487    /* draw axis frame */
09488    taxis(im, gdFontSmall, fgcol, gridcol, x1, y1, x2 - x1, width, 3, 5, 9, 10, 0,
09489          ss_time() - scale + toffset, ss_time() + toffset);
09490 
09491    vaxis(im, gdFontSmall, fgcol, gridcol, x1, y1, y1 - y2, -3, -5, -7, -8, x2 - x1, ymin,
09492          ymax, logaxis);
09493    gdImageLine(im, x1, y2, x2, y2, fgcol);
09494    gdImageLine(im, x2, y2, x2, y1, fgcol);
09495 
09496    xs = ys = xold = yold = 0;
09497 
09498    /* write run markes if selected */
09499    if (runmarker) {
09500 
09501       const char* event_names[] = {
09502          "Run transitions", 
09503          "Run transitions", 
09504          0 };
09505 
09506       const char* tag_names[] = {
09507          "State", 
09508          "Run number", 
09509          0 };
09510 
09511       const int tag_indexes[] = {
09512          0,
09513          0,
09514          0 };
09515 
09516       int num_entries[3];
09517       time_t *tbuf[3];
09518       double *dbuf[3];
09519       int     st[3];
09520 
09521       status = mh->hs_read(ss_time() - scale + toffset - scale, ss_time() + toffset, 0,
09522                            2, event_names, tag_names, tag_indexes,
09523                            num_entries, tbuf, dbuf, st);
09524 
09525       //printf("read run info: status %d, entries %d %d\n", status, num_entries[0], num_entries[1]);
09526 
09527       int n_marker = num_entries[0];
09528 
09529       if (status == HS_SUCCESS && n_marker > 0 && n_marker < 100) {
09530          xs_old = -1;
09531          xmaxm = x1;
09532          for (j = 0; j < (int) n_marker; j++) {
09533             int col;
09534 
09535             x_marker = (int)(tbuf[1][j] - ss_time());
09536             xs = (int) ((x_marker / 3600.0 - xmin) / (xmax - xmin) * (x2 - x1) + x1 +
09537                         0.5);
09538 
09539             if (xs < x1)
09540                continue;
09541             if (xs >= x2)
09542                continue;
09543 
09544             double run_number = dbuf[1][j];
09545 
09546             if (xs <= xs_old)
09547                xs = xs_old + 1;
09548             xs_old = xs;
09549 
09550             if (dbuf[0][j] == 1)
09551                col = state_col[0];
09552             else if (dbuf[0][j] == 2)
09553                col = state_col[1];
09554             else if (dbuf[0][j] == 3)
09555                col = state_col[2];
09556             else
09557                col = state_col[0];
09558 
09559             gdImageDashedLine(im, xs, y1, xs, y2, col);
09560 
09561             sprintf(str, "%.0f", run_number);
09562 
09563             if (dbuf[0][j] == STATE_RUNNING) {
09564                if (xs > xmaxm) {
09565                   gdImageStringUp(im, gdFontSmall, xs + 0,
09566                                   y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
09567                   xmaxm = xs - 2 + gdFontSmall->h;
09568                }
09569             } else if (dbuf[0][j] == STATE_STOPPED) {
09570                if (xs + 2 - gdFontSmall->h > xmaxm) {
09571                   gdImageStringUp(im, gdFontSmall, xs + 2 - gdFontSmall->h,
09572                                   y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
09573                   xmaxm = xs - 1;
09574                }
09575             }
09576          }
09577       }
09578 
09579       if (num_entries[0]) {
09580          free(tbuf[0]);
09581          free(dbuf[0]);
09582       }
09583 
09584       if (num_entries[1]) {
09585          free(tbuf[1]);
09586          free(dbuf[1]);
09587       }
09588    }
09589 
09590    for (i = 0; i < n_vars; i++) {
09591       if (index != -1 && index != i)
09592          continue;
09593 
09594       /* draw alarm limits */
09595       if (lower_limit[i] != -12345) {
09596          if (logaxis) {
09597             if (lower_limit[i] <= 0)
09598                ys = y1;
09599             else
09600                ys = (int) (y1 -
09601                            (log(lower_limit[i]) - log(ymin)) / (log(ymax) -
09602                                                                 log(ymin)) * (y1 - y2) +
09603                            0.5);
09604          } else
09605             ys = (int) (y1 - (lower_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
09606 
09607          if (xs < 0)
09608             xs = 0;
09609          if (xs >= width)
09610             xs = width-1;
09611          if (ys < 0)
09612             ys = 0;
09613          if (ys >= height)
09614             ys = height-1;
09615 
09616          if (ys > y2 && ys < y1) {
09617             gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
09618 
09619             poly[0].x = x1;
09620             poly[0].y = ys;
09621             poly[1].x = x1 + 5;
09622             poly[1].y = ys;
09623             poly[2].x = x1;
09624             poly[2].y = ys - 5;
09625 
09626             gdImageFilledPolygon(im, poly, 3, curve_col[i]);
09627          }
09628       }
09629       if (upper_limit[i] != -12345) {
09630          if (logaxis) {
09631             if (upper_limit[i] <= 0)
09632                ys = y1;
09633             else
09634                ys = (int) (y1 -
09635                            (log(upper_limit[i]) - log(ymin)) / (log(ymax) -
09636                                                                 log(ymin)) * (y1 - y2) +
09637                            0.5);
09638          } else
09639             ys = (int) (y1 - (upper_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
09640 
09641          if (xs < 0)
09642             xs = 0;
09643          if (xs >= width)
09644             xs = width-1;
09645          if (ys < 0)
09646             ys = 0;
09647          if (ys >= height)
09648             ys = height-1;
09649 
09650          if (ys > y2 && ys < y1) {
09651             gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
09652 
09653             poly[0].x = x1;
09654             poly[0].y = ys;
09655             poly[1].x = x1 + 5;
09656             poly[1].y = ys;
09657             poly[2].x = x1;
09658             poly[2].y = ys + 5;
09659 
09660             gdImageFilledPolygon(im, poly, 3, curve_col[i]);
09661          }
09662       }
09663 
09664       for (j = 0; j < (int) n_point[i]; j++) {
09665          xs = (int) ((x[i][j] / 3600.0 - xmin) / (xmax - xmin) * (x2 - x1) + x1 + 0.5);
09666 
09667          if (logaxis) {
09668             if (y[i][j] <= 0)
09669                ys = y1;
09670             else
09671                ys = (int) (y1 -
09672                            (log(y[i][j]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 -
09673                                                                                    y2) +
09674                            0.5);
09675          } else
09676             ys = (int) (y1 - (y[i][j] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
09677 
09678          if (xs < 0)
09679             xs = 0;
09680          if (xs >= width)
09681             xs = width-1;
09682          if (ys < 0)
09683             ys = 0;
09684          if (ys >= height)
09685             ys = height-1;
09686 
09687          if (j > 0)
09688             gdImageLine(im, xold, yold, xs, ys, curve_col[i]);
09689          xold = xs;
09690          yold = ys;
09691       }
09692 
09693       if (n_point[i] > 0) {
09694          poly[0].x = xs;
09695          poly[0].y = ys;
09696          poly[1].x = xs + 12;
09697          poly[1].y = ys - 6;
09698          poly[2].x = xs + 12;
09699          poly[2].y = ys + 6;
09700 
09701          gdImageFilledPolygon(im, poly, 3, curve_col[i]);
09702       }
09703    }
09704 
09705    if (labels) {
09706       for (i = 0; i < n_vars; i++) {
09707          if (index != -1 && index != i)
09708             continue;
09709 
09710          str[0] = 0;
09711          status = db_find_key(hDB, hkeypanel, "Label", &hkeydvar);
09712          if (status == DB_SUCCESS) {
09713             size = sizeof(str);
09714             status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
09715          }
09716 
09717          if (status != DB_SUCCESS || strlen(str) < 1) {
09718             if (factor[i] != 1) {
09719                if (offset[i] == 0)
09720                   sprintf(str, "%s * %1.2lG", strchr(tag_name[i], ':') + 1, factor[i]);
09721                else
09722                   sprintf(str, "%s * %1.2lG %c %1.5lG", strchr(tag_name[i], ':') + 1,
09723                           factor[i], offset[i] < 0 ? '-' : '+', fabs(offset[i]));
09724             } else {
09725                if (offset[i] == 0)
09726                   sprintf(str, "%s", strchr(tag_name[i], ':') + 1);
09727                else
09728                   sprintf(str, "%s %c %1.5lG", strchr(tag_name[i], ':') + 1,
09729                           offset[i] < 0 ? '-' : '+', fabs(offset[i]));
09730             }
09731          }
09732 
09733          if (show_values) {
09734             char xstr[256];
09735             if (n_point[i] > 0)
09736                sprintf(xstr," = %g", y[i][n_point[i]-1]);
09737             else
09738                sprintf(xstr," = no data");
09739             strlcat(str, xstr, sizeof(str));
09740          }
09741 
09742          if (strlen(var_status[i]) > 1) {
09743             char xstr[256];
09744             sprintf(xstr," (%s)", var_status[i]);
09745             strlcat(str, xstr, sizeof(str));
09746          }
09747 
09748          row = index == -1 ? i : 0;
09749 
09750          gdImageFilledRectangle(im,
09751                                 x1 + 10,
09752                                 y2 + 10 + row * (gdFontMediumBold->h + 10),
09753                                 x1 + 10 + strlen(str) * gdFontMediumBold->w + 10,
09754                                 y2 + 10 + row * (gdFontMediumBold->h + 10) +
09755                                 gdFontMediumBold->h + 2 + 2, white);
09756          gdImageRectangle(im, x1 + 10, y2 + 10 + row * (gdFontMediumBold->h + 10),
09757                           x1 + 10 + strlen(str) * gdFontMediumBold->w + 10,
09758                           y2 + 10 + row * (gdFontMediumBold->h + 10) +
09759                           gdFontMediumBold->h + 2 + 2, curve_col[i]);
09760 
09761          gdImageString(im, gdFontMediumBold,
09762                        x1 + 10 + 5, y2 + 10 + 2 + row * (gdFontMediumBold->h + 10), str,
09763                        curve_col[i]);
09764       }
09765    }
09766 
09767    gdImageRectangle(im, x1, y2, x2, y1, fgcol);
09768 
09769  error:
09770 
09771    /* generate GIF */
09772    gdImageInterlace(im, 1);
09773    gdImageGif(im, &gb);
09774    gdImageDestroy(im);
09775    length = gb.size;
09776 
09777    if (buffer == NULL) {
09778       rsprintf("HTTP/1.0 200 Document follows\r\n");
09779       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
09780 
09781       rsprintf("Content-Type: image/gif\r\n");
09782       rsprintf("Content-Length: %d\r\n", length);
09783       rsprintf("Pragma: no-cache\r\n");
09784       rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
09785 
09786       if (length > (int) (sizeof(return_buffer) - strlen(return_buffer))) {
09787          printf("return buffer too small\n");
09788          return;
09789       }
09790 
09791       return_length = strlen(return_buffer) + length;
09792       memcpy(return_buffer + strlen(return_buffer), gb.data, length);
09793    } else {
09794       if (length > *buffer_size) {
09795          printf("return buffer too small\n");
09796          return;
09797       }
09798 
09799       memcpy(buffer, gb.data, length);
09800       *buffer_size = length;
09801    }
09802 }
09803 
09804 /*------------------------------------------------------------------*/
09805 
09806 void show_query_page(const char *path)
09807 {
09808    int i;
09809    time_t ltime_start, ltime_end;
09810    HNDLE hDB;
09811    char str[256], redir[256];
09812    time_t now;
09813    struct tm *ptms, tms;
09814 
09815    if (*getparam("m1")) {
09816       memset(&tms, 0, sizeof(struct tm));
09817       tms.tm_year = atoi(getparam("y1")) % 100;
09818 
09819       strlcpy(str, getparam("m1"), sizeof(str));
09820       for (i = 0; i < 12; i++)
09821          if (equal_ustring(str, mname[i]))
09822             break;
09823       if (i == 12)
09824          i = 0;
09825 
09826       tms.tm_mon = i;
09827       tms.tm_mday = atoi(getparam("d1"));
09828       tms.tm_hour = 0;
09829 
09830       if (tms.tm_year < 90)
09831          tms.tm_year += 100;
09832 
09833       ltime_start = mktime(&tms);
09834       memset(&tms, 0, sizeof(struct tm));
09835       tms.tm_year = atoi(getparam("y2")) % 100;
09836 
09837       strlcpy(str, getparam("m2"), sizeof(str));
09838       for (i = 0; i < 12; i++)
09839          if (equal_ustring(str, mname[i]))
09840             break;
09841       if (i == 12)
09842          i = 0;
09843 
09844       tms.tm_mon = i;
09845       tms.tm_mday = atoi(getparam("d2"));
09846       tms.tm_hour = 0;
09847 
09848       if (tms.tm_year < 90)
09849          tms.tm_year += 100;
09850       ltime_end = mktime(&tms);
09851       ltime_end += 3600 * 24;
09852 
09853       strcpy(str, path);
09854       if (strrchr(str, '/'))
09855          strcpy(str, strrchr(str, '/')+1);
09856       sprintf(redir, "%s?scale=%d&offset=%d", str, (int) (ltime_end - ltime_start),
09857               MIN((int) (ltime_end - ss_time()), 0));
09858       redirect(redir);
09859       return;
09860    }
09861 
09862    cm_get_experiment_database(&hDB, NULL);
09863 
09864    strcpy(str, path);
09865    if (strrchr(str, '/'))
09866       strcpy(str, strrchr(str, '/')+1);
09867    show_header(hDB, "History", "GET", str, 1, 0);
09868 
09869    /* menu buttons */
09870    rsprintf("<tr><td colspan=2 bgcolor=#C0C0C0>\n");
09871    rsprintf("<input type=submit name=cmd value=Query>\n");
09872    rsprintf("<input type=submit name=cmd value=History>\n");
09873    rsprintf("<input type=submit name=cmd value=Status></tr>\n");
09874    rsprintf("</tr>\n\n");
09875 
09876    time(&now);
09877    now -= 3600 * 24;
09878    ptms = localtime(&now);
09879    ptms->tm_year += 1900;
09880 
09881    rsprintf("<tr><td nowrap bgcolor=#CCCCFF>Start date:</td>", "Start date");
09882 
09883    rsprintf("<td bgcolor=#DDEEBB>Month: <select name=\"m1\">\n");
09884    rsprintf("<option value=\"\">\n");
09885    for (i = 0; i < 12; i++)
09886       if (i == ptms->tm_mon)
09887          rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
09888       else
09889          rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
09890    rsprintf("</select>\n");
09891 
09892    rsprintf("&nbsp;Day: <select name=\"d1\">");
09893    rsprintf("<option selected value=\"\">\n");
09894    for (i = 0; i < 31; i++)
09895       if (i + 1 == ptms->tm_mday)
09896          rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
09897       else
09898          rsprintf("<option value=%d>%d\n", i + 1, i + 1);
09899    rsprintf("</select>\n");
09900 
09901    rsprintf
09902        ("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">",
09903         ptms->tm_year);
09904    rsprintf("</td></tr>\n");
09905 
09906    rsprintf("<tr><td nowrap bgcolor=#CCCCFF>End date:</td>");
09907    time(&now);
09908    ptms = localtime(&now);
09909    ptms->tm_year += 1900;
09910 
09911    rsprintf("<td bgcolor=#DDEEBB>Month: <select name=\"m2\">\n");
09912    rsprintf("<option value=\"\">\n");
09913    for (i = 0; i < 12; i++)
09914       if (i == ptms->tm_mon)
09915          rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
09916       else
09917          rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
09918    rsprintf("</select>\n");
09919 
09920    rsprintf("&nbsp;Day: <select name=\"d2\">");
09921    rsprintf("<option selected value=\"\">\n");
09922    for (i = 0; i < 31; i++)
09923       if (i + 1 == ptms->tm_mday)
09924          rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
09925       else
09926          rsprintf("<option value=%d>%d\n", i + 1, i + 1);
09927    rsprintf("</select>\n");
09928 
09929    rsprintf
09930        ("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y2\" value=\"%d\">",
09931         ptms->tm_year);
09932    rsprintf("</td></tr>\n");
09933 
09934    rsprintf("</table>\n");
09935    rsprintf("</body></html>\r\n");
09936 }
09937 
09938 /*------------------------------------------------------------------*/
09939 
09940 static int cmp_names(const void *a, const void *b)
09941 {
09942   int i;
09943   const char*sa = (const char*)a;
09944   const char*sb = (const char*)b;
09945 
09946   int debug = 0;
09947 
09948   // Cannot use strcmp() because it does not know how to compare numerical values, e.g.
09949   // it thinks "111" is smaller than "9"
09950   //return strcmp(sa, sb);
09951 
09952   if (debug)
09953     printf("compare [%s] and [%s]\n", sa, sb);
09954 
09955   for (i=0; ; i++) {
09956     if (sa[i]==0 && sb[i]==0)
09957       return 0; // both strings have the same length and the same characters
09958 
09959     //printf("index %d, char [%c] [%c], isdigit %d %d\n", i, sa[i], sb[i], isdigit(sa[i]), isdigit(sb[i]));
09960 
09961     if (isdigit(sa[i]) && isdigit(sb[i])) {
09962       int va = atoi(sa+i);
09963       int vb = atoi(sb+i);
09964 
09965       if (debug)
09966         printf("index %d, values %d %d\n", i, va, vb);
09967 
09968       if (va < vb)
09969         return -1;
09970       else if (va > vb)
09971         return 1;
09972 
09973       // values are equal, skip the the end of the digits, compare any trailing text
09974       continue;
09975     }
09976 
09977     if (sa[i]==sb[i]) {
09978       continue;
09979     }
09980 
09981     if (debug)
09982       printf("index %d, char [%c] [%c]\n", i, sa[i], sb[i]);
09983     
09984     if (sa[i] == 0) // string sa is shorter
09985       return -1;
09986     else if (sb[i] == 0) // string sb is shorter
09987       return 1;
09988 
09989     if (sa[i]<sb[i])
09990       return -1;
09991     else
09992       return 1;
09993   }
09994 
09995   // NOT REACHED
09996 }
09997 
09998 const bool cmp_events(const std::string& a, const std::string& b)
09999 {
10000   return cmp_names(a.c_str(), b.c_str()) < 0;
10001 }
10002 
10003 const bool cmp_events1(const std::string& a, const std::string& b)
10004 {
10005   return a < b;
10006 }
10007 
10008 const bool cmp_tags(const TAG& a, const TAG& b)
10009 {
10010   return cmp_names(a.name, b.name) < 0;
10011 }
10012 
10013 #if 0
10014 static int cmp_tags(const void *a, const void *b)
10015 {
10016   const TAG*sa = (const TAG*)a;
10017   const TAG*sb = (const TAG*)b;
10018   return cmp_names(sa->name, sb->name);
10019 }
10020 
10021 static void sort_tags(int ntags, TAG* tags)
10022 {
10023    qsort(tags, ntags, sizeof(TAG), cmp_tags);
10024 }
10025 #endif
10026 
10027 #define STRLCPY(dst, src) strlcpy((dst), (src), sizeof(dst))
10028 #define STRLCAT(dst, src) strlcat((dst), (src), sizeof(dst))
10029 
10030 struct hist_var_t
10031 {
10032    char event_name[NAME_LENGTH];
10033    char var_name[NAME_LENGTH];
10034    float hist_factor;
10035    float hist_offset;
10036    char hist_col[NAME_LENGTH];
10037    char hist_label[NAME_LENGTH];
10038    int  hist_order;
10039 };
10040 
10041 static int cmp_vars(const void *a, const void *b)
10042 {
10043    return ((const hist_var_t*)a)->hist_order >= ((const hist_var_t*)b)->hist_order;
10044 }
10045 
10046 static void print_vars(const hist_var_t vars[])
10047 {
10048    for (int i=0; i<MAX_VARS; i++) {
10049       if (vars[i].event_name[0]==0)
10050          break;
10051       printf("%d event [%s][%s] factor %f, offset %f, color [%s] label [%s] order %d\n", i, vars[i].event_name, vars[i].var_name, vars[i].hist_factor, vars[i].hist_offset, vars[i].hist_col, vars[i].hist_label, vars[i].hist_order);
10052    }
10053 }
10054 
10055 int xdb_get_data_index(HNDLE hDB, const char* str, void *value, int size, int index, int tid)
10056 {
10057    HNDLE hKey;
10058    int status = db_find_key(hDB, 0, str, &hKey);
10059    if (status != DB_SUCCESS)
10060       return status;
10061 
10062    KEY key;
10063    db_get_key(hDB, hKey, &key);
10064    if (index >= key.num_values)
10065       return DB_OUT_OF_RANGE;
10066 
10067    status = db_get_data_index(hDB, hKey, value, &size, index, tid);
10068    return status;
10069 }
10070 
10071 static void load_vars_odb(HNDLE hDB, const char* path, hist_var_t vars[])
10072 {
10073    for (int index=0; index<MAX_VARS; index++) {
10074       char str[256];
10075       char var_name_odb[256];
10076 
10077       var_name_odb[0] = 0;
10078 
10079       sprintf(str, "/History/Display/%s/Variables", path);
10080       xdb_get_data_index(hDB, str, var_name_odb, sizeof(var_name_odb), index, TID_STRING);
10081 
10082       if (var_name_odb[0] == 0)
10083          break;
10084 
10085       //printf("index %d, var_name_odb %s\n", index, var_name_odb);
10086 
10087       char* s = strchr(var_name_odb, ':');
10088 
10089       //printf("index %d, var_name_odb [%s] %p [%s]\n", index, var_name_odb, s, s?s:"");
10090 
10091       if (s)
10092          *s = 0;
10093       STRLCPY(vars[index].event_name, var_name_odb);
10094       if (s)
10095          STRLCPY(vars[index].var_name, s+1);
10096 
10097       //printf("index %d, var_name_odb [%s] %p [%s]\n", index, var_name_odb, s, s?(s+1):"");
10098 
10099       vars[index].hist_factor = 1;
10100 
10101       sprintf(str, "/History/Display/%s/Factor", path);
10102       xdb_get_data_index(hDB, str, &vars[index].hist_factor, sizeof(float), index, TID_FLOAT);
10103 
10104       vars[index].hist_offset = 0;
10105 
10106       sprintf(str, "/History/Display/%s/Offset", path);
10107       xdb_get_data_index(hDB, str, &vars[index].hist_offset, sizeof(float), index, TID_FLOAT);
10108 
10109       sprintf(str, "/History/Display/%s/Colour", path);
10110       xdb_get_data_index(hDB, str, &vars[index].hist_col, sizeof(vars[index].hist_col), index, TID_STRING);
10111 
10112       sprintf(str, "/History/Display/%s/Label", path);
10113       xdb_get_data_index(hDB, str, &vars[index].hist_label, sizeof(vars[index].hist_label), index, TID_STRING);
10114 
10115       vars[index].hist_order = (index+1)*10;
10116    }
10117 
10118    //print_vars(vars);
10119 }
10120 
10121 static void load_vars_param(hist_var_t vars[])
10122 {
10123    for (int index=0; index<MAX_VARS; index++) {
10124       char str[256];
10125 
10126       sprintf(str, "event%d", index);
10127       STRLCPY(vars[index].event_name, getparam(str));
10128 
10129       if (strlen(vars[index].event_name) < 1) {
10130          vars[index].event_name[0] = 0;
10131          break;
10132       }
10133 
10134       sprintf(str, "var%d", index);
10135       STRLCPY(vars[index].var_name, getparam(str));
10136 
10137       sprintf(str, "fac%d", index);
10138       vars[index].hist_factor = (float) atof(getparam(str));
10139     
10140       sprintf(str, "ofs%d", index);
10141       vars[index].hist_offset = (float) atof(getparam(str));
10142     
10143       sprintf(str, "col%d", index);
10144       STRLCPY(vars[index].hist_col, getparam(str));
10145 
10146       sprintf(str, "lab%d", index);
10147       STRLCPY(vars[index].hist_label, getparam(str));
10148 
10149       sprintf(str, "ord%d", index);
10150       vars[index].hist_order = atoi(getparam(str));
10151    }
10152 }
10153 
10154 static int xdb_find_key(HNDLE hDB, HNDLE dir, const char* str, HNDLE* hKey, int tid)
10155 {
10156    int status = db_find_key(hDB, dir, str, hKey);
10157    if (status == DB_SUCCESS)
10158       return status;
10159 
10160    db_create_key(hDB, dir, str, tid);
10161    status = db_find_key(hDB, dir, str, hKey);
10162    assert(hKey);
10163    return status;
10164 }
10165 
10166 static void resize_vars_odb(HNDLE hDB, const char* path, int index)
10167 {
10168    HNDLE hKey;
10169    char str[256];
10170 
10171    sprintf(str, "/History/Display/%s/Variables", path);
10172    xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10173 
10174    if (index == 0) {
10175       db_set_data_index(hDB, hKey, "", 2*NAME_LENGTH, index, TID_STRING);
10176       index = 1;
10177    }
10178 
10179    db_set_num_values(hDB, hKey, index);
10180 
10181    sprintf(str, "/History/Display/%s/Label", path);
10182    xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10183    db_set_num_values(hDB, hKey, index);
10184 
10185    sprintf(str, "/History/Display/%s/Colour", path);
10186    xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10187    db_set_num_values(hDB, hKey, index);
10188 
10189    sprintf(str, "/History/Display/%s/Factor", path);
10190    xdb_find_key(hDB, 0, str, &hKey, TID_FLOAT);
10191    db_set_num_values(hDB, hKey, index);
10192 
10193    sprintf(str, "/History/Display/%s/Offset", path);
10194    xdb_find_key(hDB, 0, str, &hKey, TID_FLOAT);
10195    db_set_num_values(hDB, hKey, index);
10196 }
10197 
10198 void save_vars_odb(HNDLE hDB, const char* path, const hist_var_t vars[])
10199 {
10200    int numvars = 0;
10201    for (int i=0; i<MAX_VARS; i++)
10202       if (vars[i].event_name[0] == 0) {
10203          numvars = i;
10204          break;
10205       }
10206 
10207    resize_vars_odb(hDB, path, numvars);
10208 
10209    for (int index=0; index<numvars; index++) {
10210       HNDLE hKey;
10211       char str[256];
10212       char var_name[256];
10213       sprintf(var_name, "%s:%s", vars[index].event_name, vars[index].var_name);
10214 
10215       sprintf(str, "/History/Display/%s/Variables", path);
10216       xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10217       db_set_data_index(hDB, hKey, var_name, 2 * NAME_LENGTH, index, TID_STRING);
10218 
10219       sprintf(str, "/History/Display/%s/Factor", path);
10220       xdb_find_key(hDB, 0, str, &hKey, TID_FLOAT);
10221       db_set_data_index(hDB, hKey, &vars[index].hist_factor, sizeof(float), index, TID_FLOAT);
10222      
10223       sprintf(str, "/History/Display/%s/Offset", path);
10224       xdb_find_key(hDB, 0, str, &hKey, TID_FLOAT);
10225       db_set_data_index(hDB, hKey, &vars[index].hist_offset, sizeof(float), index, TID_FLOAT);
10226      
10227       sprintf(str, "/History/Display/%s/Colour", path);
10228       xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10229       db_set_data_index(hDB, hKey, vars[index].hist_col, NAME_LENGTH, index, TID_STRING);
10230      
10231       sprintf(str, "/History/Display/%s/Label", path);
10232       xdb_find_key(hDB, 0, str, &hKey, TID_STRING);
10233       db_set_data_index(hDB, hKey, vars[index].hist_label, NAME_LENGTH, index, TID_STRING);
10234    }
10235 }
10236 
10237 static void add_vars(struct hist_var_t vars[], const char* event_name, const char* tag_name)
10238 {
10239    for (int i=0; i<MAX_VARS; i++) {
10240      if (vars[i].event_name[0] == 0) {
10241        STRLCPY(vars[i].event_name, event_name);
10242        STRLCPY(vars[i].var_name, tag_name);
10243        vars[i].hist_factor = 1;
10244        vars[i].hist_order = (i+1)*10;
10245        return;
10246      }
10247    }
10248 }
10249 
10250 /*------------------------------------------------------------------*/
10251 
10252 void show_hist_config_page(const char *path, const char *hgroup, const char *panel)
10253 {
10254    int status, size, index, sort_vars;
10255    BOOL flag;
10256    HNDLE hDB, hKeyVar;
10257    int max_display_events = 20;
10258    int max_display_tags = 200;
10259    char str[256], cmd[256], ref[256];
10260    struct hist_var_t vars[MAX_VARS];
10261    char def_hist_col[MAX_VARS][NAME_LENGTH] = { "#0000FF", "#00C000", "#FF0000", "#00C0C0", "#FF00FF",
10262       "#C0C000", "#808080", "#80FF80", "#FF8080", "#8080FF"
10263    };
10264 
10265    cm_get_experiment_database(&hDB, NULL);
10266 
10267    size = sizeof(max_display_events);
10268    db_get_value(hDB, 0, "/History/MaxDisplayEvents", &max_display_events, &size, TID_INT, TRUE);
10269 
10270    size = sizeof(max_display_tags);
10271    db_get_value(hDB, 0, "/History/MaxDisplayTags", &max_display_tags, &size, TID_INT, TRUE);
10272 
10273    strlcpy(cmd, getparam("cmd"), sizeof(cmd));
10274    hKeyVar = 0;
10275 
10276    if (equal_ustring(cmd, "Clear history cache")) {
10277       strcpy(cmd, "refresh");
10278       if (mh)
10279          mh->hs_clear_cache();
10280    }
10281 
10282    memset(vars, 0, sizeof(vars));
10283 
10284    for (int i=0; i<MAX_VARS; i++) {
10285       if (def_hist_col[i])
10286          STRLCPY(vars[i].hist_col, def_hist_col[i]);
10287       vars[i].hist_factor = 1;
10288    }
10289 
10290    //printf("cmd [%s]\n", cmd);
10291    //printf("cmdx [%s]\n", getparam("cmdx"));
10292 
10293    /* load variables from web request parameters */
10294    /* if list is empty, we are here for the first time,
10295     * load variables from ODB */
10296 
10297    load_vars_param(vars);
10298    if ((vars[0].event_name[0] == 0) && !equal_ustring(cmd, "refresh") && !equal_ustring(cmd, "save"))
10299       load_vars_odb(hDB, path, vars);
10300 
10301    /* delete variables according to "hist_order" */
10302 
10303    for (int i=0; i<MAX_VARS; i++) {
10304       if (vars[i].event_name[0]==0) {
10305          break;
10306       }
10307 
10308       while ((vars[i].hist_order <= 0) && (vars[i].event_name[0] != 0)) {
10309          for (int j=i+1; j<MAX_VARS; j++)
10310             vars[j-1] = vars[j];
10311       }
10312    }
10313 
10314    /* sort variables according to "hist_order" */
10315 
10316    bool need_sort = false;
10317    int num_vars = 0;
10318    for (int i=1; i<MAX_VARS; i++) {
10319       if (vars[i].event_name[0]==0) {
10320          num_vars = i;
10321          break;
10322       }
10323       if (vars[i-1].hist_order >= vars[i].hist_order) {
10324          need_sort = true;
10325       }
10326    }
10327 
10328    if (need_sort) {
10329       /* sort variables by order */
10330       qsort(vars, num_vars, sizeof(vars[0]), cmp_vars);
10331 
10332       for (int index=0; index<MAX_VARS; index++)
10333          vars[index].hist_order = (index+1)*10;
10334    }
10335 
10336    if (strlen(getparam("seln")) > 0) {
10337       int seln = atoi(getparam("seln"));
10338       for (int i=0; i<seln; i++) {
10339          char str[256];
10340          sprintf(str, "sel%d", i);
10341 
10342          char event_name[256];
10343          STRLCPY(event_name, getparam(str));
10344          if (strlen(event_name) < 1)
10345             continue;
10346 
10347          char tag_name[256];
10348          char* s = strchr(event_name, ':');
10349          if (!s)
10350             continue;
10351          *s = 0;
10352          STRLCPY(tag_name, s+1);
10353 
10354          add_vars(vars, event_name, tag_name);
10355       } 
10356    }
10357 
10358    //print_vars(vars);
10359 
10360    if (cmd[0] && equal_ustring(cmd, "save")) {
10361       save_vars_odb(hDB, path, vars);
10362 
10363       if (*getparam("timescale")) {
10364          sprintf(ref, "/History/Display/%s/Timescale", path);
10365          strlcpy(str, getparam("timescale"), sizeof(str));
10366          db_set_value(hDB, 0, ref, str, NAME_LENGTH, 1, TID_STRING);
10367       }
10368 
10369       if (*getparam("minimum")) {
10370          float val = (float) strtod(getparam("minimum"),NULL);
10371          sprintf(ref, "/History/Display/%s/Minimum", path);
10372          db_set_value(hDB, 0, ref, &val, sizeof(val), 1, TID_FLOAT);
10373       }
10374 
10375       if (*getparam("maximum")) {
10376          float val = (float) strtod(getparam("maximum"),NULL);
10377          sprintf(ref, "/History/Display/%s/Maximum", path);
10378          db_set_value(hDB, 0, ref, &val, sizeof(val), 1, TID_FLOAT);
10379       }
10380 
10381       sprintf(ref, "/History/Display/%s/Zero ylow", path);
10382       flag = *getparam("zero_ylow");
10383       db_set_value(hDB, 0, ref, &flag, sizeof(flag), 1, TID_BOOL);
10384 
10385       sprintf(ref, "/History/Display/%s/Log Axis", path);
10386       flag = *getparam("log_axis");
10387       db_set_value(hDB, 0, ref, &flag, sizeof(flag), 1, TID_BOOL);
10388 
10389       sprintf(ref, "/History/Display/%s/Show run markers", path);
10390       flag = *getparam("run_markers");
10391       db_set_value(hDB, 0, ref, &flag, sizeof(flag), 1, TID_BOOL);
10392 
10393       sprintf(ref, "/History/Display/%s/Show values", path);
10394       flag = *getparam("show_values");
10395       db_set_value(hDB, 0, ref, &flag, sizeof(flag), 1, TID_BOOL);
10396 
10397       sprintf(ref, "/History/Display/%s/Sort Vars", path);
10398       flag = *getparam("sort_vars");
10399       db_set_value(hDB, 0, ref, &flag, sizeof(flag), 1, TID_BOOL);
10400 
10401       strlcpy(str, path, sizeof(str));
10402       if (strrchr(str, '/'))
10403          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
10404       redirect(str);
10405       return;
10406    }
10407 
10408    if (panel[0]) {
10409       str[0] = 0;
10410       for (const char* p=path ; *p ; p++)
10411          if (*p == '/')
10412             strlcat(str, "../", sizeof(str));
10413       strlcat(str, hgroup, sizeof(str));
10414       strlcat(str, "/", sizeof(str));
10415       strlcat(str, panel, sizeof(str));
10416    } else {
10417       strlcpy(str, path, sizeof(str));
10418       if (strrchr(str, '/'))
10419          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
10420    }
10421    show_header(hDB, "History Config", "GET", str, 4, 0);
10422 
10423    /* menu buttons */
10424    rsprintf("<tr><td colspan=8 bgcolor=\"#C0C0C0\">\n");
10425    rsprintf("<input type=submit name=cmd value=Save>\n");
10426    rsprintf("<input type=submit name=cmd value=Cancel>\n");
10427    rsprintf("<input type=submit name=cmd value=Refresh>\n");
10428    rsprintf("<input type=submit name=cmd value=\"Clear history cache\">\n");
10429    rsprintf("<input type=submit name=cmd value=\"Delete Panel\">\n");
10430    rsprintf("</td></tr>\n");
10431 
10432    rsprintf("<tr><td colspan=8 bgcolor=\"#FFFF00\" align=center><b>Panel \"%s / %s\"</b>\n",
10433             hgroup, panel);
10434 
10435    /* hidden command for refresh */
10436    rsprintf("<input type=hidden name=cmd value=Refresh>\n");
10437    rsprintf("<input type=hidden name=panel value=\"%s\">\n", panel);
10438    rsprintf("<input type=hidden name=group value=\"%s\">\n", hgroup);
10439    rsprintf("</td></tr>\n");
10440 
10441    /* time scale */
10442    if (equal_ustring(cmd, "refresh"))
10443       strlcpy(str, getparam("timescale"), sizeof(str));
10444    else {
10445       sprintf(ref, "/History/Display/%s/%s/Timescale", hgroup, panel);
10446       size = NAME_LENGTH;
10447       db_get_value(hDB, 0, ref, str, &size, TID_STRING, TRUE);
10448    }
10449    rsprintf("<tr><td bgcolor=\"#E0E0E0\" colspan=8>Time scale: &nbsp;&nbsp;");
10450    rsprintf("<input type=text name=timescale value=%s></td></tr>\n", str);
10451 
10452    /* ylow_zero */
10453    if (equal_ustring(cmd, "refresh"))
10454       flag = *getparam("zero_ylow");
10455    else {
10456       sprintf(ref, "/History/Display/%s/%s/Zero ylow", hgroup, panel);
10457       size = sizeof(flag);
10458       db_get_value(hDB, 0, ref, &flag, &size, TID_BOOL, TRUE);
10459    }
10460    if (flag)
10461       rsprintf
10462           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox checked name=zero_ylow value=1>",
10463            str);
10464    else
10465       rsprintf
10466           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox name=zero_ylow value=1>",
10467            str);
10468    rsprintf("&nbsp;&nbsp;Zero Ylow</td></tr>\n");
10469 
10470    /* minimum */
10471    if (equal_ustring(cmd, "refresh"))
10472       strlcpy(str, getparam("minimum"), sizeof(str));
10473    else {
10474       float xxminimum = 0;
10475       sprintf(ref, "/History/Display/%s/%s/Minimum", hgroup, panel);
10476       size = sizeof(float);
10477       db_get_value(hDB, 0, ref, &xxminimum, &size, TID_FLOAT, TRUE);
10478       sprintf(str, "%f", xxminimum);
10479    }
10480    rsprintf("<tr><td bgcolor=\"#E0E0E0\" colspan=8>Minimum: &nbsp;&nbsp;");
10481    rsprintf("<input type=text name=minimum value=%s></td></tr>\n", str);
10482 
10483    /* maximum */
10484    if (equal_ustring(cmd, "refresh"))
10485       strlcpy(str, getparam("maximum"), sizeof(str));
10486    else {
10487       float xxmaximum = 0;
10488       sprintf(ref, "/History/Display/%s/%s/Maximum", hgroup, panel);
10489       size = sizeof(float);
10490       db_get_value(hDB, 0, ref, &xxmaximum, &size, TID_FLOAT, TRUE);
10491       sprintf(str, "%f", xxmaximum);
10492    }
10493    rsprintf("<tr><td bgcolor=\"#E0E0E0\" colspan=8>Maximum: &nbsp;&nbsp;");
10494    rsprintf("<input type=text name=maximum value=%s></td></tr>\n", str);
10495 
10496    /* log_axis */
10497    if (equal_ustring(cmd, "refresh"))
10498       flag = *getparam("log_axis");
10499    else {
10500       sprintf(ref, "/History/Display/%s/%s/Log axis", hgroup, panel);
10501       size = sizeof(flag);
10502       db_get_value(hDB, 0, ref, &flag, &size, TID_BOOL, TRUE);
10503    }
10504    if (flag)
10505       rsprintf
10506           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox checked name=log_axis value=1>",
10507            str);
10508    else
10509       rsprintf
10510           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox name=log_axis value=1>",
10511            str);
10512    rsprintf("&nbsp;&nbsp;Logarithmic Y axis</td></tr>\n");
10513 
10514    /* run_markers */
10515    if (equal_ustring(cmd, "refresh"))
10516       flag = *getparam("run_markers");
10517    else {
10518       sprintf(ref, "/History/Display/%s/%s/Show run markers", hgroup, panel);
10519       size = sizeof(flag);
10520       db_get_value(hDB, 0, ref, &flag, &size, TID_BOOL, TRUE);
10521    }
10522    if (flag)
10523       rsprintf
10524           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox checked name=run_markers value=1>",
10525            str);
10526    else
10527       rsprintf
10528           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox name=run_markers value=1>",
10529            str);
10530    rsprintf("&nbsp;&nbsp;Show run markers</td></tr>\n");
10531 
10532    /* show_values */
10533    if (equal_ustring(cmd, "refresh"))
10534       flag = *getparam("show_values");
10535    else {
10536       sprintf(ref, "/History/Display/%s/Show values", path);
10537       size = sizeof(flag);
10538       flag = 0;
10539       db_get_value(hDB, 0, ref, &flag, &size, TID_BOOL, TRUE);
10540    }
10541    if (flag)
10542       rsprintf
10543           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox checked name=show_values value=1>",
10544            str);
10545    else
10546       rsprintf
10547           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox name=show_values value=1>",
10548            str);
10549    rsprintf("&nbsp;&nbsp;Show values of variables</td></tr>\n");
10550 
10551    /* sort_vars */
10552    if (equal_ustring(cmd, "refresh"))
10553       sort_vars = *getparam("sort_vars");
10554    else {
10555       sprintf(ref, "/History/Display/%s/Sort Vars", path);
10556       size = sizeof(sort_vars);
10557       sort_vars = 0;
10558       db_get_value(hDB, 0, ref, &sort_vars, &size, TID_BOOL, TRUE);
10559    }
10560    if (sort_vars)
10561       rsprintf
10562           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox checked name=sort_vars value=1>",
10563            str);
10564    else
10565       rsprintf
10566           ("<tr><td bgcolor=\"#E0E0E0\" colspan=8><input type=checkbox name=sort_vars value=1>",
10567            str);
10568    rsprintf("&nbsp;&nbsp;Sort variable names (\"Save\" or \"Refresh\" to update the list)</td></tr>\n");
10569 
10570    /*---- events and variables ----*/
10571 
10572    /* get display event name */
10573 
10574    set_history_path();
10575 
10576    std::vector<std::string> events;
10577    mh->hs_get_events(&events);
10578 
10579    // has to be sorted of equipment name code below would not work
10580    //std::sort(events.begin(), events.end(), cmp_events);
10581    std::sort(events.begin(), events.end(), cmp_events1);
10582 
10583    if (strlen(getparam("cmdx")) > 0) {
10584       rsprintf("<tr><th colspan=1>Sel<th colspan=1>Equipment<th colspan=1>Event<th colspan=1>Variable</tr>\n");
10585 
10586       std::string cmdx = getparam("cmdx");
10587       std::string xeqname;
10588 
10589       int i=0;
10590       for (unsigned e=0; e<events.size(); e++) {
10591          std::string eqname;
10592          eqname = events[e].substr(0, events[e].find("/"));
10593 
10594          if (eqname.length() < 1)
10595             eqname = events[e];
10596 
10597          bool once = false;
10598          if (eqname != xeqname)
10599             once = true;
10600 
10601          std::string qcmd = "Expand " + eqname;
10602 
10603          //printf("param [%s] is [%s]\n", qcmd.c_str(), getparam(qcmd.c_str()));
10604 
10605          bool collapsed = true;
10606 
10607          if (cmdx == qcmd)
10608             collapsed = false;
10609 
10610          if (strlen(getparam(qcmd.c_str())) > 0)
10611             collapsed = false;
10612 
10613          if (collapsed) {
10614             if (eqname == xeqname)
10615                continue;
10616 
10617             rsprintf("<tr align=left>\n");
10618             rsprintf("<td></td>\n");
10619             rsprintf("<td>%s</td>\n", eqname.c_str());
10620             rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", qcmd.c_str());
10621             rsprintf("<td>%s</td>\n", "");
10622             rsprintf("</tr>\n");
10623             xeqname = eqname;
10624             continue;
10625          }
10626 
10627          if (once)
10628             rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", qcmd.c_str(), 1);
10629 
10630          std::string rcmd = "Expand " + events[e];
10631 
10632          //printf("param [%s] is [%s]\n", rcmd.c_str(), getparam(rcmd.c_str()));
10633 
10634          collapsed = true;
10635 
10636          if (cmdx == rcmd)
10637             collapsed = false;
10638 
10639          if (strlen(getparam(rcmd.c_str())) > 0)
10640             collapsed = false;
10641 
10642          if (collapsed) {
10643             rsprintf("<tr align=left>\n");
10644             rsprintf("<td></td>\n");
10645             rsprintf("<td>%s</td>\n", eqname.c_str());
10646             rsprintf("<td>%s</td>\n", events[e].c_str());
10647             rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", rcmd.c_str());
10648             rsprintf("</tr>\n");
10649             continue;
10650          }
10651 
10652          rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", rcmd.c_str(), 1);
10653 
10654          xeqname = eqname;
10655 
10656          std::vector<TAG> tags;
10657 
10658          status = mh->hs_get_tags(events[e].c_str(), &tags);
10659 
10660          if (tags.size() > 0) {
10661 
10662             if (sort_vars)
10663                std::sort(tags.begin(), tags.end(), cmp_tags);
10664 
10665             for (unsigned v=0; v<tags.size(); v++) {
10666 
10667                for (unsigned j=0; j<tags[v].n_data; j++) {
10668                   char tagname[256];
10669 
10670                   if (tags[v].n_data == 1)
10671                      sprintf(tagname, "%s", tags[v].name);
10672                   else
10673                      sprintf(tagname, "%s[%d]", tags[v].name, j);
10674 
10675                   bool checked = false;
10676 #if 0
10677                   for (int index=0; index<MAX_VARS; index++) {
10678                     if (equal_ustring(vars[index].event_name, events[e].c_str()) && equal_ustring(vars[index].var_name, tagname)) {
10679                       checked = true;
10680                       break;
10681                     }
10682                   }
10683 #endif
10684                   
10685 
10686 
10687                   rsprintf("<tr align=left>\n");
10688                   rsprintf("<td><input type=checkbox %s name=\"sel%d\" value=\"%s:%s\"></td>\n", checked?"checked":"", i++, events[e].c_str(), tagname);
10689                   rsprintf("<td>%s</td>\n", eqname.c_str());
10690                   rsprintf("<td>%s</td>\n", events[e].c_str());
10691                   rsprintf("<td>%s</td>\n", tagname);
10692                   rsprintf("</tr>\n");
10693                }
10694             }
10695          }
10696       }
10697 
10698       rsprintf("<tr>\n");
10699       rsprintf("<td></td>\n");
10700       rsprintf("<td>\n");
10701       rsprintf("<input type=hidden name=seln value=%d>\n", i);
10702       rsprintf("<input type=submit value=\"Add Selected\">\n");
10703       rsprintf("</td>\n");
10704       rsprintf("</tr>\n");
10705    }
10706 
10707    rsprintf("<tr><th>Col<th>Event<th>Variable<th>Factor<th>Offset<th>Colour<th>Label<th>Order</tr>\n");
10708 
10709    //print_vars(vars);
10710 
10711    /* extract colours */
10712    for (index = 0; index < MAX_VARS; index++) {
10713 
10714       if (!vars[index].hist_col[0])
10715          strlcpy(vars[index].hist_col, "#808080", NAME_LENGTH);
10716 
10717       rsprintf("<tr><td bgcolor=\"%s\">&nbsp;<td>\n", vars[index].hist_col);
10718 
10719       /* event and variable selection */
10720 
10721       rsprintf("<select name=\"event%d\" size=1 onChange=\"document.form1.submit()\">\n", index);
10722 
10723       /* enumerate events */
10724 
10725       /* empty option */
10726       rsprintf("<option value=\"\">&lt;empty&gt;\n");
10727 
10728       bool found_event = false;
10729 
10730       if ((int)events.size() < max_display_events || (strlen(vars[index].event_name) <= 0)) {
10731          for (unsigned e=0; e<events.size(); e++) {
10732             const char *s = "";
10733             const char *p = events[e].c_str();
10734             if (equal_ustring(vars[index].event_name, p)) {
10735                s = "selected";
10736                found_event = true;
10737             }
10738             rsprintf("<option %s value=\"%s\">%s\n", s, p, p);
10739          }
10740       }
10741 
10742       if (!found_event)
10743          if (strlen(vars[index].event_name) > 0) {
10744             rsprintf("<option selected value=\"%s\">%s\n", vars[index].event_name, vars[index].event_name);
10745          }
10746 
10747       rsprintf("</select></td>\n");
10748 
10749       //if (vars[index].hist_order <= 0)
10750       //vars[index].hist_order = (index+1)*10;
10751 
10752       if (vars[index].event_name[0]) {
10753          char selected_var[NAME_LENGTH];
10754 
10755          bool found_var = false;
10756 
10757          STRLCPY(selected_var, vars[index].var_name);
10758 
10759          rsprintf("<td><select name=\"var%d\">\n", index);
10760 
10761          std::vector<TAG> tags;
10762 
10763          status = mh->hs_get_tags(vars[index].event_name, &tags);
10764 
10765          if (tags.size() > 0) {
10766 
10767             if (0) {
10768                printf("Compare %d\n", cmp_names("AAA", "BBB"));
10769                printf("Compare %d\n", cmp_names("BBB", "AAA"));
10770                printf("Compare %d\n", cmp_names("AAA", "AAA"));
10771                printf("Compare %d\n", cmp_names("A", "AAA"));
10772                printf("Compare %d\n", cmp_names("A111", "A1"));
10773                printf("Compare %d\n", cmp_names("A111", "A2"));
10774                printf("Compare %d\n", cmp_names("A111", "A222"));
10775                printf("Compare %d\n", cmp_names("A111a", "A111b"));
10776             }
10777 
10778             if (sort_vars)
10779                std::sort(tags.begin(), tags.end(), cmp_tags);
10780 
10781             if (0) {
10782                printf("Event [%s] %d tags\n", vars[index].event_name, (int)tags.size());
10783 
10784                for (unsigned v=0; v<tags.size(); v++) {
10785                  printf("tag[%d] [%s]\n", v, tags[v].name);
10786                }
10787             }
10788 
10789             int count_tags = 0;
10790             for (unsigned v=0; v<tags.size(); v++)
10791                count_tags += tags[v].n_data;
10792 
10793             //printf("output %d option tags\n", count_tags);
10794 
10795             if (count_tags < max_display_tags) {
10796                for (unsigned v=0; v<tags.size(); v++) {
10797 
10798                  for (unsigned j=0; j<tags[v].n_data; j++) {
10799                     char tagname[256];
10800 
10801                     if (tags[v].n_data == 1)
10802                        sprintf(tagname, "%s", tags[v].name);
10803                     else
10804                        sprintf(tagname, "%s[%d]", tags[v].name, j);
10805 
10806                     if (equal_ustring(selected_var, tagname)) {
10807                        rsprintf("<option selected value=\"%s\">%s\n", tagname, tagname);
10808                        found_var = true;
10809                     }
10810                     else
10811                        rsprintf("<option value=\"%s\">%s\n", tagname, tagname);
10812 
10813                     //printf("%d [%s] [%s] [%s][%s] %d\n", index, vars[index].event_name, tagname, vars[index].var_name, selected_var, found_var);
10814                  }
10815                }
10816             }
10817          }
10818 
10819          if (!found_var)
10820             if (strlen(vars[index].var_name) > 0)
10821                rsprintf("<option selected value=\"%s\">%s\n", vars[index].var_name, vars[index].var_name);
10822 
10823          rsprintf("</select></td>\n");
10824 
10825       rsprintf("<td><input type=text size=10 maxlength=10 name=\"fac%d\" value=%g></td>\n", index, vars[index].hist_factor);
10826 
10827       rsprintf("<td><input type=text size=10 maxlength=10 name=\"ofs%d\" value=%g></td>\n", index, vars[index].hist_offset);
10828 
10829       rsprintf("<td><input type=text size=10 maxlength=10 name=\"col%d\" value=%s></td>\n", index, vars[index].hist_col);
10830 
10831       rsprintf("<td><input type=text size=10 maxlength=%d name=\"lab%d\" value=\"%s\"></td>\n", NAME_LENGTH, index, vars[index].hist_label);
10832 
10833       rsprintf("<td><input type=text size=5 maxlength=10 name=\"ord%d\" value=\"%d\"></td>\n", index, vars[index].hist_order);
10834 
10835       } else {
10836          rsprintf("<td><input type=submit name=cmdx value=\"List all variables\"></td>\n");
10837          rsprintf("<input type=hidden name=\"fac%d\" value=%g>\n", index, vars[index].hist_factor);
10838          rsprintf("<input type=hidden name=\"col%d\" value=%s>\n", index, vars[index].hist_col);
10839          rsprintf("<input type=hidden name=\"ord%d\" value=\"%d\">\n", index, (index+1)*10);
10840       }
10841 
10842       rsprintf("</tr>\n");
10843 
10844       /* loop over all already defined entries,
10845        * show one "empty" entry and exit */
10846       if (!vars[index].event_name[0])
10847          break;
10848    }
10849 
10850    rsprintf("</table></form>\n");
10851    rsprintf("</body></html>\r\n");
10852 }
10853 
10854 /*------------------------------------------------------------------*/
10855 
10856 void export_hist(const char *path, int scale, int toffset, int index, int labels)
10857 {
10858    HNDLE hDB, hkey, hkeypanel, hkeyeq, hkeydvar, hkeyvars, hkeyroot, hkeynames;
10859    KEY key;
10860    int i, j, k, l, n_vars, n_all_vars, size, status, n_vp;
10861    DWORD bsize, tsize, n_run_number, *state, *run_number, *t_run_number, i_run, *i_var;
10862    char str[256], fmt[256], *p, odbpath[256];
10863    INT var_index[MAX_VARS];
10864    DWORD type, event_id, dt;
10865    time_t t;
10866    char event_name[MAX_VARS][NAME_LENGTH];
10867    char tag_name[MAX_VARS][64], var_name[MAX_VARS][NAME_LENGTH], varname[64],
10868        key_name[256];
10869    DWORD n_point[MAX_VARS];
10870    DWORD *x[MAX_VARS];
10871    float *y[MAX_VARS];
10872    float factor[MAX_VARS], offset[MAX_VARS];
10873    BOOL runmarker;
10874    struct tm *tms;
10875 
10876    static char *ybuffer;
10877    static DWORD *tbuffer;
10878    static int hbuffer_size = 0;
10879 
10880    if (hbuffer_size == 0) {
10881       hbuffer_size = 1000 * sizeof(DWORD);
10882       tbuffer = (DWORD*)malloc(hbuffer_size);
10883       ybuffer = (char*)malloc(hbuffer_size);
10884    }
10885 
10886    /* header */
10887    rsprintf("HTTP/1.1 200 Document follows\r\n");
10888    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
10889    rsprintf("Accept-Ranges: bytes\r\n");
10890    rsprintf("Pragma: no-cache\r\n");
10891    rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
10892    rsprintf("Content-Type: text/plain\r\n");
10893    rsprintf("Content-disposition: attachment; filename=\"export.csv\"\r\n");
10894    rsprintf("\r\n");
10895 
10896    cm_get_experiment_database(&hDB, NULL);
10897 
10898    /* set history path */
10899    status = db_find_key(hDB, 0, "/Logger/Data dir", &hkey);
10900    if (status != DB_SUCCESS) {
10901       rsprintf("No data directory defined in ODB");
10902       return;
10903    }
10904 
10905    /* check dedicated history path */
10906    set_history_path();
10907 
10908    /* check panel name in ODB */
10909    sprintf(str, "/History/Display/%s", path);
10910    db_find_key(hDB, 0, str, &hkeypanel);
10911    if (!hkey) {
10912       rsprintf("Cannot find /History/Display/%s in ODB", path);
10913       return;
10914    }
10915 
10916    db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
10917    if (!hkeydvar) {
10918       rsprintf("Cannot find /History/Display/%s/Variables in ODB", str);
10919       return;
10920    }
10921 
10922    db_get_key(hDB, hkeydvar, &key);
10923    n_all_vars = key.num_values;
10924 
10925    if (n_all_vars > MAX_VARS) {
10926       rsprintf(str, "Too many variables in panel %s", path);
10927       return;
10928    }
10929 
10930    for (i = n_vars = 0; i < n_all_vars; i++) {
10931       if (index != -1 && index != i)
10932          continue;
10933 
10934       size = sizeof(str);
10935       db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
10936       strlcpy(tag_name[n_vars], str, sizeof(tag_name[0]));
10937 
10938       /* split varname in event, variable and index */
10939       if (strchr(tag_name[n_vars], ':')) {
10940          strlcpy(event_name[n_vars], tag_name[n_vars], sizeof(event_name[0]));
10941          *strchr(event_name[n_vars], ':') = 0;
10942          strlcpy(var_name[n_vars], strchr(tag_name[n_vars], ':') + 1, sizeof(var_name[0]));
10943          var_index[n_vars] = 0;
10944          if (strchr(var_name[n_vars], '[')) {
10945             var_index[n_vars] = atoi(strchr(var_name[n_vars], '[') + 1);
10946             *strchr(var_name[n_vars], '[') = 0;
10947          }
10948       } else {
10949          rsprintf("Tag \"%s\" has wrong format in panel %s", tag_name[n_vars], path);
10950          return;
10951       }
10952 
10953       /* search event_id */
10954       status = hs_get_event_id(0, event_name[n_vars], &event_id);
10955 
10956       if (status != HS_SUCCESS) {
10957          rsprintf("Event \"%s\" from panel \"%s\" not found in history",
10958                   event_name[n_vars], path);
10959          return;
10960       }
10961 
10962       /* get timescale */
10963       if (scale == 0) {
10964          strlcpy(str, "1h", sizeof(str));
10965          size = NAME_LENGTH;
10966          status = db_get_value(hDB, hkeypanel, "Timescale", str, &size, TID_STRING, TRUE);
10967          if (status != DB_SUCCESS) {
10968             /* delete old integer key */
10969             db_find_key(hDB, hkeypanel, "Timescale", &hkey);
10970             if (hkey)
10971                db_delete_key(hDB, hkey, FALSE);
10972 
10973             strcpy(str, "1h");
10974             size = NAME_LENGTH;
10975             status =
10976                 db_get_value(hDB, hkeypanel, "Timescale", str, &size, TID_STRING, TRUE);
10977          }
10978 
10979          scale = time_to_sec(str);
10980       }
10981 
10982       for (j = 0; j < MAX_VARS; j++) {
10983          factor[j] = 1;
10984          offset[j] = 0;
10985       }
10986 
10987       /* get factors */
10988       size = sizeof(float) * n_vars;
10989       db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
10990 
10991       /* get offsets */
10992       size = sizeof(float) * n_vars;
10993       db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
10994 
10995       /* get runmarker flag */
10996       size = sizeof(runmarker);
10997       runmarker = 1;
10998       db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
10999 
11000       /* make ODB path from tag name */
11001       odbpath[0] = 0;
11002       db_find_key(hDB, 0, "/Equipment", &hkeyroot);
11003       if (hkeyroot) {
11004          for (j = 0;; j++) {
11005             db_enum_key(hDB, hkeyroot, j, &hkeyeq);
11006 
11007             if (!hkeyeq)
11008                break;
11009 
11010             db_get_key(hDB, hkeyeq, &key);
11011             if (equal_ustring(key.name, event_name[n_vars])) {
11012                /* check if variable is individual key under variabels/ */
11013                sprintf(str, "Variables/%s", var_name[n_vars]);
11014                db_find_key(hDB, hkeyeq, str, &hkey);
11015                if (hkey) {
11016                   sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[n_vars],
11017                           var_name[n_vars]);
11018                   break;
11019                }
11020 
11021                /* check if variable is in setttins/names array */
11022                db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
11023                if (hkeynames) {
11024                   /* extract variable name and Variables/<key> */
11025                   strlcpy(str, var_name[n_vars], sizeof(str));
11026                   p = str + strlen(str) - 1;
11027                   while (p > str && *p != ' ')
11028                      p--;
11029                   strlcpy(key_name, p + 1, sizeof(key_name));
11030                   *p = 0;
11031                   strlcpy(varname, str, sizeof(varname));
11032 
11033                   /* find key in single name array */
11034                   db_get_key(hDB, hkeynames, &key);
11035                   for (k = 0; k < key.num_values; k++) {
11036                      size = sizeof(str);
11037                      db_get_data_index(hDB, hkeynames, str, &size, k, TID_STRING);
11038                      if (equal_ustring(str, varname)) {
11039                         sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[n_vars],
11040                                 key_name, k);
11041                         break;
11042                      }
11043                   }
11044                } else {
11045                   /* go through /variables/<name> entries */
11046                   db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
11047                   if (hkeyvars) {
11048                      for (k = 0;; k++) {
11049                         db_enum_key(hDB, hkeyvars, k, &hkey);
11050 
11051                         if (!hkey)
11052                            break;
11053 
11054                         /* find "settins/names <key>" for this key */
11055                         db_get_key(hDB, hkey, &key);
11056 
11057                         /* find key in key_name array */
11058                         strlcpy(key_name, key.name, sizeof(key_name));
11059                         sprintf(str, "Settings/Names %s", key_name);
11060 
11061                         db_find_key(hDB, hkeyeq, str, &hkeynames);
11062                         if (hkeynames) {
11063                            db_get_key(hDB, hkeynames, &key);
11064                            for (l = 0; l < key.num_values; l++) {
11065                               size = sizeof(str);
11066                               db_get_data_index(hDB, hkeynames, str, &size, l,
11067                                                 TID_STRING);
11068                               if (equal_ustring(str, var_name[n_vars])) {
11069                                  sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]",
11070                                          event_name[n_vars], key_name, l);
11071                                  break;
11072                               }
11073                            }
11074                         }
11075                      }
11076                   }
11077                }
11078 
11079                break;
11080             }
11081          }
11082 
11083          if (!hkeyeq) {
11084             db_find_key(hDB, 0, "/History/Links", &hkeyroot);
11085             if (hkeyroot) {
11086                for (j = 0;; j++) {
11087                   db_enum_link(hDB, hkeyroot, j, &hkey);
11088 
11089                   if (!hkey)
11090                      break;
11091 
11092                   db_get_key(hDB, hkey, &key);
11093                   if (equal_ustring(key.name, event_name[n_vars])) {
11094                      db_enum_key(hDB, hkeyroot, j, &hkey);
11095                      db_find_key(hDB, hkey, var_name[n_vars], &hkey);
11096                      if (hkey) {
11097                         db_get_key(hDB, hkey, &key);
11098                         db_get_path(hDB, hkey, odbpath, sizeof(odbpath));
11099                         if (key.num_values > 1)
11100                            sprintf(odbpath + strlen(odbpath), "[%d]", var_index[n_vars]);
11101                         break;
11102                      }
11103                   }
11104                }
11105             }
11106          }
11107       }
11108 
11109       do {
11110          bsize = tsize = hbuffer_size;
11111          memset(ybuffer, 0, bsize);
11112          status =
11113              hs_read(event_id, ss_time() - scale + toffset, ss_time() + toffset,
11114                      0, var_name[n_vars], var_index[n_vars], tbuffer, &tsize,
11115                      ybuffer, &bsize, &type, &n_point[n_vars]);
11116 
11117          if (status == HS_TRUNCATED) {
11118             hbuffer_size *= 2;
11119             tbuffer = (DWORD*)realloc(tbuffer, hbuffer_size);
11120             assert(tbuffer);
11121             ybuffer = (char*)realloc(ybuffer, hbuffer_size);
11122             assert(ybuffer);
11123          }
11124 
11125       } while (status == HS_TRUNCATED);
11126 
11127       if (status == HS_UNDEFINED_VAR) {
11128          rsprintf("Variable \"%s\" not found in history", var_name[n_vars]);
11129          return;
11130       }
11131 
11132       x[n_vars] = (DWORD*)M_MALLOC(sizeof(DWORD) * n_point[n_vars]);
11133       y[n_vars] = (float*)M_MALLOC(sizeof(DWORD) * n_point[n_vars]);
11134 
11135       for (j = n_vp = 0; j < (int) n_point[n_vars]; j++) {
11136          x[n_vars][n_vp] = tbuffer[j];
11137 
11138          /* convert data to float */
11139          switch (type) {
11140          case TID_BYTE:
11141             y[n_vars][n_vp] = (float) *(((BYTE *) ybuffer) + j);
11142             break;
11143          case TID_SBYTE:
11144             y[n_vars][n_vp] = (float) *(((char *) ybuffer) + j);
11145             break;
11146          case TID_CHAR:
11147             y[n_vars][n_vp] = (float) *(((char *) ybuffer) + j);
11148             break;
11149          case TID_WORD:
11150             y[n_vars][n_vp] = (float) *(((WORD *) ybuffer) + j);
11151             break;
11152          case TID_SHORT:
11153             y[n_vars][n_vp] = (float) *(((short *) ybuffer) + j);
11154             break;
11155          case TID_DWORD:
11156             y[n_vars][n_vp] = (float) *(((DWORD *) ybuffer) + j);
11157             break;
11158          case TID_INT:
11159             y[n_vars][n_vp] = (float) *(((INT *) ybuffer) + j);
11160             break;
11161          case TID_BOOL:
11162             y[n_vars][n_vp] = (float) *(((BOOL *) ybuffer) + j);
11163             break;
11164          case TID_FLOAT:
11165             y[n_vars][n_vp] = (float) *(((float *) ybuffer) + j);
11166             break;
11167          case TID_DOUBLE:
11168             y[n_vars][n_vp] = (float) *(((double *) ybuffer) + j);
11169             break;
11170          }
11171 
11172          /* skip NaNs */
11173          if (ss_isnan(y[n_vars][n_vp]))
11174             continue;
11175 
11176          /* apply factor and offset */
11177          y[n_vars][n_vp] = y[n_vars][n_vp] * factor[n_vars] + offset[n_vars];
11178 
11179          /* increment number of valid points */
11180          n_vp++;
11181       }
11182 
11183       n_point[n_vars] = n_vp;
11184 
11185       n_vars ++;
11186    }
11187 
11188    /* read run markes if selected */
11189    state = run_number = t_run_number = NULL;
11190    n_run_number = 0;
11191    if (runmarker) {
11192       bsize = hbuffer_size;
11193       tsize = hbuffer_size;
11194 
11195       /* read run state */
11196 
11197       status = hs_read(0, ss_time() - scale + toffset - scale, ss_time() + toffset, 0,
11198                        "State", 0, tbuffer, &tsize, ybuffer, &bsize, &type, &n_run_number);
11199 
11200       if (status != HS_UNDEFINED_VAR) {
11201         state = (DWORD*)M_MALLOC(sizeof(DWORD) * n_run_number);
11202          for (j = 0; j < (int) n_run_number; j++)
11203             state[j] = *((DWORD *) ybuffer + j);
11204       }
11205 
11206       bsize = hbuffer_size;
11207       tsize = hbuffer_size;
11208 
11209       /* read run number */
11210 
11211       status = hs_read(0, ss_time() - scale + toffset - scale, ss_time() + toffset, 0,
11212                        "Run number", 0, tbuffer, &tsize, ybuffer, &bsize, &type,
11213                        &n_run_number);
11214 
11215       if (status != HS_UNDEFINED_VAR) {
11216         run_number = (DWORD*)M_MALLOC(sizeof(DWORD) * n_run_number);
11217         t_run_number = (DWORD*)M_MALLOC(sizeof(DWORD) * n_run_number);
11218          for (j = 0; j < (int) n_run_number; j++) {
11219             t_run_number[j] = tbuffer[j];
11220             run_number[j] = *((DWORD *) ybuffer + j);
11221          }
11222       }
11223 
11224    }
11225 
11226    /* output header line with variable names */
11227    if (runmarker)
11228       rsprintf("Time, Run, Run State, ");
11229    else
11230       rsprintf("Time, ");
11231 
11232    for (i = 0; i < n_vars; i++) {
11233       rsprintf(var_name[i]);
11234       if (i < n_vars-1)
11235          rsprintf(", ");
11236    }
11237    rsprintf("\n");
11238 
11239    i_var = (DWORD*)M_MALLOC(sizeof(DWORD) * n_vars);
11240 
11241    i_run = 0;
11242    for (i = 0; i < n_vars; i++) 
11243       i_var[i] = 0;
11244 
11245    /* find first time where all variables are available */
11246    if (n_vars == 1)
11247       t = x[0][0];
11248    else {
11249       t = 0;
11250       for (i = 1; i < n_vars; i++) 
11251          if (n_point[i] > 0 && x[i][0] > (DWORD)t)
11252             t = x[i][0];
11253    }
11254 
11255    if (t == 0 && n_vars > 1) {
11256       rsprintf("=== No history available for choosen period ===\n");
11257       return;
11258    }
11259 
11260    do {
11261       /* find run number/state which is valid for t */
11262       if (runmarker)
11263          while (i_run < n_run_number-1 && t_run_number[i_run+1] <= (DWORD)t)
11264             i_run++;
11265 
11266       /* find index for all variables which is valid for t */
11267       for (i = 0; i < n_vars; i++)
11268          while (n_point[i] > 0 && i_var[i] < n_point[i] - 1 && x[i][i_var[i]+1] <= (DWORD)t)
11269             i_var[i]++;
11270 
11271       /* finish if last point for all variables reached */
11272       for (i = 0 ; i < n_vars ; i++)
11273          if (n_point[i] > 0 && i_var[i] < n_point[i] - 1)
11274             break;
11275       if (i == n_vars)
11276          break;
11277 
11278       tms = localtime(&t);
11279       strcpy(fmt, "%c");
11280       strftime(str, sizeof(str), fmt, tms);
11281 
11282       if (runmarker) {
11283          if (t_run_number[i_run] <= (DWORD)t)
11284             rsprintf("%s, %d, %d, ", str, run_number[i_run], state[i_run]);
11285          else
11286             rsprintf("%s, N/A, N/A, ", str);
11287       } else
11288          rsprintf("%s, ", str);
11289 
11290       for (i= 0 ; i < n_vars ; i++) {
11291             rsprintf("%lf", y[i][i_var[i]]);
11292          if (i < n_vars-1)
11293             rsprintf(", ");
11294       }
11295       rsprintf("\n");
11296 
11297       /* find next t as smallest delta t */
11298       dt = (DWORD) (x[0][i_var[0]+1] - t);
11299       for (i = 1 ; i < n_vars ; i++)
11300          if (x[i][i_var[i]+1] - t < dt)
11301             dt = (DWORD) (x[i][i_var[i]+1] - t);
11302       t += dt;
11303 
11304    } while (1);
11305 
11306    M_FREE(i_var);
11307    for (i=0 ; i<n_vars ; i++) {
11308       M_FREE(x[i]);
11309       M_FREE(y[i]);
11310    }
11311 
11312    if (state)
11313       M_FREE(state);
11314 
11315    if (run_number)
11316       M_FREE(run_number);
11317 
11318    if (t_run_number)
11319       M_FREE(t_run_number);
11320 }
11321 
11322 /*------------------------------------------------------------------*/
11323 
11324 void show_hist_page(const char *path, int path_size, char *buffer, int *buffer_size,
11325                     int refresh)
11326 {
11327    char str[256], ref[256], ref2[256], paramstr[256], scalestr[256], hgroup[256],
11328        bgcolor[32], fgcolor[32], gridcolor[32], url[256], dir[256], file_name[256],
11329        back_path[256], panel[256];
11330    char hurl[256];
11331    const char *p;
11332    HNDLE hDB, hkey, hikeyp, hkeyp, hkeybutton;
11333    KEY key, ikey;
11334    int i, j, k, scale, offset, index, width, size, status, labels, fh, fsize;
11335    float factor[2];
11336    char def_button[][NAME_LENGTH] = { "10m", "1h", "3h", "12h", "24h", "3d", "7d" };
11337    time_t now;
11338    struct tm *tms;
11339 
11340    cm_get_experiment_database(&hDB, NULL);
11341 
11342    if (equal_ustring(getparam("cmd"), "Query")) {
11343       show_query_page(path);
11344       return;
11345    }
11346 
11347    if (equal_ustring(getparam("cmd"), "cancel")) {
11348       strlcpy(str, path, sizeof(str));
11349       if (strrchr(str, '/'))
11350          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
11351       redirect(str);
11352       return;
11353    }
11354 
11355    if (equal_ustring(getparam("cmd"), "Config") ||
11356        equal_ustring(getparam("cmd"), "Save")
11357        || equal_ustring(getparam("cmd"), "Clear history cache")
11358        || equal_ustring(getparam("cmd"), "Refresh")) {
11359 
11360       /* get group and panel from path if not given */
11361       if (!isparam("group")) {
11362          strlcpy(hgroup, path, sizeof(hgroup));
11363          if (strchr(hgroup, '/'))
11364             *strchr(hgroup, '/') = 0;
11365          panel[0] = 0;
11366          if (strrchr(path, '/'))
11367             strlcpy(panel, strrchr(path, '/')+1, sizeof(panel));
11368       } else {
11369          strlcpy(hgroup, getparam("group"), sizeof(hgroup));
11370          strlcpy(panel, getparam("panel"), sizeof(panel));
11371       }
11372 
11373       show_hist_config_page(path, hgroup, panel);
11374       return;
11375    }
11376 
11377    /* evaluate path pointing back to /HS */
11378    back_path[0] = 0;
11379    for (p=path ; *p ; p++)
11380       if (*p == '/')
11381          strlcat(back_path, "../", sizeof(back_path));
11382 
11383    if (isparam("fpanel") && isparam("fgroup") && 
11384       !isparam("scale")  && !isparam("shift") && !isparam("width") && !isparam("cmd")) {
11385 
11386       if (strchr(path, '/')) {
11387          strlcpy(panel, strchr(path, '/') + 1, sizeof(panel));
11388          strlcpy(hgroup, path, sizeof(hgroup));
11389          *strchr(hgroup, '/') = 0;
11390       } else {
11391          strlcpy(hgroup, path, sizeof(str));
11392          panel[0] = 0;
11393       }
11394 
11395       /* rewrite path if parameters come from a form submission */
11396 
11397       char path[256];
11398       /* check if group changed */
11399       if (!equal_ustring(getparam("fgroup"), hgroup))
11400          sprintf(path, "%s%s", back_path, getparam("fgroup"));
11401       else if (*getparam("fpanel"))
11402          sprintf(path, "%s%s/%s", back_path, getparam("fgroup"), getparam("fpanel"));
11403       else
11404          sprintf(path, "%s%s", back_path, getparam("fgroup"));
11405 
11406       redirect(path);
11407       return;
11408    }
11409 
11410    if (equal_ustring(getparam("cmd"), "New")) {
11411       strlcpy(str, path, sizeof(str));
11412       if (strrchr(str, '/'))
11413          strlcpy(str, strrchr(str, '/')+1, sizeof(str));
11414       show_header(hDB, "History", "GET", str, 1, 0);
11415 
11416       rsprintf("<tr><td align=center bgcolor=\"#FFFF80\" colspan=2>\n");
11417       rsprintf("Select group: &nbsp;&nbsp;");
11418       rsprintf("<select name=\"group\">\n");
11419 
11420       /* list existing groups */
11421       db_find_key(hDB, 0, "/History/Display", &hkey);
11422       if (hkey) {
11423          for (i = 0;; i++) {
11424             db_enum_link(hDB, hkey, i, &hkeyp);
11425 
11426             if (!hkeyp)
11427                break;
11428 
11429             db_get_key(hDB, hkeyp, &key);
11430             if (equal_ustring(path, key.name))
11431                rsprintf("<option selected>%s</option>\n", key.name);
11432             else
11433                rsprintf("<option>%s</option>\n", key.name);
11434          }
11435       }
11436       if (!hkey || i == 0)
11437          rsprintf("<option>Default</option>\n");
11438       rsprintf("</select><p>\n");
11439 
11440       rsprintf("Or enter new group name: &nbsp;&nbsp;");
11441       rsprintf("<input type=text size=15 maxlength=31 name=new_group>\n");
11442 
11443       rsprintf("<tr><td align=center bgcolor=\"#FFFF00\" colspan=2>\n");
11444       rsprintf("<br>Panel name: &nbsp;&nbsp;");
11445       rsprintf("<input type=text size=15 maxlength=31 name=panel><br><br>\n");
11446       rsprintf("</td></tr>\n");
11447 
11448       rsprintf("<tr><td align=center colspan=2>");
11449       rsprintf("<input type=submit value=Submit>\n");
11450       rsprintf("</td></tr>\n");
11451 
11452       rsprintf("</table>\r\n");
11453       rsprintf("</body></html>\r\n");
11454       return;
11455    }
11456 
11457    if (equal_ustring(getparam("cmd"), "Delete Panel")) {
11458       sprintf(str, "/History/Display/%s", path);
11459       if (db_find_key(hDB, 0, str, &hkey)==DB_SUCCESS)
11460          db_delete_key(hDB, hkey, FALSE);
11461 
11462       redirect("../");
11463       return;
11464    }
11465 
11466    if (*getparam("panel")) {
11467       strlcpy(panel, getparam("panel"), sizeof(panel));
11468       
11469       /* strip leading/trailing spaces */
11470       while (*panel == ' ')
11471          strlcpy(panel, panel+1, sizeof(panel));
11472       while (strlen(panel)> 1 && panel[strlen(panel)-1] == ' ')
11473          panel[strlen(panel)-1] = 0;
11474 
11475       strlcpy(hgroup, getparam("group"), sizeof(hgroup));
11476       /* use new group if present */
11477       if (isparam("new_group") && *getparam("new_group"))
11478          strlcpy(hgroup, getparam("new_group"), sizeof(hgroup));
11479 
11480       /* create new panel */
11481       sprintf(str, "/History/Display/%s/%s", hgroup, panel);
11482       db_create_key(hDB, 0, str, TID_KEY);
11483       db_find_key(hDB, 0, str, &hkey);
11484       assert(hkey);
11485       db_set_value(hDB, hkey, "Timescale", "1h", NAME_LENGTH, 1, TID_STRING);
11486       i = 1;
11487       db_set_value(hDB, hkey, "Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11488       db_set_value(hDB, hkey, "Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11489       i = 0;
11490       db_set_value(hDB, hkey, "Show values", &i, sizeof(BOOL), 1, TID_BOOL);
11491       i = 0;
11492       db_set_value(hDB, hkey, "Sort Vars", &i, sizeof(BOOL), 1, TID_BOOL);
11493       i = 0;
11494       db_set_value(hDB, hkey, "Log axis", &i, sizeof(BOOL), 1, TID_BOOL);
11495 
11496       /* configure that panel */
11497       show_hist_config_page(path, hgroup, panel);
11498       return;
11499    }
11500 
11501    const char* pscale = getparam("scale");
11502    if (pscale == NULL || *pscale == 0)
11503       pscale = getparam("hscale");
11504    const char* poffset = getparam("offset");
11505    if (poffset == NULL || *poffset == 0)
11506       poffset = getparam("hoffset");
11507    const char* pmag = getparam("width");
11508    if (pmag == NULL || *pmag == 0)
11509       pmag = getparam("hwidth");
11510    const char* pindex = getparam("index");
11511    if (pindex == NULL || *pindex == 0)
11512       pindex = getparam("hindex");
11513 
11514    labels = 1;
11515    if (*getparam("labels") && atoi(getparam("labels")) == 0)
11516       labels = 0;
11517 
11518    if (*getparam("bgcolor"))
11519       strlcpy(bgcolor, getparam("bgcolor"), sizeof(bgcolor));
11520    else
11521       strcpy(bgcolor, "FFFFFF");
11522 
11523    if (*getparam("fgcolor"))
11524       strlcpy(fgcolor, getparam("fgcolor"), sizeof(fgcolor));
11525    else
11526       strcpy(fgcolor, "000000");
11527 
11528    if (*getparam("gcolor"))
11529       strlcpy(gridcolor, getparam("gcolor"), sizeof(gridcolor));
11530    else
11531       strcpy(gridcolor, "A0A0A0");
11532 
11533    /* evaluate scale and offset */
11534 
11535    if (poffset && *poffset)
11536       offset = time_to_sec(poffset);
11537    else
11538       offset = 0;
11539 
11540    if (pscale && *pscale)
11541       scale = time_to_sec(pscale);
11542    else
11543       scale = 0;
11544 
11545    index = -1;
11546    if (pindex && *pindex)
11547       index = atoi(pindex);
11548 
11549    /* use contents of "/History/URL" to access history images (*images only*)
11550     * otherwise, use relative addresses from "back_path" */
11551 
11552    size = sizeof(hurl);
11553    status = db_get_value(hDB, 0, "/History/URL", hurl, &size, TID_STRING, FALSE);
11554    if (status != DB_SUCCESS)
11555       strlcpy(hurl, back_path, sizeof(hurl));
11556 
11557    if (equal_ustring(getparam("cmd"), "Create ELog")) {
11558       size = sizeof(url);
11559       if (db_get_value(hDB, 0, "/Elog/URL", url, &size, TID_STRING, FALSE) == DB_SUCCESS) {
11560 
11561          get_elog_url(url, sizeof(url));
11562 
11563          /*---- use external ELOG ----*/
11564          fsize = 100000;
11565          char* fbuffer = (char*)M_MALLOC(fsize);
11566          assert(fbuffer != NULL);
11567 
11568          if (equal_ustring(pmag, "Large"))
11569             generate_hist_graph(path, fbuffer, &fsize, 1024, 768, scale, offset, index,
11570                               labels, bgcolor, fgcolor, gridcolor);
11571          else if (equal_ustring(pmag, "Small"))
11572             generate_hist_graph(path, fbuffer, &fsize, 320, 200, scale, offset, index,
11573                               labels, bgcolor, fgcolor, gridcolor);
11574          else
11575             generate_hist_graph(path, fbuffer, &fsize, 640, 400, scale, offset, index,
11576                               labels, bgcolor, fgcolor, gridcolor);
11577 
11578          /* save temporary file */
11579          size = sizeof(dir);
11580          dir[0] = 0;
11581          db_get_value(hDB, 0, "/Elog/Logbook Dir", dir, &size, TID_STRING, TRUE);
11582          if (strlen(dir) > 0 && dir[strlen(dir)-1] != DIR_SEPARATOR)
11583             strlcat(dir, DIR_SEPARATOR_STR, sizeof(dir));
11584 
11585          time(&now);
11586          tms = localtime(&now);
11587 
11588          if (strchr(path, '/'))
11589             strlcpy(str, strchr(path, '/') + 1, sizeof(str));
11590          else
11591             strlcpy(str, path, sizeof(str));
11592          sprintf(file_name, "%02d%02d%02d_%02d%02d%02d_%s.gif",
11593                   tms->tm_year % 100, tms->tm_mon + 1, tms->tm_mday,
11594                   tms->tm_hour, tms->tm_min, tms->tm_sec, str);
11595          sprintf(str, "%s%s", dir, file_name);
11596 
11597          /* save attachment */
11598          fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
11599          if (fh < 0) {
11600             cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\"",
11601                      str);
11602          } else {
11603             write(fh, fbuffer, fsize);
11604             close(fh);
11605          }
11606 
11607          /* redirect to ELOG */
11608          if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11609             strlcat(url, "/", sizeof(url));
11610          strlcat(url, "?cmd=New&fa=", sizeof(url));
11611          strlcat(url, file_name, sizeof(url));
11612          redirect(url);
11613 
11614          M_FREE(fbuffer);
11615          return;
11616 
11617       } else {
11618          /*---- use internal ELOG ----*/
11619          sprintf(str, "\\HS\\%s.gif", path);
11620          if (getparam("hscale") && *getparam("hscale"))
11621             sprintf(str + strlen(str), "?scale=%s", getparam("hscale"));
11622          if (getparam("hoffset") && *getparam("hoffset")) {
11623             if (strchr(str, '?'))
11624                strlcat(str, "&", sizeof(str));
11625             else
11626                strlcat(str, "?", sizeof(str));
11627             sprintf(str + strlen(str), "offset=%s", getparam("hoffset"));
11628          }
11629          if (getparam("hwidth") && *getparam("hwidth")) {
11630             if (strchr(str, '?'))
11631                strlcat(str, "&", sizeof(str));
11632             else
11633                strlcat(str, "?", sizeof(str));
11634             sprintf(str + strlen(str), "width=%s", getparam("hwidth"));
11635          }
11636          if (getparam("hindex") && *getparam("hindex")) {
11637             if (strchr(str, '?'))
11638                strlcat(str, "&", sizeof(str));
11639             else
11640                strlcat(str, "?", sizeof(str));
11641             sprintf(str + strlen(str), "index=%s", getparam("hindex"));
11642          }
11643 
11644          show_elog_new(NULL, FALSE, str, "../../EL/");
11645          return;
11646       }
11647    }
11648 
11649    if (equal_ustring(getparam("cmd"), "Export")) {
11650       export_hist(path, scale, offset, index, labels);
11651       return;
11652    }
11653 
11654    if (strstr(path, ".gif")) {
11655       if (equal_ustring(pmag, "Large"))
11656          generate_hist_graph(path, buffer, buffer_size, 1024, 768, scale, offset, index,
11657                              labels, bgcolor, fgcolor, gridcolor);
11658       else if (equal_ustring(pmag, "Small"))
11659          generate_hist_graph(path, buffer, buffer_size, 320, 200, scale, offset, index,
11660                              labels, bgcolor, fgcolor, gridcolor);
11661       else if (atoi(pmag) > 0)
11662          generate_hist_graph(path, buffer, buffer_size, atoi(pmag),
11663                              (int) (atoi(pmag) * 0.625), scale, offset, index, labels,
11664                              bgcolor, fgcolor, gridcolor);
11665       else
11666          generate_hist_graph(path, buffer, buffer_size, 640, 400, scale, offset, index,
11667                              labels, bgcolor, fgcolor, gridcolor);
11668 
11669       return;
11670    }
11671 
11672    if (history_mode && index < 0)
11673       return;
11674 
11675    /* evaluate offset shift */
11676    if (equal_ustring(getparam("shift"), "<"))
11677       offset -= scale / 2;
11678 
11679    if (equal_ustring(getparam("shift"), ">")) {
11680       offset += scale / 2;
11681       if (offset > 0)
11682          offset = 0;
11683    }
11684    if (equal_ustring(getparam("shift"), ">>"))
11685       offset = 0;
11686 
11687    if (equal_ustring(getparam("shift"), " + ")) {
11688       offset -= scale / 4;
11689       scale /= 2;
11690    }
11691 
11692    if (equal_ustring(getparam("shift"), " - ")) {
11693       offset += scale / 2;
11694       if (offset > 0)
11695          offset = 0;
11696       scale *= 2;
11697    }
11698 
11699    strlcpy(str, path, sizeof(str));
11700    if (strrchr(str, '/'))
11701       strlcpy(str, strrchr(str, '/')+1, sizeof(str));
11702    show_header(hDB, "History", "GET", str, 1, offset == 0 ? refresh : 0);
11703 
11704    /* menu buttons */
11705    rsprintf("<tr><td colspan=2 bgcolor=\"#C0C0C0\">\n");
11706    rsprintf("<input type=submit name=cmd value=ODB>\n");
11707    rsprintf("<input type=submit name=cmd value=Alarms>\n");
11708    rsprintf("<input type=submit name=cmd value=Status>\n");
11709    rsprintf("<input type=submit name=cmd value=History>\n");
11710 
11711    /* check if panel exists */
11712    sprintf(str, "/History/Display/%s", path);
11713    status = db_find_key(hDB, 0, str, &hkey);
11714    if (status != DB_SUCCESS && !equal_ustring(path, "All") && !equal_ustring(path,"")) {
11715       rsprintf("<h1>Error: History panel \"%s\" does not exist</h1>\n", path);
11716       rsprintf("</table></form></body></html>\r\n");
11717       return;
11718    }
11719 
11720    /* define hidden field for parameters */
11721    if (pscale && *pscale)
11722       rsprintf("<input type=hidden name=hscale value=%d>\n", scale);
11723    else {
11724       /* if no scale and offset given, get it from default */
11725       if (path[0] && !equal_ustring(path, "All") && strchr(path, '/') != NULL) {
11726          sprintf(str, "/History/Display/%s/Timescale", path);
11727 
11728          strcpy(scalestr, "1h");
11729          size = NAME_LENGTH;
11730          status = db_get_value(hDB, 0, str, scalestr, &size, TID_STRING, TRUE);
11731          if (status != DB_SUCCESS) {
11732             /* delete old integer key */
11733             db_find_key(hDB, 0, str, &hkey);
11734             if (hkey)
11735                db_delete_key(hDB, hkey, FALSE);
11736 
11737             strcpy(scalestr, "1h");
11738             size = NAME_LENGTH;
11739             db_get_value(hDB, 0, str, scalestr, &size, TID_STRING, TRUE);
11740          }
11741 
11742          rsprintf("<input type=hidden name=hscale value=%s>\n", scalestr);
11743          scale = time_to_sec(scalestr);
11744       }
11745    }
11746 
11747    if (offset != 0)
11748       rsprintf("<input type=hidden name=hoffset value=%d>\n", offset);
11749    if (pmag && *pmag)
11750       rsprintf("<input type=hidden name=hwidth value=%s>\n", pmag);
11751    if (pindex && *pindex)
11752       rsprintf("<input type=hidden name=hindex value=%s>\n", pindex);
11753 
11754    rsprintf("</td></tr>\n");
11755 
11756    if (path[0] == 0) {
11757       /* show big selection page */
11758 
11759       /* links for history panels */
11760       rsprintf("<tr><td colspan=2 bgcolor=\"#FFFFA0\">\n");
11761       if (!path[0])
11762          rsprintf("<b>Please select panel:</b><br>\n");
11763 
11764       /* table for panel selection */
11765       rsprintf("<table border=1 cellpadding=3 style='text-align: left;'>");
11766 
11767       /* "All" link */
11768       rsprintf("<tr><td colspan=2>\n");
11769       if (equal_ustring(path, "All"))
11770          rsprintf("<b>All</b> &nbsp;&nbsp;");
11771       else
11772          rsprintf("<a href=\"%sAll\">ALL</a>\n", back_path);
11773       rsprintf("</td></tr>\n");
11774 
11775       /* Setup History table links */
11776       db_find_key(hDB, 0, "/History/Display", &hkey);
11777       if (!hkey) {
11778          /* create default panel */
11779          strcpy(str, "System:Trigger per sec.");
11780          strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11781          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables",
11782                       str, NAME_LENGTH * 4, 2, TID_STRING);
11783          strcpy(str, "1h");
11784          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale",
11785                       str, NAME_LENGTH, 1, TID_STRING);
11786 
11787          factor[0] = 1;
11788          factor[1] = 1;
11789          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Factor",
11790                       factor, 2 * sizeof(float), 2, TID_FLOAT);
11791          factor[0] = 0;
11792          factor[1] = 0;
11793          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Offset",
11794                       factor, 2 * sizeof(float), 2, TID_FLOAT);
11795          strcpy(str, "1h");
11796          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale",
11797                       str, NAME_LENGTH, 1, TID_STRING);
11798          i = 1;
11799          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i,
11800                       sizeof(BOOL), 1, TID_BOOL);
11801          i = 1;
11802          db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers",
11803                       &i, sizeof(BOOL), 1, TID_BOOL);
11804       }
11805 
11806       db_find_key(hDB, 0, "/History/Display", &hkey);
11807       if (hkey) {
11808          for (i = 0;; i++) {
11809             db_enum_link(hDB, hkey, i, &hkeyp);
11810 
11811             if (!hkeyp)
11812                break;
11813 
11814             // Group key
11815             db_get_key(hDB, hkeyp, &key);
11816 
11817             if (strchr(path, '/'))
11818                strlcpy(str, strchr(path, '/') + 1, sizeof(str));
11819             else
11820                strlcpy(str, path, sizeof(str));
11821 
11822             if (equal_ustring(str, key.name))
11823                rsprintf("<tr><td><b>%s</b></td>\n<td>", key.name);
11824             else
11825                rsprintf("<tr><td><b><a href=\"%s%s\">%s</a></b></td>\n<td>",
11826                          back_path, key.name, key.name);
11827 
11828             for (j = 0;; j++) {
11829                // scan items 
11830                db_enum_link(hDB, hkeyp, j, &hikeyp);
11831 
11832                if (!hikeyp) {
11833                   rsprintf("</tr>");
11834                   break;
11835                }
11836                // Item key
11837                db_get_key(hDB, hikeyp, &ikey);
11838 
11839                if (strchr(path, '/'))
11840                   strlcpy(str, strchr(path, '/') + 1, sizeof(str));
11841                else
11842                   strlcpy(str, path, sizeof(str));
11843 
11844                if (equal_ustring(str, ikey.name))
11845                   rsprintf("<small><b>%s</b></small> &nbsp;", ikey.name);
11846                else
11847                   rsprintf("<small><a href=\"%s%s/%s\">%s</a></small> &nbsp;\n",
11848                               back_path, key.name, ikey.name, ikey.name);
11849             }
11850          }
11851       }
11852 
11853       /* "New" button */
11854       rsprintf("<tr><td colspan=2><input type=submit name=cmd value=New></td></tr>\n");
11855       rsprintf("</table></tr>\n");
11856 
11857    } else {
11858       int found = 0;
11859 
11860       /* show drop-down selectors */
11861       rsprintf("<tr><td colspan=2 bgcolor=\"#FFFFA0\">\n");
11862 
11863       rsprintf("Group:\n");
11864 
11865       rsprintf("<select title=\"Select group\" name=\"fgroup\" onChange=\"document.form1.submit()\">\n");
11866 
11867       db_find_key(hDB, 0, "/History/Display", &hkey);
11868       if (hkey) {
11869          hkeyp = 0;
11870          for (i = 0;; i++) {
11871             db_enum_link(hDB, hkey, i, &hikeyp);
11872 
11873             if (!hikeyp)
11874                break;
11875 
11876             if (i == 0)
11877                hkeyp = hikeyp;
11878 
11879             // Group key
11880             db_get_key(hDB, hikeyp, &key);
11881 
11882             if (strchr(path, '/')) {
11883                strlcpy(panel, strchr(path, '/') + 1, sizeof(panel));
11884                strlcpy(hgroup, path, sizeof(hgroup));
11885                *strchr(hgroup, '/') = 0;
11886             } else {
11887                strlcpy(hgroup, path, sizeof(str));
11888                panel[0] = 0;
11889             }
11890 
11891             if (equal_ustring(key.name, hgroup)) {
11892                rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11893                hkeyp = hikeyp;
11894             } else
11895                rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11896          }
11897 
11898          rsprintf("</select>\n");
11899          rsprintf("&nbsp;&nbsp;Panel:\n");
11900          rsprintf("<select title=\"Select panel\" name=\"fpanel\" onChange=\"document.form1.submit()\">\n");
11901 
11902          found = 0;
11903          if (hkeyp) {
11904             for (i = 0;; i++) {
11905                // scan panels
11906                db_enum_link(hDB, hkeyp, i, &hikeyp);
11907 
11908                if (!hikeyp)
11909                   break;
11910 
11911                // Item key
11912                db_get_key(hDB, hikeyp, &key);
11913 
11914                if (strchr(path, '/'))
11915                   strlcpy(str, strchr(path, '/') + 1, sizeof(str));
11916                else
11917                   strlcpy(str, path, sizeof(str));
11918 
11919                if (equal_ustring(str, key.name)) {
11920                   rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11921                   found = 1;
11922                } else
11923                   rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11924             }
11925          }
11926 
11927          if (found) 
11928             rsprintf("<option value=\"\">- all -\n");
11929          else
11930             rsprintf("<option selected value=\"\">- all -\n");
11931 
11932          rsprintf("</select>\n");
11933       }
11934 
11935       rsprintf("<noscript>\n");
11936       rsprintf("<input type=submit value=\"Go\">\n");
11937       rsprintf("</noscript>\n");
11938 
11939       rsprintf("&nbsp;&nbsp;<input type=\"button\" name=\"New\" value=\"New\" ");
11940 
11941       if (found)
11942          rsprintf("onClick=\"window.location.href='../?cmd=New'\">\n");
11943       else
11944          rsprintf("onClick=\"window.location.href='?cmd=New'\">\n");
11945 
11946       rsprintf("</td></tr>\n");
11947    }
11948 
11949 
11950    /* check if whole group should be displayed */
11951    if (path[0] && !equal_ustring(path, "ALL") && strchr(path, '/') == NULL) {
11952       sprintf(str, "/History/Display/%s", path);
11953       db_find_key(hDB, 0, str, &hkey);
11954       if (hkey) {
11955          for (i = 0 ;; i++) {     // scan group
11956             db_enum_link(hDB, hkey, i, &hikeyp);
11957 
11958             if (!hikeyp)
11959                break;
11960 
11961             db_get_key(hDB, hikeyp, &key);
11962             sprintf(ref, "%s%s/%s.gif?width=Small", hurl, path, key.name);
11963             sprintf(ref2, "%s/%s", path, key.name);
11964 
11965             if (i % 2 == 0)
11966                rsprintf("<tr><td><a href=\"%s%s\"><img src=\"%s\" alt=\"%s.gif\"></a>\n",
11967                         back_path, ref2, ref, key.name);
11968             else
11969                rsprintf("<td><a href=\"%s%s\"><img src=\"%s\" alt=\"%s.gif\"></a></tr>\n",
11970                         back_path, ref2, ref, key.name);
11971          }
11972 
11973       } else {
11974          rsprintf("Group \"%s\" not found", path);
11975       }
11976    }
11977 
11978    /* image panel */
11979    else if (path[0] && !equal_ustring(path, "All")) {
11980       /* navigation links */
11981       rsprintf("<tr><td bgcolor=\"#A0FFA0\">\n");
11982 
11983       sprintf(str, "/History/Display/%s/Buttons", path);
11984       db_find_key(hDB, 0, str, &hkeybutton);
11985       if (hkeybutton == 0) {
11986          /* create default buttons */
11987          db_create_key(hDB, 0, str, TID_STRING);
11988          db_find_key(hDB, 0, str, &hkeybutton);
11989          assert(hkeybutton);
11990          db_set_data(hDB, hkeybutton, def_button, sizeof(def_button), 7, TID_STRING);
11991       }
11992 
11993       db_get_key(hDB, hkeybutton, &key);
11994 
11995       for (i = 0; i < key.num_values; i++) {
11996          size = sizeof(str);
11997          db_get_data_index(hDB, hkeybutton, str, &size, i, TID_STRING);
11998          rsprintf("<input type=submit name=scale value=%s>\n", str);
11999       }
12000 
12001       rsprintf("<input type=submit name=shift value=\"<\">\n");
12002       rsprintf("<input type=submit name=shift value=\" + \">\n");
12003       rsprintf("<input type=submit name=shift value=\" - \">\n");
12004       if (offset != 0) {
12005          rsprintf("<input type=submit name=shift value=\">\">\n");
12006          rsprintf("<input type=submit name=shift value=\">>\">\n");
12007       }
12008 
12009       rsprintf("<td bgcolor=\"#A0FFA0\">\n");
12010       rsprintf("<input type=submit name=width value=Large>\n");
12011       rsprintf("<input type=submit name=width value=Small>\n");
12012       rsprintf("<input type=submit name=cmd value=\"Create ELog\">\n");
12013       rsprintf("<input type=submit name=cmd value=Config>\n");
12014       rsprintf("<input type=submit name=cmd value=Export>\n");
12015       rsprintf("<input type=submit name=cmd value=Query>\n");
12016 
12017       rsprintf("</tr>\n");
12018 
12019       paramstr[0] = 0;
12020       sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12021       if (offset != 0)
12022          sprintf(paramstr + strlen(paramstr), "&offset=%d", offset);
12023       if (pmag && *pmag)
12024          sprintf(paramstr + strlen(paramstr), "&width=%s", pmag);
12025 
12026       /* define image map */
12027       rsprintf("<map name=\"%s\">\r\n", path);
12028 
12029       if (!(pindex && *pindex)) {
12030          sprintf(str, "/History/Display/%s/Variables", path);
12031          db_find_key(hDB, 0, str, &hkey);
12032          if (hkey) {
12033             db_get_key(hDB, hkey, &key);
12034 
12035             for (i = 0; i < key.num_values; i++) {
12036                if (paramstr[0])
12037                   sprintf(ref, "%s?%s&index=%d", path, paramstr, i);
12038                else
12039                   sprintf(ref, "%s?index=%d", path, i);
12040 
12041                rsprintf("  <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s%s\">\r\n",
12042                         30, 31 + 23 * i, 150, 30 + 23 * i + 17, back_path, ref);
12043             }
12044          }
12045       } else {
12046          if (paramstr[0])
12047             sprintf(ref, "%s?%s", path, paramstr);
12048          else
12049             sprintf(ref, "%s", path);
12050 
12051          if (equal_ustring(pmag, "Large"))
12052             width = 1024;
12053          else if (equal_ustring(pmag, "Small"))
12054             width = 320;
12055          else if (atoi(pmag) > 0)
12056             width = atoi(pmag);
12057          else
12058             width = 640;
12059 
12060          rsprintf("  <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s%s\">\r\n", 0, 0,
12061                   width, 20, back_path, ref);
12062       }
12063 
12064       rsprintf("</map>\r\n");
12065 
12066       /* Display individual panels */
12067       if (pindex && *pindex)
12068          sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12069       if (paramstr[0])
12070          sprintf(ref, "%s%s.gif?%s", hurl, path, paramstr);
12071       else
12072          sprintf(ref, "%s%s.gif", hurl, path);
12073 
12074       /* put reference to graph */
12075       rsprintf("<tr><td colspan=2><img src=\"%s\" alt=\"%s.gif\" usemap=\"#%s\"></tr>\n",
12076                ref, path, path);
12077    }
12078 
12079    else if (equal_ustring(path, "All")) {
12080       /* Display all panels */
12081       db_find_key(hDB, 0, "/History/Display", &hkey);
12082       if (hkey)
12083          for (i = 0, k = 0;; i++) {     // scan Groups
12084             db_enum_link(hDB, hkey, i, &hkeyp);
12085 
12086             if (!hkeyp)
12087                break;
12088 
12089             db_get_key(hDB, hkeyp, &key);
12090 
12091             for (j = 0;; j++, k++) {
12092                // scan items 
12093                db_enum_link(hDB, hkeyp, j, &hikeyp);
12094 
12095                if (!hikeyp)
12096                   break;
12097 
12098                db_get_key(hDB, hikeyp, &ikey);
12099                sprintf(ref, "%s%s/%s.gif?width=Small", hurl, key.name, ikey.name);
12100                sprintf(ref2, "%s/%s", key.name, ikey.name);
12101 
12102                if (k % 2 == 0)
12103                   rsprintf("<tr><td><a href=\"%s%s\"><img src=\"%s\" alt=\"%s.gif\"></a>\n",
12104                            back_path, ref2, ref, key.name);
12105                else
12106                   rsprintf("<td><a href=\"%s%s\"><img src=\"%s\" alt=\"%s.gif\"></a></tr>\n",
12107                        back_path, ref2, ref, key.name);
12108             }                   // items loop
12109          }                      // Groups loop
12110    }                            // All
12111    rsprintf("</table>\r\n");
12112    rsprintf("</form></body></html>\r\n");
12113 }
12114 
12115 
12116 /*------------------------------------------------------------------*/
12117 
12118 void get_password(char *password)
12119 {
12120    static char last_password[32];
12121 
12122    if (strncmp(password, "set=", 4) == 0)
12123       strlcpy(last_password, password + 4, sizeof(last_password));
12124    else
12125       strcpy(password, last_password);  // unsafe: do not know size of password string, has to be this way because of cm_connect_experiment() KO 27-Jul-2006
12126 }
12127 
12128 /*------------------------------------------------------------------*/
12129 
12130 void send_icon(const char *icon)
12131 {
12132    int length;
12133    const unsigned char *picon;
12134    char str[256], format[256];
12135    time_t now;
12136    struct tm *gmt;
12137 
12138    if (strstr(icon, "favicon.ico") != 0) {
12139       length = sizeof(favicon_ico);
12140       picon = favicon_ico;
12141    } else if (strstr(icon, "favicon.png") != 0) {
12142       length = sizeof(favicon_png);
12143       picon = favicon_png;
12144    } else if (strstr(icon, "reload.png") != 0){
12145       length = sizeof(reload_png);
12146       picon = reload_png;
12147    } else
12148       return;
12149 
12150    rsprintf("HTTP/1.1 200 Document follows\r\n");
12151    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
12152    rsprintf("Accept-Ranges: bytes\r\n");
12153 
12154    /* set expiration time to one day */
12155    time(&now);
12156    now += (int) (3600 * 24);
12157    gmt = gmtime(&now);
12158    strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12159    strftime(str, sizeof(str), format, gmt);
12160    rsprintf("Expires: %s\r\n", str);
12161 
12162    if (equal_ustring(icon, "favicon.ico"))
12163       rsprintf("Content-Type: image/x-icon\r\n");
12164    else
12165       rsprintf("Content-Type: image/png\r\n");
12166 
12167    rsprintf("Content-Length: %d\r\n\r\n", length);
12168 
12169    return_length = strlen(return_buffer) + length;
12170    memcpy(return_buffer + strlen(return_buffer), picon, length);
12171 }
12172 
12173 /*------------------------------------------------------------------*/
12174 
12175 char mhttpd_css[] = "body {\
12176   margin:3px;\
12177   color:black;\
12178   background-color:white;\
12179   font-family:verdana,tahoma,sans-serif;\
12180 }\
12181 \
12182 /* standard link colors and decorations */\
12183 a:link { color:#0000FF; text-decoration:none }\
12184 a:visited { color:#800080; text-decoration:none }\
12185 a:hover { color:#0000FF; text-decoration:underline }\
12186 a:active { color:#0000FF; text-decoration:underline }\
12187 a:focus { color:#0000FF; text-decoration:underline }\
12188 ";
12189 
12190 
12191 void send_css()
12192 {
12193    int length;
12194    char str[256], format[256];
12195    time_t now;
12196    struct tm *gmt;
12197 
12198    rsprintf("HTTP/1.1 200 Document follows\r\n");
12199    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
12200    rsprintf("Accept-Ranges: bytes\r\n");
12201 
12202    /* set expiration time to one day */
12203    time(&now);
12204    now += (int) (3600 * 24);
12205    gmt = gmtime(&now);
12206    strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12207    strftime(str, sizeof(str), format, gmt);
12208    rsprintf("Expires: %s\r\n", str);
12209    rsprintf("Content-Type: text/css\r\n");
12210 
12211    length = strlen(mhttpd_css);
12212    rsprintf("Content-Length: %d\r\n\r\n", length);
12213 
12214    return_length = strlen(return_buffer) + length;
12215    memcpy(return_buffer + strlen(return_buffer), mhttpd_css, length);
12216 }
12217 
12218 /*------------------------------------------------------------------*/
12219 
12220 const char *mhttpd_js = 
12221 "\n"
12222 "document.onmousemove = getMouseXY;\n"
12223 "\n"
12224 "function getMouseXY(e)\n"
12225 "{\n"
12226 "   try {\n"
12227 "      var x = e.pageX;\n"
12228 "      var y = e.pageY;\n"
12229 "      var p = 'abs: ' + x + '/' + y;\n"
12230 "      i = document.getElementById('refimg');\n"
12231 "      if (i == null)\n"
12232 "         return false;\n"
12233 "      document.body.style.cursor = 'crosshair';\n"
12234 "      x -= i.offsetLeft;\n"
12235 "      y -= i.offsetTop;\n"
12236 "      while (i = i.offsetParent) {\n"
12237 "         x -= i.offsetLeft;\n"
12238 "         y -= i.offsetTop;\n"
12239 "      }\n"
12240 "      p += '   rel: ' + x + '/' + y;\n"
12241 "      window.status = p;\n"
12242 "      return true;\n"
12243 "      }\n"
12244 "   catch (e) {\n"
12245 "      return false;\n"
12246 "   }\n"
12247 "}\n"
12248 "\n"
12249 "function XMLHttpRequestGeneric()\n"
12250 "{\n"
12251 "   var request;\n"
12252 "   try {\n"
12253 "      request = new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari\n"
12254 "   }\n"
12255 "   catch (e) {\n"
12256 "      try {\n"
12257 "         request = new ActiveXObject('Msxml2.XMLHTTP'); // Internet Explorer\n"
12258 "      }\n"
12259 "      catch (e) {\n"
12260 "         try {\n"
12261 "            request = new ActiveXObject('Microsoft.XMLHTTP');\n"
12262 "         }\n"
12263 "         catch (e) {\n"
12264 "           alert('Your browser does not support AJAX!');\n"
12265 "           return undefined;\n"
12266 "         }\n"
12267 "      }\n"
12268 "   }\n"
12269 "\n"
12270 "   return request;\n"
12271 "}\n"
12272 "\n"
12273 "function ODBSet(path, value, pwdname)\n"
12274 "{\n"
12275 "   var value, request, url;\n"
12276 "\n"
12277 "   if (pwdname != undefined)\n"
12278 "      pwd = prompt('Please enter password', '');\n"
12279 "   else\n"
12280 "      pwd = '';\n"
12281 "\n"
12282 "   request = XMLHttpRequestGeneric();\n"
12283 "\n"
12284 "   url = '?cmd=jset&odb=' + path + '&value=' + value;\n"
12285 "\n"
12286 "   if (pwdname != undefined)\n"
12287 "      url += '&pnam=' + pwdname;\n"
12288 "\n"
12289 "   request.open('GET', url, false);\n"
12290 "\n"
12291 "   if (pwdname != undefined)\n"
12292 "      request.setRequestHeader('Cookie', 'cpwd='+pwd);\n"
12293 "\n"
12294 "   request.send(null);\n"
12295 "\n"
12296 "   if (request.status != 200 || request.responseText != 'OK') \n"
12297 "      alert('ODBSet error:\\nPath: '+path+'\\nHTTP Status: '+request.status+'\\nMessage: '+request.responseText+'\\n'+document.location) ;\n"
12298 "}\n"
12299 "\n"
12300 "function ODBGet(path, format, defval, len, type)\n"
12301 "{\n"
12302 "   request = XMLHttpRequestGeneric();\n"
12303 "\n"
12304 "   var url = '?cmd=jget&odb=' + path;\n"
12305 "   if (format != undefined && format != '')\n"
12306 "      url += '&format=' + format;\n"
12307 "   request.open('GET', url, false);\n"
12308 "   request.send(null);\n"
12309 "\n"
12310 "   if (path.match(/[*]/)) {\n"
12311 "      if (request.responseText == null)\n"
12312 "         return null;\n"
12313 "      if (request.responseText == '<DB_NO_KEY>') {\n"
12314 "         url = '?cmd=jset&odb=' + path + '&value=' + defval + '&len=' + len + '&type=' + type;\n"
12315 "\n"
12316 "         request.open('GET', url, false);\n"
12317 "         request.send(null);\n"
12318 "         return defval;\n"
12319 "      } else {\n"
12320 "         var array = request.responseText.split('\\n');\n"
12321 "         return array;\n"
12322 "      }\n"
12323 "   } else {\n"
12324 "      if ((request.responseText == '<DB_NO_KEY>' ||\n"
12325 "           request.responseText == '<DB_OUT_OF_RANGE>') && defval != undefined) {\n"
12326 "         url = '?cmd=jset&odb=' + path + '&value=' + defval + '&len=' + len + '&type=' + type;\n"
12327 "\n"
12328 "         request.open('GET', url, false);\n"
12329 "         request.send(null);\n"
12330 "         return defval;\n"
12331 "      }\n"
12332 "      return request.responseText;\n"
12333 "   }\n"
12334 "}\n"
12335 "\n"
12336 "function ODBKey(path)\n"
12337 "{\n"
12338 "   request = XMLHttpRequestGeneric();\n"
12339 "\n"
12340 "   var url = '?cmd=jkey&odb=' + path;\n"
12341 "   request.open('GET', url, false);\n"
12342 "   request.send(null);\n"
12343 "   if (request.responseText == null)\n"
12344 "      return null;\n"
12345 "   var key = request.responseText.split('\\n');\n"
12346 "   this.name = key[0];\n"
12347 "   this.type = key[1];\n"
12348 "   this.num_values = key[2];\n"
12349 "   this.item_size = key[3];\n"
12350 "}\n"
12351 "\n"
12352 "function ODBRpc_rev0(name, rpc, args)\n"
12353 "{\n"
12354 "   request = XMLHttpRequestGeneric();\n"
12355 "\n"
12356 "   var url = '?cmd=jrpc_rev0&name=' + name + '&rpc=' + rpc;\n"
12357 "   for (var i = 2; i < arguments.length; i++) {\n"
12358 "     url += '&arg'+(i-2)+'='+arguments[i];\n"
12359 "   };\n"
12360 "   request.open('GET', url, false);\n"
12361 "   request.send(null);\n"
12362 "   if (request.responseText == null)\n"
12363 "      return null;\n"
12364 "   this.reply = request.responseText.split('\\n');\n"
12365 "}\n"
12366 "\n"
12367 "function ODBGetMsg(n)\n"
12368 "{\n"
12369 "   request = XMLHttpRequestGeneric();\n"
12370 "\n"
12371 "   var url = '?cmd=jmsg&n=' + n;\n"
12372 "   request.open('GET', url, false);\n"
12373 "   request.send(null);\n"
12374 "\n"
12375 "   if (n > 1) {\n"
12376 "      var array = request.responseText.split('\\n');\n"
12377 "      return array;\n"
12378 "   } else\n"
12379 "      return request.responseText;\n"
12380 "}\n"
12381 "\n"
12382 "function ODBEdit(path)\n"
12383 "{\n"
12384 "   var value = ODBGet(path);\n"
12385 "   var new_value = prompt('Please enter new value', value);\n"
12386 "   if (new_value != undefined) {\n"
12387 "      ODBSet(path, new_value);\n"
12388 "      window.location.reload();\n"
12389 "   }\n"
12390 "}\n"
12391 "";
12392 
12393 void send_js()
12394 {
12395    int i, length;
12396    char str[256], format[256], *buf;
12397    time_t now;
12398    struct tm *gmt;
12399 
12400    rsprintf("HTTP/1.1 200 Document follows\r\n");
12401    rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
12402    rsprintf("Accept-Ranges: bytes\r\n");
12403 
12404    /* set expiration time to one day */
12405    time(&now);
12406    now += (int) (3600 * 24);
12407    gmt = gmtime(&now);
12408    strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12409    strftime(str, sizeof(str), format, gmt);
12410    rsprintf("Expires: %s\r\n", str);
12411    rsprintf("Content-Type: text/javascript\r\n");
12412 
12413    buf = (char*)malloc(strlen(mhttpd_js)+10000);
12414    strcpy(buf, mhttpd_js);
12415    strcat(buf, "\n/* MIDAS type definitions */\n");
12416    for (i=1 ; i<TID_LAST ; i++) {
12417       sprintf(str, "var TID_%s = %d;\n", rpc_tid_name(i), i);
12418       strcat(buf, str);
12419    }
12420 
12421    length = strlen(buf);
12422    rsprintf("Content-Length: %d\r\n\r\n", length);
12423 
12424    return_length = strlen(return_buffer) + length;
12425    memcpy(return_buffer + strlen(return_buffer), buf, length);
12426 
12427    free(buf);
12428 }
12429 
12430 /*------------------------------------------------------------------*/
12431 
12432 void interprete(const char *cookie_pwd, const char *cookie_wpwd, const char *cookie_cpwd, const char *path, int refresh)
12433 /********************************************************************\
12434 
12435   Routine: interprete
12436 
12437   Purpose: Interprete parametersand generate HTML output from odb.
12438 
12439   Input:
12440     char *cookie_pwd        Cookie containing encrypted password
12441     char *path              ODB path "/dir/subdir/key"
12442 
12443   <implicit>
12444     _param/_value array accessible via getparam()
12445 
12446 \********************************************************************/
12447 {
12448    int i, j, n, status, size, run_state, index;
12449    WORD event_id;
12450    HNDLE hkey, hsubkey, hDB, hconn;
12451    KEY key;
12452    char *p, str[256];
12453    char enc_path[256], dec_path[256], eq_name[NAME_LENGTH], fe_name[NAME_LENGTH];
12454    char data[TEXT_SIZE];
12455    time_t now;
12456    struct tm *gmt;
12457 
12458    if (strstr(path, "favicon.ico") != 0 || 
12459        strstr(path, "favicon.png") != 0 ||
12460        strstr(path, "reload.png")) {
12461       send_icon(path);
12462       return;
12463    }
12464 
12465    if (strstr(path, "mhttpd.css")) {
12466       send_css();
12467       return;
12468    }
12469 
12470    if (strstr(path, "mhttpd.js")) {
12471       send_js();
12472       return;
12473    }
12474 
12475    /* encode path for further usage */
12476    strlcpy(dec_path, path, sizeof(dec_path));
12477    urlDecode(dec_path);
12478    // ##urlDecode(dec_path); /* necessary for %2520 -> %20 -> ' ' */
12479    strlcpy(enc_path, dec_path, sizeof(enc_path));
12480    urlEncode(enc_path, sizeof(enc_path));
12481 
12482    const char* experiment = getparam("exp");
12483    const char* password = getparam("pwd");
12484    const char* wpassword = getparam("wpwd");
12485    const char* command = getparam("cmd");
12486    const char* value = getparam("value");
12487    const char* group = getparam("group");
12488    index = atoi(getparam("index"));
12489 
12490    cm_get_experiment_database(&hDB, NULL);
12491 
12492    if (history_mode) {
12493       if (strncmp(path, "HS/", 3) == 0) {
12494          if (equal_ustring(command, "config")) {
12495             return;
12496          }
12497 
12498          show_hist_page(dec_path + 3, sizeof(dec_path) - 3, NULL, NULL, refresh);
12499          return;
12500       }
12501       
12502       return;
12503    }
12504 
12505    /* check for password */
12506    db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12507    if (!password[0] && hkey) {
12508       size = sizeof(str);
12509       db_get_data(hDB, hkey, str, &size, TID_STRING);
12510 
12511       /* check for excemption */
12512       db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12513       if (hkey == 0 && strcmp(cookie_pwd, str) != 0) {
12514          show_password_page("", experiment);
12515          return;
12516       }
12517    }
12518 
12519    /* get run state */
12520    run_state = STATE_STOPPED;
12521    size = sizeof(run_state);
12522    db_get_value(hDB, 0, "/Runinfo/State", &run_state, &size, TID_INT, TRUE);
12523 
12524    /*---- redirect with cookie if password given --------------------*/
12525 
12526    if (password[0]) {
12527       rsprintf("HTTP/1.0 302 Found\r\n");
12528       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
12529 
12530       time(&now);
12531       now += 3600 * 24;
12532       gmt = gmtime(&now);
12533       strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", gmt);
12534 
12535       rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12536                ss_crypt(password, "mi"), str);
12537 
12538       rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12539       return;
12540    }
12541 
12542    if (wpassword[0]) {
12543       /* check if password correct */
12544       if (!check_web_password(ss_crypt(wpassword, "mi"), getparam("redir"), experiment))
12545          return;
12546 
12547       rsprintf("HTTP/1.0 302 Found\r\n");
12548       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
12549 
12550       time(&now);
12551       now += 3600 * 24;
12552       gmt = gmtime(&now);
12553       strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", gmt);
12554 
12555       rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n",
12556                ss_crypt(wpassword, "mi"), str);
12557 
12558       sprintf(str, "./%s", getparam("redir"));
12559       rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12560       return;
12561    }
12562 
12563    /*---- redirect if ODB command -----------------------------------*/
12564 
12565    if (equal_ustring(command, "ODB")) {
12566       str[0] = 0;
12567       for (p=dec_path ; *p ; p++)
12568          if (*p == '/')
12569             strlcat(str, "../", sizeof(str));
12570       strlcat(str, "root", sizeof(str));
12571       redirect(str);
12572       return;
12573    }
12574 
12575    /*---- redirect if SC command ------------------------------------*/
12576 
12577    if (equal_ustring(command, "SC")) {
12578       redirect("SC/");
12579       return;
12580    }
12581 
12582    /*---- redirect if status command --------------------------------*/
12583 
12584    if (equal_ustring(command, "status")) {
12585       str[0] = 0;
12586       for (p=dec_path ; *p ; p++)
12587          if (*p == '/')
12588             strlcat(str, "../", sizeof(str));
12589       redirect(str);
12590       return;
12591    }
12592 
12593    /*---- script command --------------------------------------------*/
12594 
12595    if (getparam("script") && *getparam("script")) {
12596       sprintf(str, "%s?script=%s", path, getparam("script"));
12597       if (!check_web_password(cookie_wpwd, str, experiment))
12598          return;
12599 
12600       sprintf(str, "/Script/%s", getparam("script"));
12601 
12602       db_find_key(hDB, 0, str, &hkey);
12603 
12604       if (hkey) {
12605          /* for NT: close reply socket before starting subprocess */
12606          if (isparam("redir"))
12607            redirect2(getparam("redir"));
12608          else
12609            redirect2("");         
12610          exec_script(hkey);
12611       } else {
12612          if (isparam("redir"))
12613            redirect2(getparam("redir"));
12614          else
12615            redirect2("");         
12616       }
12617 
12618       return;
12619    }
12620 
12621    /*---- customscript command --------------------------------------*/
12622 
12623    if (getparam("customscript") && *getparam("customscript")) {
12624       sprintf(str, "%s?customscript=%s", path, getparam("customscript"));
12625       if (!check_web_password(cookie_wpwd, str, experiment))
12626          return;
12627 
12628       sprintf(str, "/CustomScript/%s", getparam("customscript"));
12629 
12630       db_find_key(hDB, 0, str, &hkey);
12631 
12632       if (hkey) {
12633          /* for NT: close reply socket before starting subprocess */
12634          if (isparam("redir"))
12635            redirect2(getparam("redir"));
12636          else
12637            redirect2("");         
12638          exec_script(hkey);
12639       } else {
12640          if (isparam("redir"))
12641            redirect(getparam("redir"));
12642          else
12643            redirect("");         
12644       }
12645 
12646       return;
12647    }
12648 
12649    /*---- alarms command --------------------------------------------*/
12650 
12651    if (equal_ustring(command, "alarms")) {
12652       str[0] = 0;
12653       for (p=dec_path ; *p ; p++)
12654          if (*p == '/')
12655             strlcat(str, "../", sizeof(str));
12656       if (str[0]) {
12657          strlcat(str, "./?cmd=alarms", sizeof(str));
12658          redirect(str);
12659          return;
12660       }
12661       show_alarm_page();
12662       return;
12663    }
12664 
12665    /*---- history command -------------------------------------------*/
12666 
12667    if (equal_ustring(command, "history")) {
12668       str[0] = 0;
12669       for (p=dec_path ; *p ; p++)
12670          if (*p == '/')
12671             strlcat(str, "../", sizeof(str));
12672       strlcat(str, "HS/", sizeof(str));
12673       redirect(str);
12674       return;
12675    }
12676 
12677    if (strncmp(path, "HS/", 3) == 0) {
12678       if (equal_ustring(command, "config")) {
12679          sprintf(str, "%s?cmd=%s", path, command);
12680          if (!check_web_password(cookie_wpwd, str, experiment))
12681             return;
12682       }
12683 
12684       show_hist_page(dec_path + 3, sizeof(dec_path) - 3, NULL, NULL, refresh);
12685       return;
12686    }
12687 
12688    /*---- MSCB command ----------------------------------------------*/
12689 
12690    if (equal_ustring(command, "MSCB")) {
12691       str[0] = 0;
12692       for (p=dec_path ; *p ; p++)
12693          if (*p == '/')
12694             strlcat(str, "../", sizeof(str));
12695       strlcat(str, "MS/", sizeof(str));
12696       redirect(str);
12697       return;
12698    }
12699 
12700    if (strncmp(path, "MS/", 3) == 0) {
12701       if (equal_ustring(command, "set")) {
12702          sprintf(str, "%s?cmd=%s", path, command);
12703          if (!check_web_password(cookie_wpwd, str, experiment))
12704             return;
12705       }
12706 
12707 #ifdef HAVE_MSCB
12708       show_mscb_page(dec_path + 3, refresh);
12709 #else
12710       show_error("MSCB support not compiled into this version of mhttpd");
12711 #endif
12712       return;
12713    }
12714 
12715    /*---- help command ----------------------------------------------*/
12716 
12717    if (equal_ustring(command, "help")) {
12718       show_help_page();
12719       return;
12720    }
12721 
12722    /*---- pause run -------------------------------------------*/
12723 
12724    if (equal_ustring(command, "pause")) {
12725       if (run_state != STATE_RUNNING) {
12726          show_error("Run is not running");
12727          return;
12728       }
12729 
12730       if (!check_web_password(cookie_wpwd, "?cmd=pause", experiment))
12731          return;
12732 
12733       status = cm_transition(TR_PAUSE, 0, str, sizeof(str), DETACH, FALSE);
12734       if (status != CM_SUCCESS && status != CM_DEFERRED_TRANSITION)
12735          show_error(str);
12736       else if (isparam("redir"))
12737          redirect(getparam("redir"));
12738       else
12739          redirect("");
12740 
12741       requested_old_state = run_state;
12742       if (status == SUCCESS)
12743          requested_transition = TR_PAUSE;
12744 
12745       return;
12746    }
12747 
12748    /*---- resume run ------------------------------------------*/
12749 
12750    if (equal_ustring(command, "resume")) {
12751       if (run_state != STATE_PAUSED) {
12752          show_error("Run is not paused");
12753          return;
12754       }
12755 
12756       if (!check_web_password(cookie_wpwd, "?cmd=resume", experiment))
12757          return;
12758 
12759       status = cm_transition(TR_RESUME, 0, str, sizeof(str), DETACH, FALSE);
12760       if (status != CM_SUCCESS && status != CM_DEFERRED_TRANSITION)
12761          show_error(str);
12762       else if (isparam("redir"))
12763          redirect(getparam("redir"));
12764       else
12765          redirect("");
12766 
12767       requested_old_state = run_state;
12768       if (status == SUCCESS)
12769          requested_transition = TR_RESUME;
12770 
12771       return;
12772    }
12773 
12774    /*---- start dialog --------------------------------------------*/
12775 
12776    if (equal_ustring(command, "start")) {
12777       if (run_state == STATE_RUNNING) {
12778          show_error("Run is already started");
12779          return;
12780       }
12781 
12782       if (value[0] == 0) {
12783          if (!check_web_password(cookie_wpwd, "?cmd=start", experiment))
12784             return;
12785          show_start_page();
12786       } else {
12787          /* set run parameters */
12788          db_find_key(hDB, 0, "/Experiment/Edit on start", &hkey);
12789          if (hkey) {
12790             for (i = 0, n = 0;; i++) {
12791                db_enum_key(hDB, hkey, i, &hsubkey);
12792 
12793                if (!hsubkey)
12794                   break;
12795 
12796                db_get_key(hDB, hsubkey, &key);
12797 
12798                for (j = 0; j < key.num_values; j++) {
12799                   size = key.item_size;
12800                   sprintf(str, "x%d", n++);
12801                   db_sscanf(getparam(str), data, &size, 0, key.type);
12802                   db_set_data_index(hDB, hsubkey, data, key.item_size, j, key.type);
12803                }
12804             }
12805          }
12806 
12807          i = atoi(value);
12808          if (i <= 0) {
12809             cm_msg(MERROR, "interprete", "Start run: invalid run number %d", i);
12810             sprintf(str, "Invalid run number %d", i);
12811             show_error(str);
12812             return;
12813          }
12814 
12815          status = cm_transition(TR_START, i, str, sizeof(str), DETACH, FALSE);
12816          if (status != CM_SUCCESS && status != CM_DEFERRED_TRANSITION) {
12817             show_error(str);
12818          } else {
12819 
12820             requested_old_state = run_state;
12821             requested_transition = TR_START;
12822 
12823             if (isparam("redir"))
12824                redirect(getparam("redir"));
12825             else
12826                redirect("");
12827          }
12828       }
12829       return;
12830    }
12831 
12832    /*---- stop run --------------------------------------------*/
12833 
12834    if (equal_ustring(command, "stop")) {
12835       if (run_state != STATE_RUNNING && run_state != STATE_PAUSED) {
12836          show_error("Run is not running");
12837          return;
12838       }
12839 
12840       if (!check_web_password(cookie_wpwd, "?cmd=stop", experiment))
12841          return;
12842 
12843       status = cm_transition(TR_STOP, 0, str, sizeof(str), DETACH, FALSE);
12844       if (status != CM_SUCCESS && status != CM_DEFERRED_TRANSITION)
12845          show_error(str);
12846       else if (isparam("redir"))
12847          redirect(getparam("redir"));
12848       else
12849          redirect("");
12850 
12851       requested_old_state = run_state;
12852       if (status == CM_SUCCESS)
12853          requested_transition = TR_STOP;
12854 
12855       return;
12856    }
12857 
12858    /*---- trigger equipment readout ---------------------------*/
12859 
12860    if (strncmp(command, "Trigger", 7) == 0) {
12861       sprintf(str, "?cmd=%s", command);
12862       if (!check_web_password(cookie_wpwd, str, experiment))
12863          return;
12864 
12865       /* extract equipment name */
12866       strlcpy(eq_name, command + 8, sizeof(eq_name));
12867       if (strchr(eq_name, ' '))
12868          *strchr(eq_name, ' ') = 0;
12869 
12870       /* get frontend name */
12871       sprintf(str, "/Equipment/%s/Common/Frontend name", eq_name);
12872       size = NAME_LENGTH;
12873       db_get_value(hDB, 0, str, fe_name, &size, TID_STRING, TRUE);
12874 
12875       /* and ID */
12876       sprintf(str, "/Equipment/%s/Common/Event ID", eq_name);
12877       size = sizeof(event_id);
12878       db_get_value(hDB, 0, str, &event_id, &size, TID_WORD, TRUE);
12879 
12880       if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12881          sprintf(str, "Frontend \"%s\" not running!", fe_name);
12882          show_error(str);
12883       } else {
12884          status = cm_connect_client(fe_name, &hconn);
12885          if (status != RPC_SUCCESS) {
12886             sprintf(str, "Cannot connect to frontend \"%s\" !", fe_name);
12887             show_error(str);
12888          } else {
12889             status = rpc_client_call(hconn, RPC_MANUAL_TRIG, event_id);
12890             if (status != CM_SUCCESS)
12891                show_error("Error triggering event");
12892             else
12893                redirect("");
12894 
12895             cm_disconnect_client(hconn, FALSE);
12896          }
12897       }
12898 
12899       return;
12900    }
12901 
12902    /*---- cancel command --------------------------------------------*/
12903 
12904    if (equal_ustring(command, "cancel")) {
12905 
12906       if (group[0]) {
12907          /* extract equipment name */
12908          eq_name[0] = 0;
12909          if (strncmp(enc_path, "Equipment/", 10) == 0) {
12910             strlcpy(eq_name, enc_path + 10, sizeof(eq_name));
12911             if (strchr(eq_name, '/'))
12912                *strchr(eq_name, '/') = 0;
12913          }
12914 
12915          /* back to SC display */
12916          sprintf(str, "SC/%s/%s", eq_name, group);
12917          redirect(str);
12918       } else {
12919          if (isparam("redir"))
12920             redirect(getparam("redir"));
12921          else
12922             redirect("./");
12923       }
12924 
12925       return;
12926    }
12927 
12928    /*---- set command -----------------------------------------------*/
12929 
12930    if (equal_ustring(command, "set") && strncmp(path, "SC/", 3) != 0
12931        && strncmp(path, "CS/", 3) != 0) {
12932 
12933       if (strchr(enc_path, '/'))
12934          strlcpy(str, strrchr(enc_path, '/') + 1, sizeof(str));
12935       else
12936          strlcpy(str, enc_path, sizeof(str));
12937       strlcat(str, "?cmd=set", sizeof(str));
12938       if (!check_web_password(cookie_wpwd, str, experiment))
12939          return;
12940 
12941       show_set_page(enc_path, sizeof(enc_path), dec_path, group, index, value);
12942       return;
12943    }
12944 
12945    /*---- find command ----------------------------------------------*/
12946 
12947    if (equal_ustring(command, "find")) {
12948       show_find_page(enc_path, value);
12949       return;
12950    }
12951 
12952    /*---- create command --------------------------------------------*/
12953 
12954    if (equal_ustring(command, "create")) {
12955       sprintf(str, "%s?cmd=create", enc_path);
12956       if (!check_web_password(cookie_wpwd, str, experiment))
12957          return;
12958 
12959       show_create_page(enc_path, dec_path, value, index, atoi(getparam("type")));
12960       return;
12961    }
12962 
12963    /*---- CAMAC CNAF command ----------------------------------------*/
12964 
12965    if (equal_ustring(command, "CNAF") || strncmp(path, "CNAF", 4) == 0) {
12966       if (!check_web_password(cookie_wpwd, "?cmd=CNAF", experiment))
12967          return;
12968 
12969       show_cnaf_page();
12970       return;
12971    }
12972 
12973    /*---- alarms command --------------------------------------------*/
12974 
12975    if (equal_ustring(command, "reset all alarms")) {
12976       if (!check_web_password(cookie_wpwd, "?cmd=reset%20all%20alarms", experiment))
12977          return;
12978 
12979       al_reset_alarm(NULL);
12980       redirect("./?cmd=alarms");
12981       return;
12982    }
12983 
12984    if (equal_ustring(command, "reset")) {
12985       if (!check_web_password(cookie_wpwd, "?cmd=reset%20all%20alarms", experiment))
12986          return;
12987 
12988       al_reset_alarm(dec_path);
12989       redirect("./?cmd=alarms");
12990       return;
12991    }
12992 
12993    if (equal_ustring(command, "Alarms on/off")) {
12994       redirect("Alarms/Alarm system active?cmd=set");
12995       return;
12996    }
12997 
12998    /*---- programs command ------------------------------------------*/
12999 
13000    if (equal_ustring(command, "programs")) {
13001       str[0] = 0;
13002       for (p=dec_path ; *p ; p++)
13003          if (*p == '/')
13004             strlcat(str, "../", sizeof(str));
13005       if (str[0]) {
13006          strlcat(str, "./?cmd=programs", sizeof(str));
13007          redirect(str);
13008          return;
13009       }
13010 
13011       str[0] = 0;
13012       if (*getparam("Start"))
13013          sprintf(str, "?cmd=programs&Start=%s", getparam("Start"));
13014       if (*getparam("Stop"))
13015          sprintf(str, "?cmd=programs&Stop=%s", getparam("Stop"));
13016 
13017       if (str[0])
13018          if (!check_web_password(cookie_wpwd, str, experiment))
13019             return;
13020 
13021       show_programs_page();
13022       return;
13023    }
13024 
13025    /*---- config command --------------------------------------------*/
13026 
13027    if (equal_ustring(command, "config")) {
13028       show_config_page(refresh);
13029       return;
13030    }
13031 
13032    /*---- Messages command ------------------------------------------*/
13033 
13034    if (equal_ustring(command, "messages")) {
13035       show_messages_page(refresh, 20);
13036       return;
13037    }
13038 
13039    if (strncmp(command, "More", 4) == 0 && strncmp(path, "EL/", 3) != 0) {
13040       i = atoi(command + 4);
13041       if (i == 0)
13042          i = 100;
13043       show_messages_page(0, i);
13044       return;
13045    }
13046 
13047   /*---- ELog command ----------------------------------------------*/
13048 
13049    if (equal_ustring(command, "elog")) {
13050       get_elog_url(str, sizeof(str));
13051       redirect(str);
13052       return;
13053    }
13054 
13055    if (strncmp(path, "EL/", 3) == 0) {
13056       if (equal_ustring(command, "new") || equal_ustring(command, "edit")
13057           || equal_ustring(command, "reply")) {
13058          sprintf(str, "%s?cmd=%s", path, command);
13059          if (!check_web_password(cookie_wpwd, str, experiment))
13060             return;
13061       }
13062 
13063       show_elog_page(dec_path + 3, sizeof(dec_path) - 3);
13064       return;
13065    }
13066 
13067    if (equal_ustring(command, "Create ELog from this page")) {
13068       show_elog_page(dec_path, sizeof(dec_path));
13069       return;
13070    }
13071 
13072    /*---- accept command --------------------------------------------*/
13073 
13074    if (equal_ustring(command, "accept")) {
13075       refresh = atoi(getparam("refr"));
13076 
13077       /* redirect with cookie */
13078       rsprintf("HTTP/1.0 302 Found\r\n");
13079       rsprintf("Server: MIDAS HTTP %d\r\n", mhttpd_revision());
13080       rsprintf("Content-Type: text/html; charset=iso-8859-1\r\n");
13081 
13082       time(&now);
13083       now += 3600 * 24 * 365;
13084       gmt = gmtime(&now);
13085       strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", gmt);
13086 
13087       rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
13088 
13089       rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
13090 
13091       return;
13092    }
13093 
13094    /*---- delete command --------------------------------------------*/
13095 
13096    if (equal_ustring(command, "delete")) {
13097       sprintf(str, "%s?cmd=delete", enc_path);
13098       if (!check_web_password(cookie_wpwd, str, experiment))
13099          return;
13100 
13101       show_delete_page(enc_path, dec_path, value, index);
13102       return;
13103    }
13104 
13105    /*---- slow control display --------------------------------------*/
13106 
13107    if (strncmp(path, "SC/", 3) == 0) {
13108       if (equal_ustring(command, "edit")) {
13109          sprintf(str, "%s?cmd=Edit&index=%d", path, index);
13110          if (!check_web_password(cookie_wpwd, str, experiment))
13111             return;
13112       }
13113 
13114       show_sc_page(dec_path + 3, refresh);
13115       return;
13116    }
13117 
13118    /*---- custom page -----------------------------------------------*/
13119 
13120    if (strncmp(path, "CS/", 3) == 0) {
13121       if (equal_ustring(command, "edit")) {
13122          sprintf(str, "%s?cmd=Edit&index=%d", path+3, index);
13123          if (!check_web_password(cookie_wpwd, str, experiment))
13124             return;
13125       }
13126 
13127       show_custom_page(dec_path + 3, cookie_cpwd);
13128       return;
13129    }
13130 
13131    if (db_find_key(hDB, 0, "/Custom/Status", &hkey) == DB_SUCCESS && path[0] == 0) {
13132       if (equal_ustring(command, "edit")) {
13133          sprintf(str, "%s?cmd=Edit&index=%d", path, index);
13134          if (!check_web_password(cookie_wpwd, str, experiment))
13135             return;
13136       }
13137 
13138       show_custom_page("Status", cookie_cpwd);
13139       return;
13140    }
13141 
13142    /*---- show status -----------------------------------------------*/
13143 
13144    if (path[0] == 0) {
13145       if (elog_mode) {
13146          redirect("EL/");
13147          return;
13148       }
13149 
13150       show_status_page(refresh, cookie_wpwd);
13151       return;
13152    }
13153 
13154    /*---- show ODB --------------------------------------------------*/
13155 
13156    if (path[0]) {
13157       show_odb_page(enc_path, sizeof(enc_path), dec_path);
13158       return;
13159    }
13160 }
13161 
13162 /*------------------------------------------------------------------*/
13163 
13164 void decode_get(char *string, char *cookie_pwd, char *cookie_wpwd, char *cookie_cpwd, int refresh)
13165 {
13166    char path[256];
13167    char *p, *pitem;
13168 
13169    initparam();   
13170    strlcpy(path, string + 1, sizeof(path));     /* strip leading '/' */
13171    path[255] = 0;
13172    if (strchr(path, '?'))
13173       *strchr(path, '?') = 0;
13174    setparam("path", path);
13175 
13176    if (strchr(string, '?')) {
13177       p = strchr(string, '?') + 1;
13178 
13179       /* cut trailing "/" from netscape */
13180       if (p[strlen(p) - 1] == '/')
13181          p[strlen(p) - 1] = 0;
13182 
13183       p = strtok(p, "&");
13184       while (p != NULL) {
13185          pitem = p;
13186          p = strchr(p, '=');
13187          if (p != NULL) {
13188             *p++ = 0;
13189             urlDecode(pitem);
13190             if (!equal_ustring(pitem, "format"))
13191                urlDecode(p);
13192 
13193             setparam(pitem, p);
13194 
13195             p = strtok(NULL, "&");
13196          }
13197       }
13198    }
13199 
13200    interprete(cookie_pwd, cookie_wpwd, cookie_cpwd, path, refresh);
13201 
13202    freeparam();
13203 }
13204 
13205 /*------------------------------------------------------------------*/
13206 
13207 void decode_post(char *header, char *string, char *boundary, int length,
13208                  char *cookie_pwd, char *cookie_wpwd, int refresh)
13209 {
13210    char *pinit, *p, *pitem, *ptmp, file_name[256], str[256], path[256];
13211    int n;
13212 
13213    initparam();
13214 
13215    strlcpy(path, header + 1, sizeof(path));     /* strip leading '/' */
13216    path[255] = 0;
13217    if (strchr(path, '?'))
13218       *strchr(path, '?') = 0;
13219    if (strchr(path, ' '))
13220       *strchr(path, ' ') = 0;
13221    setparam("path", path);
13222 
13223    _attachment_size[0] = _attachment_size[1] = _attachment_size[2] = 0;
13224    pinit = string;
13225 
13226    /* return if no boundary defined */
13227    if (!boundary[0])
13228       return;
13229 
13230    if (strstr(string, boundary))
13231       string = strstr(string, boundary) + strlen(boundary);
13232 
13233    do {
13234       if (strstr(string, "name=")) {
13235          pitem = strstr(string, "name=") + 5;
13236          if (*pitem == '\"')
13237             pitem++;
13238 
13239          if (strncmp(pitem, "attfile", 7) == 0) {
13240             n = pitem[7] - '1';
13241 
13242             /* evaluate file attachment */
13243             if (strstr(pitem, "filename=")) {
13244                p = strstr(pitem, "filename=") + 9;
13245                if (*p == '\"')
13246                   p++;
13247                if (strstr(p, "\r\n\r\n"))
13248                   string = strstr(p, "\r\n\r\n") + 4;
13249                else if (strstr(p, "\r\r\n\r\r\n"))
13250                   string = strstr(p, "\r\r\n\r\r\n") + 6;
13251                if (strchr(p, '\"'))
13252                   *strchr(p, '\"') = 0;
13253 
13254                /* set attachment filename */
13255                strlcpy(file_name, p, sizeof(file_name));
13256                sprintf(str, "attachment%d", n);
13257                setparam(str, file_name);
13258             } else
13259                file_name[0] = 0;
13260 
13261             /* find next boundary */
13262             ptmp = string;
13263             do {
13264                while (*ptmp != '-')
13265                   ptmp++;
13266 
13267                if ((p = strstr(ptmp, boundary)) != NULL) {
13268                   while (*p == '-')
13269                      p--;
13270                   if (*p == 10)
13271                      p--;
13272                   if (*p == 13)
13273                      p--;
13274                   p++;
13275                   break;
13276                } else
13277                   ptmp += strlen(ptmp);
13278 
13279             } while (TRUE);
13280 
13281             /* save pointer to file */
13282             if (file_name[0]) {
13283                _attachment_buffer[n] = string;
13284                _attachment_size[n] = (POINTER_T) p - (POINTER_T) string;
13285             }
13286 
13287             string = strstr(p, boundary) + strlen(boundary);
13288          } else {
13289             p = pitem;
13290             if (strstr(p, "\r\n\r\n"))
13291                p = strstr(p, "\r\n\r\n") + 4;
13292             else if (strstr(p, "\r\r\n\r\r\n"))
13293                p = strstr(p, "\r\r\n\r\r\n") + 6;
13294 
13295             if (strchr(pitem, '\"'))
13296                *strchr(pitem, '\"') = 0;
13297 
13298             if (strstr(p, boundary)) {
13299                string = strstr(p, boundary) + strlen(boundary);
13300                *strstr(p, boundary) = 0;
13301                ptmp = p + (strlen(p) - 1);
13302                while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13303                   *ptmp-- = 0;
13304             }
13305             setparam(pitem, p);
13306          }
13307 
13308          while (*string == '-' || *string == '\n' || *string == '\r')
13309             string++;
13310       }
13311 
13312    } while ((POINTER_T) string - (POINTER_T) pinit < length);
13313 
13314    interprete(cookie_pwd, cookie_wpwd, "", path, refresh);
13315 }
13316 
13317 /*------------------------------------------------------------------*/
13318 
13319 BOOL _abort = FALSE;
13320 
13321 void ctrlc_handler(int sig)
13322 {
13323    _abort = TRUE;
13324 }
13325 
13326 /*------------------------------------------------------------------*/
13327 
13328 char net_buffer[WEB_BUFFER_SIZE];
13329 
13330 void server_loop()
13331 {
13332    int status, i, refresh, n_error;
13333    struct sockaddr_in bind_addr, acc_addr;
13334    char cookie_pwd[256], cookie_wpwd[256], cookie_cpwd[256], boundary[256], *p;
13335    int lsock, flag, content_length, header_length;
13336    unsigned int len;
13337    struct hostent *local_phe = NULL;
13338    fd_set readfds;
13339    struct timeval timeout;
13340    INT last_time = 0;
13341    struct hostent *remote_phe;
13342    char hname[256];
13343    BOOL allowed;
13344 
13345    /* establish Ctrl-C handler */
13346    ss_ctrlc_handler(ctrlc_handler);
13347 
13348 #ifdef OS_WINNT
13349    {
13350       WSADATA WSAData;
13351 
13352       /* Start windows sockets */
13353       if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
13354          return;
13355    }
13356 #endif
13357 
13358    /* create a new socket */
13359    lsock = socket(AF_INET, SOCK_STREAM, 0);
13360 
13361    if (lsock == -1) {
13362       printf("Cannot create socket\n");
13363       return;
13364    }
13365 
13366    /* bind local node name and port to socket */
13367    memset(&bind_addr, 0, sizeof(bind_addr));
13368    bind_addr.sin_family = AF_INET;
13369    bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13370    bind_addr.sin_port = htons((short) tcp_port);
13371 
13372    /* try reusing address */
13373    flag = 1;
13374    setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13375    status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13376 
13377    if (status < 0) {
13378       printf
13379           ("Cannot bind to port %d.\nPlease try later or use the \"-p\" flag to specify a different port\n",
13380            tcp_port);
13381       return;
13382    }
13383 
13384    /* get host name for mail notification */
13385    gethostname(host_name, sizeof(host_name));
13386 
13387    local_phe = gethostbyname(host_name);
13388    if (local_phe != NULL)
13389       local_phe = gethostbyaddr(local_phe->h_addr, sizeof(int), AF_INET);
13390 
13391    /* if domain name is not in host name, hope to get it from phe */
13392    if (local_phe != NULL && strchr(host_name, '.') == NULL)
13393       strlcpy(host_name, local_phe->h_name, sizeof(host_name));
13394 
13395 #ifdef OS_UNIX
13396    /* give up root privilege */
13397    setuid(getuid());
13398    setgid(getgid());
13399 #endif
13400 
13401    /* listen for connection */
13402    status = listen(lsock, SOMAXCONN);
13403    if (status < 0) {
13404       printf("Cannot listen\n");
13405       return;
13406    }
13407 
13408    printf("Server listening on port %d...\n", tcp_port);
13409 
13410    do {
13411       FD_ZERO(&readfds);
13412       FD_SET(lsock, &readfds);
13413 
13414       timeout.tv_sec = 0;
13415       timeout.tv_usec = 100000;
13416 
13417 #ifdef OS_UNIX
13418       do {
13419          status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
13420          /* if an alarm signal was cought, restart with reduced timeout */
13421       } while (status == -1 && errno == EINTR);
13422 #else
13423       status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
13424 #endif
13425 
13426       if (FD_ISSET(lsock, &readfds)) {
13427 
13428          len = sizeof(acc_addr);
13429 #ifdef OS_WINNT
13430          _sock = accept(lsock, (struct sockaddr *) &acc_addr, (int *)&len);
13431 #else
13432          _sock = accept(lsock, (struct sockaddr *) &acc_addr, (socklen_t *)&len);
13433 #endif
13434 
13435          last_time = (INT) ss_time();
13436 
13437          /* save remote host address */
13438          memcpy(&remote_addr, &(acc_addr.sin_addr), sizeof(remote_addr));
13439 
13440          /* check access control list */
13441          if (n_allowed_hosts > 0) {
13442             allowed = FALSE;
13443 
13444             remote_phe = gethostbyaddr((char *) &remote_addr, 4, PF_INET);
13445 
13446             if (remote_phe == NULL) {
13447                /* use IP number instead */
13448                strlcpy(hname, (char *)inet_ntoa(remote_addr), sizeof(hname));
13449             } else
13450                strlcpy(hname, remote_phe->h_name, sizeof(hname));
13451 
13452             /* always permit localhost */
13453             if (strcmp(hname, "localhost.localdomain") == 0)
13454                allowed = TRUE;
13455             if (strcmp(hname, "localhost") == 0)
13456                allowed = TRUE;
13457 
13458             if (!allowed) {
13459                for (i=0 ; i<n_allowed_hosts ; i++)
13460                   if (strcmp(hname, allowed_host[i]) == 0) {
13461                      allowed = TRUE;
13462                      break;
13463                   }
13464             }
13465 
13466             if (!allowed) {
13467                printf("Rejecting http connection from \'%s\'\n", hname);
13468                closesocket(_sock);
13469                continue;
13470             }
13471          }
13472 
13473          /* save remote host address */
13474          memcpy(&remote_addr, &(acc_addr.sin_addr), sizeof(remote_addr));
13475          if (verbose) {
13476             struct hostent *remote_phe;
13477             char str[256];
13478 
13479             strcpy(str, ss_asctime());
13480             printf(str);
13481             printf("=== Received request from ");
13482 
13483             remote_phe = gethostbyaddr((char *) &remote_addr, 4, PF_INET);
13484             if (remote_phe == NULL) {
13485                /* use IP number instead */
13486                strlcpy(str, (char *) inet_ntoa(remote_addr), sizeof(str));
13487             } else
13488                strlcpy(str, remote_phe->h_name, sizeof(str));
13489 
13490             puts(str);
13491             printf("===========\n");
13492             fflush(stdout);
13493          }
13494 
13495          memset(net_buffer, 0, sizeof(net_buffer));
13496          len = 0;
13497          header_length = 0;
13498          content_length = 0;
13499          n_error = 0;
13500          do {
13501             FD_ZERO(&readfds);
13502             FD_SET(_sock, &readfds);
13503 
13504             timeout.tv_sec = 6;
13505             timeout.tv_usec = 0;
13506 
13507 #ifdef OS_UNIX
13508             do {
13509                status =
13510                    select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
13511                /* if an alarm signal was cought, restart with reduced timeout */
13512             } while (status == -1 && errno == EINTR);
13513 #else
13514             status = select(FD_SETSIZE, (fd_set *) &readfds, NULL, NULL, (const timeval *) &timeout);
13515 #endif
13516             if (FD_ISSET(_sock, &readfds))
13517                i = recv(_sock, net_buffer + len, sizeof(net_buffer) - len, 0);
13518             else
13519                goto error;
13520 
13521             /* abort if connection got broken */
13522             if (i < 0)
13523                goto error;
13524 
13525             if (i > 0)
13526                len += i;
13527 
13528             /* check if net_buffer too small */
13529             if (len >= sizeof(net_buffer)) {
13530                /* drain incoming remaining data */
13531                do {
13532                   FD_ZERO(&readfds);
13533                   FD_SET(_sock, &readfds);
13534 
13535                   timeout.tv_sec = 2;
13536                   timeout.tv_usec = 0;
13537 
13538                   status =
13539                       select(FD_SETSIZE, &readfds, NULL, NULL,
13540                              &timeout);
13541 
13542                   if (FD_ISSET(_sock, &readfds))
13543                      i = recv(_sock, net_buffer, sizeof(net_buffer), 0);
13544                   else
13545                      break;
13546                } while (i);
13547 
13548                memset(return_buffer, 0, sizeof(return_buffer));
13549                strlen_retbuf = 0;
13550                return_length = 0;
13551 
13552                show_error("Submitted attachment too large, please increase WEB_BUFFER_SIZE in mhttpd.c and recompile");
13553                send(_sock, return_buffer, strlen_retbuf + 1, 0);
13554                if (verbose) {
13555                   printf("==== Return error info %i bytes ==============\n",
13556                          strlen_retbuf + 1);
13557                   puts(return_buffer);
13558                   printf("\n\n");
13559                }
13560                goto error;
13561             }
13562 
13563             if (i == 0) {
13564                n_error++;
13565                if (n_error == 100)
13566                   goto error;
13567             }
13568 
13569             /* finish when empty line received */
13570             if (strstr(net_buffer, "GET") != NULL && strstr(net_buffer, "POST") == NULL) {
13571                if (len > 4 && strcmp(&net_buffer[len - 4], "\r\n\r\n") == 0)
13572                   break;
13573                if (len > 6 && strcmp(&net_buffer[len - 6], "\r\r\n\r\r\n") == 0)
13574                   break;
13575             } else if (strstr(net_buffer, "POST") != NULL) {
13576                if (header_length == 0) {
13577                   /* extract header and content length */
13578                   if (strstr(net_buffer, "Content-Length:"))
13579                      content_length = atoi(strstr(net_buffer, "Content-Length:") + 15);
13580                   else if (strstr(net_buffer, "Content-length:"))
13581                      content_length = atoi(strstr(net_buffer, "Content-length:") + 15);
13582 
13583                   boundary[0] = 0;
13584                   if (strstr(net_buffer, "boundary=")) {
13585                      strlcpy(boundary, strstr(net_buffer, "boundary=") + 9,
13586                              sizeof(boundary));
13587                      if (strchr(boundary, '\r'))
13588                         *strchr(boundary, '\r') = 0;
13589                   }
13590 
13591                   if (strstr(net_buffer, "\r\n\r\n"))
13592                      header_length =
13593                          (POINTER_T) strstr(net_buffer,
13594                                             "\r\n\r\n") - (POINTER_T) net_buffer + 4;
13595 
13596                   if (strstr(net_buffer, "\r\r\n\r\r\n"))
13597                      header_length =
13598                          (POINTER_T) strstr(net_buffer,
13599                                             "\r\r\n\r\r\n") - (POINTER_T) net_buffer + 6;
13600 
13601                   if (header_length)
13602                      net_buffer[header_length - 1] = 0;
13603                }
13604 
13605                if (header_length > 0 && (int) len >= header_length + content_length)
13606                   break;
13607             } else if (strstr(net_buffer, "OPTIONS") != NULL)
13608                goto error;
13609             else {
13610                printf(net_buffer);
13611                goto error;
13612             }
13613 
13614          } while (1);
13615 
13616          if (!strchr(net_buffer, '\r'))
13617             goto error;
13618 
13619          /* extract cookies */
13620          cookie_pwd[0] = 0;
13621          cookie_wpwd[0] = 0;
13622          if (strstr(net_buffer, "midas_pwd=") != NULL) {
13623             strlcpy(cookie_pwd, strstr(net_buffer, "midas_pwd=") + 10,
13624                     sizeof(cookie_pwd));
13625             cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
13626          }
13627          if (strstr(net_buffer, "midas_wpwd=") != NULL) {
13628             strlcpy(cookie_wpwd, strstr(net_buffer, "midas_wpwd=") + 11,
13629                     sizeof(cookie_wpwd));
13630             cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
13631          }
13632          if (strstr(net_buffer, "cpwd=") != NULL) {
13633             strlcpy(cookie_cpwd, strstr(net_buffer, "cpwd=") + 5,
13634                     sizeof(cookie_cpwd));
13635             cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
13636          }
13637 
13638          refresh = 0;
13639          if (strstr(net_buffer, "midas_refr=") != NULL)
13640             refresh = atoi(strstr(net_buffer, "midas_refr=") + 11);
13641          else
13642             refresh = DEFAULT_REFRESH;
13643 
13644          /* extract referer */
13645          referer[0] = 0;
13646          if ((p = strstr(net_buffer, "Referer:")) != NULL) {
13647             p += 9;
13648             while (*p && *p == ' ')
13649                p++;
13650             strlcpy(referer, p, sizeof(referer));
13651             if (strchr(referer, '\r'))
13652                *strchr(referer, '\r') = 0;
13653             if (strchr(referer, '?'))
13654                *strchr(referer, '?') = 0;
13655             for (p = referer + strlen(referer) - 1; p > referer && *p != '/'; p--)
13656                *p = 0;
13657          }
13658 
13659          memset(return_buffer, 0, sizeof(return_buffer));
13660          strlen_retbuf = 0;
13661 
13662          if (strncmp(net_buffer, "GET", 3) != 0 && strncmp(net_buffer, "POST", 4) != 0)
13663             goto error;
13664 
13665          return_length = 0;
13666 
13667          if (verbose) {
13668             INT temp;
13669             printf("Received buffer of %i bytes :\n%s\n", len, net_buffer);
13670             fflush(stdout);
13671             if (strncmp(net_buffer, "POST", 4) == 0) {
13672                printf("Contents of POST has %i bytes:\n", content_length);
13673                if (content_length > 2000) {
13674                   printf("--- Dumping first 2000 bytes only\n");
13675                   temp = net_buffer[header_length + 2000];
13676                   net_buffer[header_length + 2000] = 0;
13677                   puts(net_buffer + header_length);
13678                   net_buffer[header_length + 2000] = temp;
13679                } else
13680                   puts(net_buffer + header_length);
13681                printf("\n\n");
13682                fflush(stdout);
13683             }
13684          }
13685 
13686          if (strncmp(net_buffer, "GET", 3) == 0) {
13687             /* extract path and commands */
13688             *strchr(net_buffer, '\r') = 0;
13689 
13690             if (!strstr(net_buffer, "HTTP"))
13691                goto error;
13692             *(strstr(net_buffer, "HTTP") - 1) = 0;
13693 
13694             /* decode command and return answer */
13695             decode_get(net_buffer + 4, cookie_pwd, cookie_wpwd, cookie_cpwd, refresh);
13696          } else {
13697             decode_post(net_buffer + 5, net_buffer + header_length, boundary,
13698                         content_length, cookie_pwd, cookie_wpwd, refresh);
13699          }
13700 
13701          if (return_length != -1) {
13702             if (return_length == 0)
13703                return_length = strlen(return_buffer);
13704 
13705             if (verbose) {
13706                char str[256];
13707                strcpy(str, ss_asctime());
13708                printf(str);
13709                printf("==== Return buffer %i bytes ===\n", return_length);
13710                printf("\n\n");
13711             }
13712 
13713             i = send_tcp(_sock, return_buffer, return_length, 0x10000);
13714 
13715             if (verbose) {
13716                if (return_length > 1000) {
13717                   printf("--- Dumping first 1000 bytes only\n");
13718                   return_buffer[1000] = 0;
13719                }
13720                puts(return_buffer);
13721                printf("\n\n");
13722             }
13723 
13724           error:
13725 
13726             closesocket(_sock);
13727          }
13728       }
13729 
13730       /* re-establish ctrl-c handler */
13731       ss_ctrlc_handler(ctrlc_handler);
13732 
13733       /* check for shutdown message */
13734       status = cm_yield(0);
13735       if (status == RPC_SHUTDOWN)
13736          break;
13737 
13738    } while (!_abort);
13739 
13740    cm_disconnect_experiment();
13741 }
13742 
13743 /*------------------------------------------------------------------*/
13744 
13745 int main(int argc, char *argv[])
13746 {
13747    int i, status;
13748    int daemon = FALSE;
13749    char str[256];
13750    const char *myname = "mhttpd";
13751 
13752    setbuf(stdout, NULL);
13753    setbuf(stderr, NULL);
13754 #ifdef SIGPIPE
13755    /* avoid getting killed by "Broken pipe" signals */
13756    signal(SIGPIPE, SIG_IGN);
13757 #endif
13758 
13759    /* get default from environment */
13760    cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
13761 
13762    /* parse command line parameters */
13763    n_allowed_hosts = 0;
13764    for (i = 1; i < argc; i++) {
13765       if (argv[i][0] == '-' && argv[i][1] == 'D')
13766          daemon = TRUE;
13767       else if (argv[i][0] == '-' && argv[i][1] == 'v')
13768          verbose = TRUE;
13769       else if (argv[i][0] == '-' && argv[i][1] == 'E')
13770          elog_mode = TRUE;
13771       else if (argv[i][0] == '-' && argv[i][1] == 'H')
13772          history_mode = TRUE;
13773       else if (argv[i][0] == '-') {
13774          if (i + 1 >= argc || argv[i + 1][0] == '-')
13775             goto usage;
13776          if (argv[i][1] == 'p')
13777             tcp_port = atoi(argv[++i]);
13778          else if (argv[i][1] == 'h')
13779             strlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
13780          else if (argv[i][1] == 'e')
13781             strlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
13782          else if (argv[i][1] == 'a') {
13783             if (n_allowed_hosts < MAX_N_ALLOWED_HOSTS)
13784                strlcpy(allowed_host[n_allowed_hosts++], argv[++i], sizeof(allowed_host[0]));
13785          } else {
13786           usage:
13787             printf("usage: %s [-h Hostname] [-e Experiment] [-p port] [-v] [-D] [-c] [-a Hostname]\n\n", argv[0]);
13788             printf("       -h connect to midas server (mserver) on given host\n");
13789             printf("       -e experiment to connect to\n");
13790             printf("       -v display verbose HTTP communication\n");
13791             printf("       -D become a daemon\n");
13792             printf("       -E only display ELog system\n");
13793             printf("       -H only display history plots\n");
13794             printf("       -a only allow access for specific host(s), several\n");
13795             printf("          [-a Hostname] statements might be given\n");
13796             return 0;
13797          }
13798       }
13799    }
13800 
13801    if (daemon) {
13802       printf("Becoming a daemon...\n");
13803       ss_daemon_init(FALSE);
13804    }
13805 
13806    if (history_mode)
13807       myname = "mhttpd_history";
13808 
13809    /*---- connect to experiment ----*/
13810    status = cm_connect_experiment1(midas_hostname, midas_expt, myname, NULL,
13811                                    DEFAULT_ODB_SIZE, DEFAULT_WATCHDOG_TIMEOUT);
13812    if (status == CM_WRONG_PASSWORD)
13813       return 1;
13814    else if ((status == DB_INVALID_HANDLE)) {
13815       cm_get_error(status, str);
13816       puts(str);
13817    } else if (status != CM_SUCCESS) {
13818       cm_get_error(status, str);
13819       puts(str);
13820       return 1;
13821    }
13822 
13823    /* place a request for system messages */
13824    cm_msg_register(receive_message);
13825 
13826    /* redirect message display, turn on message logging */
13827    cm_set_msg_print(MT_ALL, MT_ALL, print_message);
13828 
13829    server_loop();
13830 
13831    return 0;
13832 }

Midas DOC Version 3.0.0 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk