Line data Source code
1 : /********************************************************************\
2 :
3 : Name: mhttpd.cxx
4 : Created by: Stefan Ritt
5 :
6 : Contents: Web server program for midas RPC calls
7 :
8 : \********************************************************************/
9 :
10 : #undef NDEBUG // midas required assert() to be always enabled
11 :
12 : #include <stdio.h>
13 : #include <math.h> // fabs()
14 : #include <assert.h>
15 : #include <algorithm> // std::sort()
16 : #include <thread> // std::thread
17 : #include <deque> // std::deque
18 : #include <mutex> // std::mutex
19 : #include <condition_variable> // std::condition_variable
20 : #include <atomic> // std::atomic<>
21 :
22 : #include "midas.h"
23 : #include "msystem.h"
24 : #include "mxml.h"
25 : #include "odbxx.h"
26 : #include "mstrlcpy.h"
27 :
28 : #include "mgd.h"
29 : #include "history.h"
30 :
31 : #ifdef HAVE_MSCB
32 : #include "mscb.h"
33 : #endif
34 :
35 : #include "mjsonrpc.h"
36 : #include "mvodb.h"
37 :
38 : /* refresh times in seconds */
39 : #define DEFAULT_REFRESH 60
40 :
41 : #ifdef HAVE_MONGOOSE6
42 : static MUTEX_T* request_mutex = NULL;
43 : #endif
44 :
45 : #define OBSOLETE 1 // obsolete code scheduled for removal. K.O.
46 :
47 : static std::mutex gMutex;
48 : static MVOdb* gOdb = NULL;
49 :
50 : /*------------------------------------------------------------------*/
51 :
52 : #define MAX_GROUPS 32
53 : #define MAX_VARS 100
54 :
55 : /*------------------------------------------------------------------*/
56 :
57 0 : static std::string toString(int i)
58 : {
59 : char buf[256];
60 0 : sprintf(buf, "%d", i);
61 0 : return buf;
62 : }
63 :
64 : /*------------------------------------------------------------------*/
65 :
66 : class Attachment
67 : {
68 : public:
69 : char* attachment_buffer[3];
70 : size_t attachment_size[3];
71 : public:
72 0 : Attachment() // ctor
73 0 : {
74 0 : for (int i=0; i<3; i++) {
75 0 : attachment_buffer[i] = NULL;
76 0 : attachment_size[i] = 0;
77 : }
78 0 : }
79 0 : ~Attachment() // dtor
80 : {
81 0 : for (int i=0; i<3; i++) {
82 0 : clear(i);
83 : }
84 0 : }
85 0 : void clear(int i)
86 : {
87 0 : if (attachment_size[i]) {
88 0 : attachment_size[i] = 0;
89 0 : free(attachment_buffer[i]);
90 0 : attachment_buffer[i] = NULL;
91 : }
92 0 : }
93 : };
94 : static BOOL elog_mode = FALSE;
95 : static BOOL history_mode = FALSE;
96 : static BOOL verbose = FALSE;
97 :
98 : // month name from midas.c
99 : extern const char *mname[];
100 :
101 : static const char default_type_list[20][NAME_LENGTH] = {
102 : "Routine",
103 : "Shift summary",
104 : "Minor error",
105 : "Severe error",
106 : "Fix",
107 : "Question",
108 : "Info",
109 : "Modification",
110 : "Reply",
111 : "Alarm",
112 : "Test",
113 : "Other"
114 : };
115 :
116 : static const char default_system_list[20][NAME_LENGTH] = {
117 : "General",
118 : "DAQ",
119 : "Detector",
120 : "Electronics",
121 : "Target",
122 : "Beamline"
123 : };
124 :
125 : struct MimetypeTableEntry {
126 : std::string ext;
127 : std::string mimetype;
128 : };
129 :
130 : const MimetypeTableEntry gMimetypeTable[] = {
131 : { ".ASC", "text/plain" },
132 : { ".CSS", "text/css" },
133 : { ".CSV", "text/csv" },
134 : { ".HTM", "text/html" },
135 : { ".HTML", "text/html" },
136 : { ".TXT", "text/plain" },
137 :
138 : { ".BMP", "image/bmp" },
139 : { ".GIF", "image/gif" },
140 : { ".ICO", "image/x-icon" },
141 : { ".JPEG", "image/jpeg" },
142 : { ".JPG", "image/jpeg" },
143 : { ".PNG", "image/png" },
144 : { ".SVG", "image/svg+xml" },
145 : { ".TIF", "image/tiff" },
146 : { ".TIFF", "image/tiff" },
147 :
148 : { ".MID", "audio/midi" },
149 : { ".MP3", "audio/mpeg" },
150 : { ".OGA", "audio/ogg" },
151 : { ".OGG", "audio/ogg" },
152 : { ".WAV", "audio/wav" },
153 :
154 : { ".BIN", "application/octet-stream" },
155 : { ".BZ", "application/x-bzip" },
156 : { ".BZ2", "application/x-bzip2" },
157 : { ".DOC", "application/msword" },
158 : { ".EPS", "application/postscript" },
159 : { ".GZ", "application/gzip" },
160 : { ".JS", "application/javascript" },
161 : { ".JSON", "application/json" },
162 : { ".MJS", "application/javascript" },
163 : { ".PDF", "application/pdf" },
164 : { ".PHP", "application/x-httpd-php" },
165 : { ".RTF", "application/rtf" },
166 : { ".PS", "application/postscript" },
167 : { ".ROOT", "application/octet-stream" },
168 : { ".XLS", "application/x-msexcel" },
169 : { ".XML", "application/xml" },
170 : { ".ZIP", "application/zip" },
171 :
172 : { ".ODP", "application/vnd.oasis.opendocument.presentation" },
173 : { ".ODS", "application/vnd.oasis.opendocument.spreadsheet" },
174 : { ".ODT", "application/vnd.oasis.opendocument.text" },
175 :
176 : { "", "" }
177 : };
178 :
179 : static MVOdb* gMimeTypesOdb = NULL;
180 :
181 0 : static std::string GetMimetype(const std::string& ext)
182 : {
183 0 : if (gMimeTypesOdb) {
184 0 : std::string mimetype;
185 0 : gMimeTypesOdb->RS(ext.c_str(), &mimetype);
186 0 : if (mimetype.length() > 0) {
187 : //printf("GetMimetype: %s -> %s from ODB\n", ext.c_str(), mimetype.c_str());
188 0 : return mimetype;
189 : }
190 0 : }
191 :
192 0 : for (int i=0; gMimetypeTable[i].ext[0]; i++) {
193 0 : if (ext == gMimetypeTable[i].ext) {
194 : //printf("GetMimetype: %s -> %s from built-in table\n", ext.c_str(), gMimetypeTable[i].mimetype.c_str());
195 0 : return gMimetypeTable[i].mimetype;
196 : }
197 : }
198 :
199 : //printf("GetMimetype: %s -> not found\n", ext.c_str());
200 0 : return "";
201 : }
202 :
203 0 : static void SaveMimetypes(MVOdb* odb)
204 : {
205 0 : gMimeTypesOdb = odb;
206 :
207 0 : for (int i=0; gMimetypeTable[i].ext.length() > 0; i++) {
208 0 : std::string tmp = gMimetypeTable[i].mimetype;
209 0 : gMimeTypesOdb->RS(gMimetypeTable[i].ext.c_str(), &tmp, true);
210 0 : }
211 0 : }
212 :
213 : #define HTTP_ENCODING "UTF-8"
214 :
215 : /*------------------------------------------------------------------*/
216 :
217 : const unsigned char favicon_png[] = {
218 : 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
219 : 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
220 : 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
221 : 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x91, 0x68,
222 : 0x36, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D,
223 : 0x45, 0x07, 0xD4, 0x0B, 0x1A, 0x08, 0x37, 0x07,
224 : 0x0D, 0x7F, 0x16, 0x5C, 0x00, 0x00, 0x00, 0x09,
225 : 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x2E, 0x23,
226 : 0x00, 0x00, 0x2E, 0x23, 0x01, 0x78, 0xA5, 0x3F,
227 : 0x76, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D,
228 : 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61,
229 : 0x05, 0x00, 0x00, 0x01, 0x7D, 0x49, 0x44, 0x41,
230 : 0x54, 0x78, 0xDA, 0x63, 0xFC, 0xFF, 0xFF, 0x3F,
231 : 0x03, 0x29, 0x80, 0x09, 0xAB, 0xE8, 0xD2, 0x65,
232 : 0x77, 0x36, 0x6F, 0x7E, 0x8A, 0x5D, 0xC7, 0x7F,
233 : 0x0C, 0x30, 0x67, 0xEE, 0x0D, 0x56, 0xCE, 0xCD,
234 : 0x5C, 0xBC, 0x3B, 0xB6, 0x6D, 0x7F, 0x81, 0x29,
235 : 0xCB, 0x88, 0xE6, 0x24, 0x20, 0x57, 0x50, 0x7C,
236 : 0xDD, 0xCF, 0x1F, 0x6C, 0x40, 0xCB, 0xB5, 0xB5,
237 : 0x05, 0xCF, 0x1C, 0xB7, 0x42, 0xB3, 0x80, 0x05,
238 : 0x8D, 0xCF, 0xC8, 0xC8, 0x58, 0x5A, 0x2A, 0xFB,
239 : 0xF6, 0x4D, 0x37, 0x1B, 0xAB, 0xA0, 0xB4, 0x4C,
240 : 0x0A, 0x51, 0x4E, 0x02, 0x82, 0x85, 0xCB, 0x12,
241 : 0x0E, 0x1D, 0xAB, 0xC7, 0x2A, 0xC5, 0x82, 0x69,
242 : 0xC4, 0xAF, 0x5F, 0x7F, 0x1E, 0x3F, 0xF8, 0xCD,
243 : 0xCB, 0xF1, 0xF5, 0xEF, 0xDF, 0x7F, 0xCC, 0xCC,
244 : 0x4C, 0x84, 0x6D, 0x98, 0x59, 0xD5, 0xEB, 0xCF,
245 : 0xA5, 0x16, 0xC4, 0xAB, 0x71, 0x72, 0xCB, 0x21,
246 : 0x4C, 0x59, 0x74, 0x03, 0x5E, 0x3F, 0x7F, 0xB3,
247 : 0x6B, 0xD6, 0x22, 0x46, 0xA6, 0x7F, 0x0C, 0x0C,
248 : 0x7F, 0xD7, 0x75, 0x4D, 0xFB, 0xF1, 0xFD, 0x27,
249 : 0x81, 0x78, 0xB8, 0x7D, 0xE9, 0x0A, 0xCB, 0xFF,
250 : 0xDF, 0x4C, 0x8C, 0x8C, 0x40, 0xF6, 0xAD, 0x4B,
251 : 0x67, 0x1F, 0xDE, 0xBD, 0x8B, 0x45, 0x03, 0x3C,
252 : 0x60, 0x8F, 0x9D, 0xD8, 0xB3, 0xEB, 0x74, 0xB5,
253 : 0x90, 0x26, 0x07, 0x03, 0x48, 0xE4, 0x3F, 0x8F,
254 : 0xF6, 0xFF, 0x1B, 0x0F, 0x9A, 0x1E, 0x3E, 0x3A,
255 : 0xFB, 0xF3, 0xDB, 0x8F, 0xB7, 0x0F, 0x9E, 0x43,
256 : 0x83, 0xF1, 0xCF, 0xDF, 0x3F, 0x8A, 0x29, 0xCE,
257 : 0x3F, 0x7F, 0xFD, 0xFC, 0xCF, 0xF0, 0xDF, 0x98,
258 : 0xE9, 0xB5, 0x8F, 0xBD, 0x8A, 0x3C, 0x6F, 0xEC,
259 : 0xB9, 0x2D, 0x47, 0xFE, 0xFC, 0xFF, 0x6F, 0x16,
260 : 0x6C, 0xF3, 0xEC, 0xD3, 0x1C, 0x2E, 0x96, 0xEF,
261 : 0xBF, 0xAB, 0x7E, 0x32, 0x7D, 0xE2, 0x10, 0xCE,
262 : 0x88, 0xF4, 0x69, 0x2B, 0x60, 0xFC, 0xF4, 0xF5,
263 : 0x97, 0x78, 0x8A, 0x36, 0xD8, 0x44, 0x86, 0x18,
264 : 0x0D, 0xD7, 0x29, 0x95, 0x13, 0xD8, 0xD9, 0x58,
265 : 0xE1, 0x0E, 0xF8, 0xF1, 0xF3, 0xDB, 0xC6, 0xD6,
266 : 0xEC, 0x5F, 0x53, 0x8E, 0xBF, 0xFE, 0xC3, 0x70,
267 : 0x93, 0x8D, 0x6D, 0xDA, 0xCB, 0x0B, 0x4C, 0x3F,
268 : 0xFF, 0xFC, 0xFA, 0xCF, 0x0C, 0xB4, 0x09, 0x84,
269 : 0x54, 0xD5, 0x74, 0x91, 0x55, 0x03, 0x01, 0x07,
270 : 0x3B, 0x97, 0x96, 0x6E, 0xC8, 0x17, 0xFE, 0x7F,
271 : 0x4F, 0xF8, 0xFE, 0xBC, 0x95, 0x16, 0x60, 0x62,
272 : 0x62, 0x64, 0xE1, 0xE6, 0x60, 0x73, 0xD1, 0xB2,
273 : 0x7A, 0xFA, 0xE2, 0xF1, 0xDF, 0x3F, 0xFF, 0xC4,
274 : 0x78, 0x44, 0x31, 0xA3, 0x45, 0x2B, 0xD0, 0xE3,
275 : 0xF6, 0xD9, 0xE3, 0x2F, 0x2E, 0x9D, 0x29, 0xA9,
276 : 0xAC, 0x07, 0xA6, 0x03, 0xF4, 0xB4, 0x44, 0x10,
277 : 0x00, 0x00, 0x75, 0x65, 0x12, 0xB0, 0x49, 0xFF,
278 : 0x3F, 0x68, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
279 : 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
280 : };
281 :
282 : const unsigned char favicon_ico[] = {
283 : 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10,
284 : 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x28, 0x01,
285 : 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
286 : 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00,
287 : 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
288 : 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
289 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x0F,
291 : 0x0A, 0x00, 0x5C, 0x86, 0x4C, 0x00, 0x2F, 0x5E,
292 : 0x1A, 0x00, 0xBF, 0xD3, 0xD7, 0x00, 0x29, 0x17,
293 : 0x8D, 0x00, 0x50, 0xA7, 0xA4, 0x00, 0x59, 0x57,
294 : 0x7F, 0x00, 0xC6, 0xA3, 0xAC, 0x00, 0xFC, 0xFE,
295 : 0xFC, 0x00, 0x28, 0x12, 0x53, 0x00, 0x58, 0x7D,
296 : 0x72, 0x00, 0xC4, 0x3A, 0x34, 0x00, 0x3C, 0x3D,
297 : 0x69, 0x00, 0xC5, 0xB6, 0xB9, 0x00, 0x94, 0x92,
298 : 0x87, 0x00, 0x7E, 0x7A, 0xAA, 0x00, 0x88, 0x88,
299 : 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x81, 0x22,
300 : 0xD8, 0x88, 0x88, 0x88, 0xF6, 0xD8, 0x82, 0x22,
301 : 0xE8, 0x88, 0x88, 0x8D, 0x44, 0x98, 0x82, 0x22,
302 : 0xA8, 0x88, 0x88, 0x8F, 0x44, 0x48, 0x82, 0x22,
303 : 0x25, 0x76, 0x67, 0x55, 0x44, 0xF8, 0x88, 0x88,
304 : 0x3A, 0xC9, 0x9C, 0x53, 0x83, 0x88, 0x88, 0x88,
305 : 0x8D, 0x99, 0x99, 0x38, 0x88, 0x88, 0x88, 0x88,
306 : 0x88, 0x99, 0x9C, 0x88, 0x88, 0x88, 0x88, 0x88,
307 : 0x88, 0xF9, 0x9D, 0x88, 0x88, 0x88, 0x88, 0x88,
308 : 0x88, 0x8A, 0x58, 0x88, 0x88, 0x88, 0x88, 0x88,
309 : 0x88, 0x85, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
310 : 0x88, 0xEA, 0xAE, 0x88, 0x88, 0x88, 0x88, 0x88,
311 : 0x88, 0x00, 0x0B, 0x88, 0x88, 0x88, 0x88, 0x88,
312 : 0x88, 0x70, 0x0D, 0x88, 0x88, 0x88, 0x88, 0x88,
313 : 0x88, 0x87, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
314 : 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
315 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
323 : };
324 :
325 : /*------------------------------------------------------------------*/
326 :
327 : class Param;
328 : class Return;
329 : void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh);
330 : int vaxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
331 : int minor, int major, int text, int label, int grid, double ymin, double ymax,
332 : BOOL logaxis);
333 : void haxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
334 : int minor, int major, int text, int label, int grid, double xmin, double xmax);
335 : void get_elog_url(char *url, int len);
336 : void show_header(Return* r, const char *title, const char *method, const char *path, int refresh);
337 : void show_navigation_bar(Return* r, const char *cur_page);
338 :
339 : /*------------------------------------------------------------------*/
340 :
341 0 : char *stristr(const char *str, const char *pattern)
342 : {
343 : char c1, c2, *ps, *pp;
344 :
345 0 : if (str == NULL || pattern == NULL)
346 0 : return NULL;
347 :
348 0 : while (*str) {
349 0 : ps = (char *) str;
350 0 : pp = (char *) pattern;
351 0 : c1 = *ps;
352 0 : c2 = *pp;
353 0 : if (toupper(c1) == toupper(c2)) {
354 0 : while (*pp) {
355 0 : c1 = *ps;
356 0 : c2 = *pp;
357 :
358 0 : if (toupper(c1) != toupper(c2))
359 0 : break;
360 :
361 0 : ps++;
362 0 : pp++;
363 : }
364 :
365 0 : if (!*pp)
366 0 : return (char *) str;
367 : }
368 0 : str++;
369 : }
370 :
371 0 : return NULL;
372 : }
373 :
374 : /*------------------------------------------------------------------*/
375 :
376 0 : static double GetTimeSec()
377 : {
378 : struct timeval tv;
379 0 : gettimeofday(&tv, NULL);
380 0 : return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
381 : }
382 :
383 : /*------------------------------------------------------------------*/
384 :
385 : class RequestTrace
386 : {
387 : public:
388 : double fTimeReceived; // time request received
389 : double fTimeLocked; // time lock is taken
390 : double fTimeUnlocked; // time lock is released
391 : double fTimeProcessed; // time processing of request is done
392 : double fTimeSent; // time sending the request is done
393 : bool fCompleted; // flag the request completed, it's RequestTrace is safe to delete
394 : std::string fMethod; // request HTTP method
395 : std::string fUri; // request URL/URI
396 : std::string fQuery; // request query string
397 : std::string fRPC; // request RPC
398 : std::string fResource; // request file resource, with full path
399 : bool fAuthOk; // password check passed
400 :
401 : public:
402 0 : RequestTrace() // ctor
403 0 : {
404 0 : fTimeReceived = 0;
405 0 : fTimeLocked = 0;
406 0 : fTimeUnlocked = 0;
407 0 : fTimeProcessed = 0;
408 0 : fTimeSent = 0;
409 0 : fCompleted = false;
410 0 : fAuthOk = false;
411 0 : }
412 :
413 0 : void PrintTrace0() const
414 : {
415 0 : printf("%.3f ", fTimeReceived);
416 0 : printf("%.3f ", fTimeLocked-fTimeReceived);
417 0 : printf("%.3f ", fTimeUnlocked-fTimeLocked);
418 0 : printf("%.3f ", fTimeProcessed-fTimeUnlocked);
419 0 : printf("%.3f ", fTimeSent-fTimeProcessed);
420 0 : printf("A ");
421 0 : printf("%d ", fAuthOk);
422 0 : printf("T ");
423 0 : printf("%.3f ", fTimeSent-fTimeReceived);
424 0 : printf("%.3f ", fTimeLocked-fTimeReceived);
425 0 : printf("%.3f ", fTimeProcessed-fTimeLocked);
426 0 : printf("M %s ", fMethod.c_str());
427 0 : printf("URL %s ", fUri.c_str());
428 0 : if (fRPC.length() > 0) {
429 0 : printf("RPC %s ", fRPC.c_str());
430 : }
431 0 : printf("\n");
432 0 : };
433 : };
434 :
435 : static int http_trace = 0;
436 :
437 : class RequestTraceBuf
438 : {
439 : public:
440 : MUTEX_T* fMutex;
441 : std::vector<RequestTrace*> fBuf;
442 :
443 : public:
444 0 : RequestTraceBuf() // ctor
445 0 : {
446 : int status;
447 0 : status = ss_mutex_create(&fMutex, FALSE);
448 0 : assert(status==SS_SUCCESS || status==SS_CREATED);
449 0 : }
450 :
451 : //RequestTrace* NewTrace() // RequestTrace factory
452 : //{
453 : // RequestTrace* t = new RequestTrace;
454 : // fBuf.push_back(t);
455 : // return t;
456 : //}
457 :
458 : void AddTrace(RequestTrace* t)
459 : {
460 : fBuf.push_back(t);
461 : }
462 :
463 0 : void AddTraceMTS(RequestTrace* t)
464 : {
465 0 : ss_mutex_wait_for(fMutex, 0);
466 0 : if (http_trace) {
467 0 : t->PrintTrace0();
468 : }
469 0 : delete t;
470 : //AddTrace(t);
471 0 : ss_mutex_release(fMutex);
472 0 : }
473 :
474 : void Clear() // clear all completed requests
475 : {
476 : // delete all completed requests
477 : for (unsigned i=0; i<fBuf.size(); i++) {
478 : if (fBuf[i] && fBuf[i]->fCompleted) {
479 : delete fBuf[i];
480 : fBuf[i] = NULL;
481 : }
482 : }
483 :
484 : // compact all non-completed requests
485 : unsigned k = 0;
486 : for (unsigned i=0; i<fBuf.size(); i++) {
487 : if (fBuf[i]) {
488 : if (fBuf[k] != NULL) {
489 : for (; k<i; k++) {
490 : if (fBuf[k] == NULL) {
491 : break;
492 : }
493 : }
494 : }
495 : // if we found an empty spot between "k" and "i" move "i" there
496 : // if there is no empty spot, then "i" does not need to be moved
497 : if (fBuf[k] == NULL) {
498 : fBuf[k] = fBuf[i];
499 : fBuf[i] = NULL;
500 : }
501 : }
502 : }
503 : }
504 : };
505 :
506 : static RequestTraceBuf* gTraceBuf = NULL;
507 :
508 : /*------------------------------------------------------------------*/
509 :
510 : /* size of buffer for incoming data, must fit sum of all attachments */
511 : #define WEB_BUFFER_SIZE (6*1024*1024)
512 :
513 : class Return
514 : {
515 : public:
516 :
517 : size_t return_size;
518 : char *return_buffer;
519 :
520 : int strlen_retbuf;
521 : int return_length;
522 :
523 : public:
524 0 : Return() // ctor
525 0 : {
526 0 : return_size = WEB_BUFFER_SIZE;
527 0 : return_buffer = (char*)malloc(return_size);
528 0 : assert(return_buffer != NULL);
529 :
530 0 : strlen_retbuf = 0;
531 0 : return_length = 0;
532 0 : }
533 :
534 0 : ~Return() // dtor
535 : {
536 0 : if (return_buffer)
537 0 : free(return_buffer);
538 0 : return_buffer = NULL;
539 0 : return_size = 0;
540 0 : strlen_retbuf = 0;
541 0 : return_length = 0;
542 0 : }
543 :
544 0 : void reset()
545 : {
546 0 : strlen_retbuf = 0;
547 0 : }
548 :
549 0 : void zero()
550 : {
551 0 : memset(return_buffer, 0, return_size);
552 0 : strlen_retbuf = 0;
553 0 : return_length = 0;
554 0 : }
555 :
556 0 : int return_grow(size_t len)
557 : {
558 : //printf("size %d, grow %d, room %d\n", return_size, len, return_size - strlen_retbuf);
559 :
560 0 : for (int i=0; i<1000; i++) { // infinite loop with protection against infinite looping
561 0 : if (strlen_retbuf + len < return_size-40)
562 0 : return SUCCESS;
563 :
564 0 : return_size *= 2;
565 0 : return_buffer = (char*)realloc(return_buffer, return_size);
566 :
567 0 : assert(return_buffer);
568 :
569 : //printf("new size %d\n", return_size);
570 : }
571 :
572 0 : assert(!"Cannot happen!"); // does not return
573 : return 0;
574 : }
575 :
576 : /*------------------------------------------------------------------*/
577 :
578 0 : void rmemcpy(const void *buf, int len)
579 : {
580 0 : return_grow(len);
581 0 : memcpy(return_buffer + strlen_retbuf, buf, len);
582 0 : strlen_retbuf += len;
583 0 : return_length = strlen_retbuf;
584 0 : }
585 :
586 : /*------------------------------------------------------------------*/
587 :
588 0 : void rread(const char* filename, int fh, int len)
589 : {
590 0 : return_grow(len);
591 0 : int rd = read(fh, return_buffer + strlen_retbuf, len);
592 0 : if (rd != len) {
593 0 : cm_msg(MERROR, "rread", "Cannot read file \'%s\', read of %d returned %d, errno %d (%s)", filename, len, rd, errno, strerror(errno));
594 0 : memset(return_buffer + strlen_retbuf, 0, len);
595 : }
596 0 : strlen_retbuf += len;
597 0 : return_length = strlen_retbuf;
598 0 : }
599 :
600 : /*------------------------------------------------------------------*/
601 :
602 0 : void rsputs(const char *str)
603 : {
604 0 : size_t len = strlen(str);
605 :
606 0 : return_grow(len);
607 :
608 0 : if (strlen_retbuf + len > return_size-40) {
609 0 : strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
610 0 : strlen_retbuf = strlen(return_buffer);
611 : } else {
612 0 : strcpy(return_buffer + strlen_retbuf, str);
613 0 : strlen_retbuf += len;
614 : }
615 :
616 0 : return_length = strlen_retbuf;
617 0 : }
618 :
619 : /*------------------------------------------------------------------*/
620 :
621 : void rsputs2(const char *str)
622 : {
623 : size_t len = strlen(str);
624 :
625 : return_grow(len);
626 :
627 : if (strlen_retbuf + len > return_size) {
628 : mstrlcpy(return_buffer, "<H1>Error: return buffer too small</H1>", return_size);
629 : strlen_retbuf = strlen(return_buffer);
630 : } else {
631 : int j = strlen_retbuf;
632 : for (size_t i = 0; i < len; i++) {
633 : if (strncmp(str + i, "http://", 7) == 0) {
634 : int k;
635 : char link[256];
636 : char* p = (char *) (str + i + 7);
637 :
638 : i += 7;
639 : for (k = 0; *p && *p != ' ' && *p != '\n'; k++, i++)
640 : link[k] = *p++;
641 : link[k] = 0;
642 :
643 : sprintf(return_buffer + j, "<a href=\"http://%s\">http://%s</a>", link, link);
644 : j += strlen(return_buffer + j);
645 : } else
646 : switch (str[i]) {
647 : case '<':
648 : mstrlcat(return_buffer, "<", return_size);
649 : j += 4;
650 : break;
651 : case '>':
652 : mstrlcat(return_buffer, ">", return_size);
653 : j += 4;
654 : break;
655 : default:
656 : return_buffer[j++] = str[i];
657 : }
658 : }
659 :
660 : return_buffer[j] = 0;
661 : strlen_retbuf = j;
662 : }
663 :
664 : return_length = strlen_retbuf;
665 : }
666 :
667 : /*------------------------------------------------------------------*/
668 :
669 0 : void rsprintf(const char *format, ...) MATTRPRINTF(2,3)
670 : {
671 : va_list argptr;
672 : char str[10000];
673 :
674 0 : va_start(argptr, format);
675 0 : vsprintf(str, (char *) format, argptr);
676 0 : va_end(argptr);
677 :
678 : // catch array overrun. better too late than never...
679 0 : assert(strlen(str) < sizeof(str));
680 :
681 0 : return_grow(strlen(str));
682 :
683 0 : if (strlen_retbuf + strlen(str) > return_size)
684 0 : strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
685 : else
686 0 : strcpy(return_buffer + strlen_retbuf, str);
687 :
688 0 : strlen_retbuf += strlen(str);
689 0 : return_length = strlen_retbuf;
690 0 : }
691 : };
692 :
693 : /*------------------------------------------------------------------*/
694 :
695 : /* Parameter handling functions similar to setenv/getenv */
696 :
697 : #define MAX_PARAM 500
698 : #define PARAM_LENGTH 256
699 : #define TEXT_SIZE 50000
700 :
701 : class Param
702 : {
703 : public:
704 : char _param[MAX_PARAM][PARAM_LENGTH];
705 : char *_value[MAX_PARAM];
706 : char _text[TEXT_SIZE];
707 :
708 : public:
709 0 : Param() // ctor
710 0 : {
711 0 : initparam();
712 0 : }
713 :
714 0 : ~Param() // dtor
715 : {
716 0 : freeparam();
717 0 : }
718 :
719 0 : void initparam()
720 : {
721 0 : memset(_param, 0, sizeof(_param));
722 0 : memset(_value, 0, sizeof(_value));
723 0 : _text[0] = 0;
724 0 : }
725 :
726 0 : void setparam(const char *param, const char *value)
727 : {
728 : int i;
729 :
730 0 : if (equal_ustring(param, "text")) {
731 0 : if (strlen(value) >= TEXT_SIZE)
732 0 : printf("Error: parameter value too big\n");
733 :
734 0 : mstrlcpy(_text, value, TEXT_SIZE);
735 0 : _text[TEXT_SIZE - 1] = 0;
736 0 : return;
737 : }
738 :
739 0 : for (i = 0; i < MAX_PARAM; i++)
740 0 : if (_param[i][0] == 0)
741 0 : break;
742 :
743 0 : if (i < MAX_PARAM) {
744 0 : mstrlcpy(_param[i], param, PARAM_LENGTH);
745 :
746 0 : int size = strlen(value)+1;
747 0 : _value[i] = (char*)malloc(size);
748 0 : mstrlcpy(_value[i], value, size);
749 0 : _value[i][strlen(value)] = 0;
750 :
751 : } else {
752 0 : printf("Error: parameter array too small\n");
753 : }
754 : }
755 :
756 0 : void freeparam()
757 : {
758 : int i;
759 :
760 0 : for (i=0 ; i<MAX_PARAM ; i++)
761 0 : if (_value[i] != NULL) {
762 0 : free(_value[i]);
763 0 : _value[i] = NULL;
764 : }
765 0 : }
766 :
767 : void printparam()
768 : {
769 : int i;
770 :
771 : for (i = 0; i < MAX_PARAM && _param[i][0]; i++) {
772 : printf("param %d name [%s] value [%s]\n", i, _param[i], _value[i]);;
773 : }
774 : }
775 :
776 0 : const char *getparam(const char *param)
777 : {
778 : int i;
779 :
780 0 : if (equal_ustring(param, "text"))
781 0 : return _text;
782 :
783 0 : for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
784 0 : if (equal_ustring(param, _param[i]))
785 0 : break;
786 :
787 0 : if (i == MAX_PARAM)
788 0 : return NULL;
789 :
790 0 : if (_value[i] == NULL)
791 0 : return "";
792 :
793 0 : return _value[i];
794 : }
795 :
796 0 : std::string xgetparam(const char *param)
797 : {
798 0 : const char* s = getparam(param);
799 0 : if (s)
800 0 : return s;
801 : else
802 0 : return "";
803 : }
804 :
805 0 : BOOL isparam(const char *param)
806 : {
807 : int i;
808 :
809 0 : for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
810 0 : if (equal_ustring(param, _param[i]))
811 0 : break;
812 :
813 0 : if (i < MAX_PARAM && _param[i][0])
814 0 : return TRUE;
815 :
816 0 : return FALSE;
817 : }
818 :
819 0 : void unsetparam(const char *param)
820 : {
821 : int i;
822 :
823 0 : for (i = 0; i < MAX_PARAM; i++)
824 0 : if (equal_ustring(param, _param[i]))
825 0 : break;
826 :
827 0 : if (i < MAX_PARAM) {
828 0 : _param[i][0] = 0;
829 0 : _value[i][0] = 0;
830 : }
831 0 : }
832 : };
833 :
834 : /*------------------------------------------------------------------*/
835 :
836 0 : const char *mhttpd_revision(void)
837 : {
838 0 : return cm_get_revision();
839 : }
840 :
841 : /*------------------------------------------------------------------*/
842 :
843 0 : static std::string UrlDecode(const char* p)
844 : /********************************************************************\
845 : Decode the given string in-place by expanding %XX escapes
846 : \********************************************************************/
847 : {
848 0 : std::string s;
849 :
850 : //printf("URL decode: [%s] --> ", p);
851 :
852 0 : while (*p) {
853 0 : if (*p == '%') {
854 : /* Escape: next 2 chars are hex representation of the actual character */
855 0 : p++;
856 0 : if (isxdigit(p[0]) && isxdigit(p[1])) {
857 0 : int i = 0;
858 : char str[3];
859 0 : str[0] = p[0];
860 0 : str[1] = p[1];
861 0 : str[2] = 0;
862 0 : sscanf(str, "%02X", &i);
863 :
864 0 : s += (char) i;
865 0 : p += 2;
866 0 : } else
867 0 : s += '%';
868 0 : } else if (*p == '+') {
869 : /* convert '+' to ' ' */
870 0 : s += ' ';
871 0 : p++;
872 : } else {
873 0 : s += *p++;
874 : }
875 : }
876 :
877 : //printf("[%s]\n", s.c_str());
878 :
879 0 : return s;
880 0 : }
881 :
882 0 : static void urlDecode(char *p)
883 : /********************************************************************\
884 : Decode the given string in-place by expanding %XX escapes
885 : \********************************************************************/
886 : {
887 : //char *px = p;
888 : char *pD, str[3];
889 : int i;
890 :
891 : //printf("URL decode: [%s] --> ", p);
892 :
893 0 : pD = p;
894 0 : while (*p) {
895 0 : if (*p == '%') {
896 : /* Escape: next 2 chars are hex representation of the actual character */
897 0 : p++;
898 0 : if (isxdigit(p[0]) && isxdigit(p[1])) {
899 0 : str[0] = p[0];
900 0 : str[1] = p[1];
901 0 : str[2] = 0;
902 0 : sscanf(str, "%02X", &i);
903 :
904 0 : *pD++ = (char) i;
905 0 : p += 2;
906 : } else
907 0 : *pD++ = '%';
908 0 : } else if (*p == '+') {
909 : /* convert '+' to ' ' */
910 0 : *pD++ = ' ';
911 0 : p++;
912 : } else {
913 0 : *pD++ = *p++;
914 : }
915 : }
916 0 : *pD = '\0';
917 :
918 : //printf("[%s]\n", px);
919 0 : }
920 :
921 0 : static void urlEncode(char *ps, int ps_size)
922 : /*
923 : Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
924 : Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
925 : */
926 : {
927 : char *pd, *p;
928 0 : int len = strlen(ps);
929 0 : char *str = (char*)malloc(len*3 + 10); // at worst, each input character is expanded into 3 output characters
930 :
931 0 : pd = str;
932 0 : p = ps;
933 0 : while (*p) {
934 0 : if (isalnum(*p)) {
935 0 : *pd++ = *p++;
936 : } else {
937 0 : sprintf(pd, "%%%02X", (*p)&0xFF);
938 0 : pd += 3;
939 0 : p++;
940 : }
941 : }
942 0 : *pd = '\0';
943 :
944 : if (/* DISABLES CODE */ (0)) {
945 : printf("urlEncode [");
946 : for (p=ps; *p!=0; p++)
947 : printf("0x%02x ", (*p)&0xFF);
948 : printf("]\n");
949 :
950 : printf("urlEncode [%s] -> [%s]\n", ps, str);
951 : }
952 :
953 0 : mstrlcpy(ps, str, ps_size);
954 0 : free(str);
955 0 : }
956 :
957 0 : static std::string urlEncode(const char *text)
958 : /*
959 : Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
960 : Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
961 : */
962 : {
963 0 : std::string encoded;
964 :
965 0 : const char* p = text;
966 0 : while (*p) {
967 0 : if (isalnum(*p)) {
968 0 : encoded += *p++;
969 : } else {
970 : char buf[16];
971 0 : sprintf(buf, "%%%02X", (*p)&0xFF);
972 0 : encoded += buf;
973 0 : p++;
974 : }
975 : }
976 :
977 : if (/* DISABLES CODE */ (0)) {
978 : printf("urlEncode [");
979 : for (p=text; *p!=0; p++)
980 : printf("0x%02x ", (*p)&0xFF);
981 : printf("]\n");
982 :
983 : printf("urlEncode [%s] -> [%s]\n", text, encoded.c_str());
984 : }
985 :
986 0 : return encoded;
987 0 : }
988 :
989 : /*------------------------------------------------------------------*/
990 :
991 0 : std::vector<std::string> get_resource_paths()
992 : {
993 : HNDLE hDB;
994 : int status;
995 :
996 0 : cm_get_experiment_database(&hDB, NULL);
997 :
998 0 : std::vector<std::string> paths;
999 :
1000 : // add /Experiment/Resources
1001 0 : std::string buf;
1002 0 : status = db_get_value_string(hDB, 0, "/Experiment/Resources", 0, &buf, TRUE);
1003 0 : if (status == DB_SUCCESS && buf.length() > 0)
1004 0 : paths.push_back(buf);
1005 :
1006 : // add "/Logger/History/IMAGE/History dir"
1007 0 : paths.push_back(cm_get_history_path("IMAGE"));
1008 :
1009 : // add /Logger/Data dir
1010 0 : status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &buf, TRUE);
1011 0 : if (status == DB_SUCCESS && buf.length() > 0)
1012 0 : paths.push_back(buf);
1013 :
1014 0 : std::string cwd = ss_getcwd();
1015 0 : if (!cwd.empty()) {
1016 0 : paths.push_back(cwd + "/");
1017 0 : paths.push_back(cwd + "/resources/");
1018 : }
1019 0 : paths.push_back(cm_get_path());
1020 0 : paths.push_back(cm_get_path() + "resources/");
1021 0 : char *m = getenv("MIDASSYS");
1022 0 : if (m) {
1023 0 : paths.push_back(std::string(m) + "/resources/");
1024 : }
1025 :
1026 0 : return paths;
1027 0 : }
1028 :
1029 : /*------------------------------------------------------------------*/
1030 :
1031 0 : bool open_resource_file(const char *filename, std::string* ppath, FILE** pfp)
1032 : {
1033 : // resource file names should not start with a directory separator "/"
1034 : // or contain ".." as this will allow them to escape the mhttpd filename "jail"
1035 : // by asking file files names like "../../etc/passwd", etc.
1036 :
1037 0 : if (strlen(filename) < 1) {
1038 0 : cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' is too short",
1039 : filename);
1040 0 : return false;
1041 : }
1042 :
1043 0 : if (filename[0] == DIR_SEPARATOR) {
1044 0 : cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' starting with \'%c\' which is not allowed",
1045 : filename, DIR_SEPARATOR);
1046 0 : return false;
1047 : }
1048 :
1049 0 : if (strstr(filename, "..") != NULL) {
1050 0 : cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' containing \'..\' which is not allowed",
1051 : filename);
1052 0 : return false;
1053 : }
1054 :
1055 0 : std::vector<std::string> paths = get_resource_paths();
1056 :
1057 0 : std::vector<std::string> paths_not_found;
1058 :
1059 0 : for (unsigned i=0; i<paths.size(); i++) {
1060 0 : std::string path = paths[i];
1061 0 : if (path.length() < 1)
1062 0 : continue;
1063 0 : if (path[0] == '#')
1064 0 : continue;
1065 :
1066 : // expand env.variables before we add the filename.
1067 : // the filename comes from the URL and if the URL
1068 : // has '$' characters we will try to expand them
1069 : // as an env.variable and maybe escape the file jail.
1070 :
1071 0 : std::string xpath = cm_expand_env(path.c_str());
1072 :
1073 0 : if (xpath[xpath.length()-1] != DIR_SEPARATOR)
1074 0 : xpath += DIR_SEPARATOR_STR;
1075 0 : xpath += filename;
1076 :
1077 : //printf("path [%s] [%s] [%s]\n", paths[i].c_str(), path.c_str(), xpath.c_str());
1078 :
1079 0 : FILE* fp = fopen(xpath.c_str(), "r");
1080 0 : if (fp) {
1081 : struct stat statbuf;
1082 0 : int status = fstat(fileno(fp), &statbuf);
1083 0 : if (status != 0) {
1084 0 : cm_msg(MERROR, "open_resource_file", "Cannot fstat() file \'%s\', error %d (%s)", xpath.c_str(), errno, strerror(errno));
1085 0 : fclose(fp);
1086 0 : fp = NULL;
1087 : }
1088 :
1089 0 : if (statbuf.st_mode & S_IFREG) {
1090 : // good, normal file
1091 : //printf("%s: regular!\n", xpath.c_str());
1092 : //} else if (statbuf.st_mode & S_IFLNK) {
1093 : // symlink
1094 : //printf("%s: symlink!\n", xpath.c_str());
1095 0 : } else if (statbuf.st_mode & S_IFDIR) {
1096 0 : cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is a directory", xpath.c_str(), filename);
1097 0 : fclose(fp);
1098 0 : fp = NULL;
1099 : } else {
1100 0 : cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is not a regular file, st_mode is 0x%08x", xpath.c_str(), filename, statbuf.st_mode);
1101 0 : fclose(fp);
1102 0 : fp = NULL;
1103 : }
1104 :
1105 0 : if (fp) {
1106 0 : if (ppath)
1107 0 : *ppath = xpath;
1108 0 : if (pfp) {
1109 0 : *pfp = fp;
1110 : } else {
1111 0 : fclose(fp);
1112 0 : fp = NULL;
1113 : }
1114 : //cm_msg(MINFO, "open_resource_file", "Resource file \'%s\' is \'%s\'", filename, xpath.c_str());
1115 0 : return true;
1116 : }
1117 : }
1118 :
1119 0 : paths_not_found.push_back(xpath);
1120 0 : }
1121 :
1122 0 : std::string s;
1123 0 : for (unsigned i=0; i<paths_not_found.size(); i++) {
1124 0 : if (i>0)
1125 0 : s += ", ";
1126 0 : s += paths_not_found[i];
1127 : }
1128 :
1129 0 : cm_msg(MERROR, "open_resource_file", "Cannot find resource file \'%s\', tried %s", filename, s.c_str());
1130 0 : return false;
1131 0 : }
1132 :
1133 : /*------------------------------------------------------------------*/
1134 :
1135 0 : std::string get_content_type(const char* filename)
1136 : {
1137 0 : std::string ext_upper;
1138 0 : const char* p = filename;
1139 0 : const char* last_dot = NULL;
1140 0 : for (; *p; p++) {
1141 0 : if (*p == '.')
1142 0 : last_dot = p;
1143 0 : if (*p == DIR_SEPARATOR)
1144 0 : last_dot = NULL;
1145 : }
1146 :
1147 0 : if (last_dot) {
1148 0 : p = last_dot;
1149 0 : for (; *p; p++)
1150 0 : ext_upper += toupper(*p);
1151 : }
1152 :
1153 : //printf("filename: [%s], ext [%s]\n", filename, ext_upper.c_str());
1154 :
1155 0 : std::string type = GetMimetype(ext_upper);
1156 0 : if (type.length() > 0)
1157 0 : return type;
1158 :
1159 0 : cm_msg(MERROR, "get_content_type", "Unknown HTTP Content-Type for resource file \'%s\', file extension \'%s\'", filename, ext_upper.c_str());
1160 :
1161 0 : return "text/plain";
1162 0 : }
1163 :
1164 : /*------------------------------------------------------------------*/
1165 :
1166 0 : bool send_fp(Return* r, const std::string& path, FILE* fp)
1167 : {
1168 0 : assert(fp != NULL);
1169 :
1170 : // send HTTP headers
1171 :
1172 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1173 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1174 0 : r->rsprintf("Accept-Ranges: bytes\r\n");
1175 :
1176 : // send HTTP cache control headers
1177 :
1178 0 : time_t now = time(NULL);
1179 0 : now += (int) (3600 * 24);
1180 : struct tm gmt_tms;
1181 0 : gmtime_r(&now, &gmt_tms);
1182 0 : const char* format = "%A, %d-%b-%y %H:%M:%S GMT";
1183 :
1184 : char str[256];
1185 0 : strftime(str, sizeof(str), format, &gmt_tms);
1186 0 : r->rsprintf("Expires: %s\r\n", str);
1187 :
1188 : // send Content-Type header
1189 :
1190 0 : r->rsprintf("Content-Type: %s\r\n", get_content_type(path.c_str()).c_str());
1191 :
1192 : // send Content-Length header
1193 :
1194 : struct stat stat_buf;
1195 0 : fstat(fileno(fp), &stat_buf);
1196 0 : int length = stat_buf.st_size;
1197 0 : r->rsprintf("Content-Length: %d\r\n", length);
1198 :
1199 : // send end of headers
1200 :
1201 0 : r->rsprintf("\r\n");
1202 :
1203 : // send file data
1204 :
1205 0 : r->rread(path.c_str(), fileno(fp), length);
1206 :
1207 0 : fclose(fp);
1208 :
1209 0 : return true;
1210 : }
1211 :
1212 0 : bool send_file(Return* r, const std::string& path, bool generate_404 = true)
1213 : {
1214 0 : FILE *fp = fopen(path.c_str(), "rb");
1215 :
1216 0 : if (!fp) {
1217 0 : if (generate_404) {
1218 : /* header */
1219 0 : r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1220 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1221 0 : r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1222 0 : r->rsprintf("\r\n");
1223 0 : r->rsprintf("Error: Cannot read \"%s\", fopen() errno %d (%s)\n", path.c_str(), errno, strerror(errno));
1224 : }
1225 0 : return false;
1226 : }
1227 :
1228 0 : return send_fp(r, path, fp);
1229 : }
1230 :
1231 0 : bool send_resource(Return* r, const std::string& name, bool generate_404 = true)
1232 : {
1233 0 : std::string path;
1234 0 : FILE *fp = NULL;
1235 :
1236 0 : bool found = open_resource_file(name.c_str(), &path, &fp);
1237 :
1238 0 : if (!found) {
1239 0 : if (generate_404) {
1240 : /* header */
1241 0 : r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1242 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1243 0 : r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1244 0 : r->rsprintf("\r\n");
1245 0 : r->rsprintf("Error: resource file \"%s\" not found, see messages\n", name.c_str());
1246 : }
1247 0 : return false;
1248 : }
1249 :
1250 0 : return send_fp(r, path, fp);
1251 0 : }
1252 :
1253 : /*------------------------------------------------------------------*/
1254 :
1255 0 : INT sendmail(const char* from_host, const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
1256 : {
1257 : struct sockaddr_in bind_addr;
1258 : struct hostent *phe;
1259 : int i, s, strsize, offset;
1260 : char *str, buf[256];
1261 :
1262 0 : if (verbose)
1263 0 : printf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
1264 :
1265 : /* create a new socket for connecting to remote server */
1266 0 : s = socket(AF_INET, SOCK_STREAM, 0);
1267 0 : if (s == -1)
1268 0 : return -1;
1269 :
1270 : /* connect to remote node port 25 */
1271 0 : memset(&bind_addr, 0, sizeof(bind_addr));
1272 0 : bind_addr.sin_family = AF_INET;
1273 0 : bind_addr.sin_port = htons((short) 25);
1274 :
1275 0 : phe = gethostbyname(smtp_host);
1276 0 : if (phe == NULL)
1277 0 : return -1;
1278 0 : memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
1279 :
1280 0 : if (connect(s, (const sockaddr*)&bind_addr, sizeof(bind_addr)) < 0) {
1281 0 : closesocket(s);
1282 0 : return -1;
1283 : }
1284 :
1285 0 : strsize = TEXT_SIZE + 1000;
1286 0 : str = (char*)malloc(strsize);
1287 :
1288 0 : recv_string(s, str, strsize, 3000);
1289 0 : if (verbose)
1290 0 : puts(str);
1291 :
1292 : /* drain server messages */
1293 : do {
1294 0 : str[0] = 0;
1295 0 : recv_string(s, str, strsize, 300);
1296 0 : if (verbose)
1297 0 : puts(str);
1298 0 : } while (str[0]);
1299 :
1300 0 : sprintf(str, "HELO %s\r\n", from_host);
1301 0 : send(s, str, strlen(str), 0);
1302 0 : if (verbose)
1303 0 : puts(str);
1304 0 : recv_string(s, str, strsize, 3000);
1305 0 : if (verbose)
1306 0 : puts(str);
1307 :
1308 0 : if (strchr(from, '<')) {
1309 0 : mstrlcpy(buf, strchr(from, '<') + 1, sizeof(buf));
1310 0 : if (strchr(buf, '>'))
1311 0 : *strchr(buf, '>') = 0;
1312 : } else
1313 0 : mstrlcpy(buf, from, sizeof(buf));
1314 :
1315 0 : sprintf(str, "MAIL FROM: %s\n", buf);
1316 0 : send(s, str, strlen(str), 0);
1317 0 : if (verbose)
1318 0 : puts(str);
1319 0 : recv_string(s, str, strsize, 3000);
1320 0 : if (verbose)
1321 0 : puts(str);
1322 :
1323 0 : sprintf(str, "RCPT TO: <%s>\r\n", to);
1324 0 : send(s, str, strlen(str), 0);
1325 0 : if (verbose)
1326 0 : puts(str);
1327 0 : recv_string(s, str, strsize, 3000);
1328 0 : if (verbose)
1329 0 : puts(str);
1330 :
1331 0 : sprintf(str, "DATA\r\n");
1332 0 : send(s, str, strlen(str), 0);
1333 0 : if (verbose)
1334 0 : puts(str);
1335 0 : recv_string(s, str, strsize, 3000);
1336 0 : if (verbose)
1337 0 : puts(str);
1338 :
1339 0 : sprintf(str, "To: %s\r\nFrom: %s\r\nSubject: %s\r\n", to, from, subject);
1340 0 : send(s, str, strlen(str), 0);
1341 0 : if (verbose)
1342 0 : puts(str);
1343 :
1344 0 : sprintf(str, "X-Mailer: mhttpd revision %s\r\n", mhttpd_revision());
1345 0 : send(s, str, strlen(str), 0);
1346 0 : if (verbose)
1347 0 : puts(str);
1348 :
1349 0 : ss_tzset(); // required for localtime_r()
1350 : time_t now;
1351 0 : time(&now);
1352 : struct tm tms;
1353 0 : localtime_r(&now, &tms);
1354 0 : strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", &tms);
1355 0 : offset = (-(int) timezone);
1356 0 : if (tms.tm_isdst)
1357 0 : offset += 3600;
1358 0 : sprintf(str, "Date: %s %+03d%02d\r\n", buf, (int) (offset / 3600),
1359 0 : (int) ((abs((int) offset) / 60) % 60));
1360 0 : send(s, str, strlen(str), 0);
1361 0 : if (verbose)
1362 0 : puts(str);
1363 :
1364 0 : sprintf(str, "Content-Type: TEXT/PLAIN; charset=US-ASCII\r\n\r\n");
1365 0 : send(s, str, strlen(str), 0);
1366 0 : if (verbose)
1367 0 : puts(str);
1368 :
1369 : /* analyze text for "." at beginning of line */
1370 0 : const char* p = text;
1371 0 : str[0] = 0;
1372 0 : while (strstr(p, "\r\n.\r\n")) {
1373 0 : i = (POINTER_T) strstr(p, "\r\n.\r\n") - (POINTER_T) p + 1;
1374 0 : mstrlcat(str, p, i);
1375 0 : p += i + 4;
1376 0 : mstrlcat(str, "\r\n..\r\n", strsize);
1377 : }
1378 0 : mstrlcat(str, p, strsize);
1379 0 : mstrlcat(str, "\r\n", strsize);
1380 0 : send(s, str, strlen(str), 0);
1381 0 : if (verbose)
1382 0 : puts(str);
1383 :
1384 : /* send ".<CR>" to signal end of message */
1385 0 : sprintf(str, ".\r\n");
1386 0 : send(s, str, strlen(str), 0);
1387 0 : if (verbose)
1388 0 : puts(str);
1389 0 : recv_string(s, str, strsize, 3000);
1390 0 : if (verbose)
1391 0 : puts(str);
1392 :
1393 0 : sprintf(str, "QUIT\n");
1394 0 : send(s, str, strlen(str), 0);
1395 0 : if (verbose)
1396 0 : puts(str);
1397 0 : recv_string(s, str, strsize, 3000);
1398 0 : if (verbose)
1399 0 : puts(str);
1400 :
1401 0 : closesocket(s);
1402 0 : free(str);
1403 :
1404 0 : return 1;
1405 : }
1406 :
1407 : /*------------------------------------------------------------------*/
1408 :
1409 0 : void redirect(Return *r, const char *path)
1410 : {
1411 : char str[256];
1412 :
1413 : //printf("redirect to [%s]\n", path);
1414 :
1415 0 : mstrlcpy(str, path, sizeof(str));
1416 0 : if (str[0] == 0)
1417 0 : strcpy(str, "./");
1418 :
1419 : /* redirect */
1420 0 : r->rsprintf("HTTP/1.1 302 Found\r\n");
1421 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1422 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1423 :
1424 0 : if (strncmp(path, "http:", 5) == 0)
1425 0 : r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1426 0 : else if (strncmp(path, "https:", 6) == 0)
1427 0 : r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1428 : else {
1429 0 : r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1430 : }
1431 0 : }
1432 :
1433 0 : void redirect_307(Return *r, const char *path)
1434 : {
1435 : //printf("redirect_307 to [%s]\n", path);
1436 :
1437 : /* redirect */
1438 0 : r->rsprintf("HTTP/1.1 307 Temporary Redirect\r\n");
1439 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1440 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1441 0 : r->rsprintf("Location: %s\r\n", path);
1442 0 : r->rsprintf("\r\n");
1443 0 : r->rsprintf("<html>redirect to %s</html>\r\n", path);
1444 0 : }
1445 :
1446 0 : void redirect2(Return* r, const char *path)
1447 : {
1448 0 : redirect(r, path);
1449 0 : }
1450 :
1451 : /*------------------------------------------------------------------*/
1452 :
1453 : struct search_data
1454 : {
1455 : Return* r;
1456 : const char* search_name;
1457 : };
1458 :
1459 0 : INT search_callback(HNDLE hDB, HNDLE hKey, KEY * key, INT level, void *info)
1460 : {
1461 0 : search_data* sinfo = (search_data*)info;
1462 : int i;
1463 : INT size, status;
1464 :
1465 0 : Return* r = sinfo->r;
1466 0 : const char* search_name = sinfo->search_name;
1467 :
1468 : /* convert strings to uppercase */
1469 :
1470 : char xstr1[MAX_ODB_PATH];
1471 0 : for (i = 0; key->name[i]; i++)
1472 0 : xstr1[i] = toupper(key->name[i]);
1473 0 : xstr1[i] = 0;
1474 :
1475 : char str2[MAX_ODB_PATH];
1476 0 : for (i = 0; search_name[i] ; i++)
1477 0 : str2[i] = toupper(search_name[i]);
1478 0 : str2[i] = 0;
1479 :
1480 0 : if (strstr(xstr1, str2) != NULL) {
1481 : char data[10000];
1482 0 : std::string path = db_get_path(hDB, hKey).substr(1);
1483 0 : std::string path_encoded = urlEncode(path.c_str());
1484 :
1485 0 : if (key->type == TID_KEY || key->type == TID_LINK) {
1486 : /* for keys, don't display data value */
1487 0 : r->rsprintf("<tr><td class=\"ODBkey\"><a href=\"?cmd=odb&odb_path=/%s\">/%s</a></tr>\n", path_encoded.c_str(), path.c_str());
1488 : } else {
1489 : /* strip variable name from path */
1490 0 : char* p = const_cast<char *>(path.data() + path.length() - 1);
1491 0 : while (*p && *p != '/')
1492 0 : *p-- = 0;
1493 0 : if (*p == '/')
1494 0 : *p = 0;
1495 :
1496 : /* display single value */
1497 0 : if (key->num_values == 1) {
1498 0 : size = sizeof(data);
1499 0 : status = db_get_data(hDB, hKey, data, &size, key->type);
1500 0 : std::string data_str;
1501 0 : if (status == DB_NO_ACCESS)
1502 0 : data_str = "<no read access>";
1503 : else
1504 0 : data_str = db_sprintf(data, key->item_size, 0, key->type);
1505 :
1506 0 : r->rsprintf("<tr><td class=\"ODBkey\">");
1507 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s</a></td>", path_encoded.c_str(), path.c_str(), key->name);
1508 0 : r->rsprintf("<td class=\"ODBvalue\">%s</td></tr>\n", data_str.c_str());
1509 0 : } else {
1510 : /* display first value */
1511 0 : i = key->num_values;
1512 0 : if (i > 10)
1513 0 : i = 11;
1514 0 : r->rsprintf("<tr><td rowspan=%d class=\"ODBkey\">", i);
1515 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s\n", path_encoded.c_str(), path.c_str(), key->name);
1516 :
1517 0 : for (int i = 0; i < key->num_values; i++) {
1518 0 : size = sizeof(data);
1519 0 : db_get_data_index(hDB, hKey, data, &size, i, key->type);
1520 :
1521 0 : std::string data_str = db_sprintf(data, key->item_size, 0, key->type);
1522 :
1523 0 : if (i > 0)
1524 0 : r->rsprintf("<tr>");
1525 :
1526 0 : r->rsprintf("<td class=\"ODBvalue\">[%d] %s</td></tr>\n", i, data_str.c_str());
1527 :
1528 0 : if (i > 8) {
1529 0 : r->rsprintf("<tr><td class=\"ODBvalue\">... [%d] values ...</td></tr>\n", key->num_values - i - 1);
1530 0 : break;
1531 : }
1532 0 : }
1533 : }
1534 : }
1535 0 : }
1536 :
1537 0 : return SUCCESS;
1538 : }
1539 :
1540 : /*------------------------------------------------------------------*/
1541 :
1542 0 : void show_help_page(Return* r, const char* dec_path)
1543 : {
1544 : const char *s;
1545 : char str[256];
1546 : int status;
1547 :
1548 0 : show_header(r, "Help", "", "./", 0);
1549 0 : r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
1550 0 : r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
1551 0 : show_navigation_bar(r, "Help");
1552 :
1553 0 : r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1554 0 : r->rsprintf(" <tr>\n");
1555 0 : r->rsprintf(" <td class=\"mtableheader\">MIDAS Help Page</td>\n");
1556 0 : r->rsprintf(" </tr>\n");
1557 0 : r->rsprintf(" <tr>\n");
1558 0 : r->rsprintf(" <td>\n");
1559 0 : r->rsprintf(" <table>\n");
1560 :
1561 0 : r->rsprintf(" <tr>\n");
1562 0 : r->rsprintf(" <td style=\"text-align:right;\">Documentation:</td>\n");
1563 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca\">https://midas.triumf.ca</a></td>\n");
1564 0 : r->rsprintf(" </tr>\n");
1565 0 : r->rsprintf(" <tr>\n");
1566 0 : r->rsprintf(" <td style=\"text-align:right;\">Discussion Forum:</td>\n");
1567 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca/forum/\">https://midas.triumf.ca/forum/</a></td>\n");
1568 0 : r->rsprintf(" </tr>\n");
1569 0 : r->rsprintf(" <tr>\n");
1570 0 : r->rsprintf(" <td style=\"text-align:right;\">Code:</td>\n");
1571 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/\">https://bitbucket.org/tmidas/midas/</a></td>\n");
1572 0 : r->rsprintf(" </tr>\n");
1573 0 : r->rsprintf(" <tr>\n");
1574 0 : r->rsprintf(" <td style=\"text-align:right;\">Report a bug:</td>\n");
1575 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/issues/\">https://bitbucket.org/tmidas/midas/issues/</a></td>\n");
1576 0 : r->rsprintf(" </tr>\n");
1577 :
1578 0 : r->rsprintf(" <tr>\n");
1579 0 : r->rsprintf(" <td style=\"text-align:right;\">Version:</td>\n");
1580 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_version());
1581 0 : r->rsprintf(" </tr>\n");
1582 0 : r->rsprintf(" <tr>\n");
1583 0 : r->rsprintf(" <td style=\"text-align:right;\">Revision:</td>\n");
1584 0 : std::string rev = cm_get_revision();
1585 0 : std::string url = "https://bitbucket.org/tmidas/midas/commits/";
1586 : // rev format looks like this:
1587 : // Fri Nov 24 10:15:54 2017 -0800 - midas-2017-07-c-171-gb8928d5c-dirty on branch develop
1588 : // -gXXX is the commit hash
1589 : // -dirty should be removed from the hash url, if present
1590 : // " " before "on branch" should be removed from the hash url
1591 0 : std::string::size_type pos = rev.find("-g");
1592 0 : if (pos != std::string::npos) {
1593 0 : std::string hash = rev.substr(pos+2);
1594 0 : pos = hash.find("-dirty");
1595 0 : if (pos != std::string::npos) {
1596 0 : hash = hash.substr(0, pos);
1597 : }
1598 0 : pos = hash.find(" ");
1599 0 : if (pos != std::string::npos) {
1600 0 : hash = hash.substr(0, pos);
1601 : }
1602 0 : url += hash;
1603 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"%s\">%s</a></td>\n", url.c_str(), rev.c_str());
1604 0 : } else {
1605 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", rev.c_str());
1606 : }
1607 0 : r->rsprintf(" </tr>\n");
1608 :
1609 0 : r->rsprintf(" <tr>\n");
1610 0 : r->rsprintf(" <td style=\"text-align:right;\">MIDASSYS:</td>\n");
1611 0 : s = getenv("MIDASSYS");
1612 0 : if (!s) s = "(unset)";
1613 0 : mstrlcpy(str, s, sizeof(str));
1614 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", str);
1615 0 : r->rsprintf(" </tr>\n");
1616 :
1617 0 : r->rsprintf(" <tr>\n");
1618 0 : r->rsprintf(" <td style=\"text-align:right;\">mhttpd current directory:</td>\n");
1619 0 : std::string cwd = ss_getcwd();
1620 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cwd.c_str());
1621 0 : r->rsprintf(" </tr>\n");
1622 :
1623 0 : r->rsprintf(" <tr>\n");
1624 0 : r->rsprintf(" <td style=\"text-align:right;\">Exptab file:</td>\n");
1625 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_exptab_filename().c_str());
1626 0 : r->rsprintf(" </tr>\n");
1627 :
1628 0 : r->rsprintf(" <tr>\n");
1629 0 : r->rsprintf(" <td style=\"text-align:right;\">Experiment:</td>\n");
1630 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_experiment_name().c_str());
1631 0 : r->rsprintf(" </tr>\n");
1632 :
1633 0 : r->rsprintf(" <tr>\n");
1634 0 : r->rsprintf(" <td style=\"text-align:right;\">Experiment directory:</td>\n");
1635 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_path().c_str());
1636 0 : r->rsprintf(" </tr>\n");
1637 :
1638 0 : STRING_LIST list;
1639 0 : status = cm_msg_facilities(&list);
1640 :
1641 0 : if (status == CM_SUCCESS) {
1642 0 : if (list.size() == 1) {
1643 0 : r->rsprintf(" <tr>\n");
1644 0 : r->rsprintf(" <td style=\"text-align:right;\">System logfile:</td>\n");
1645 0 : std::string s;
1646 0 : cm_msg_get_logfile("midas", 0, &s, NULL, NULL);
1647 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", s.c_str());
1648 0 : r->rsprintf(" </tr>\n");
1649 0 : } else {
1650 0 : r->rsprintf(" <tr>\n");
1651 0 : r->rsprintf(" <td style=\"text-align:right;\">Logfiles:</td>\n");
1652 0 : r->rsprintf(" <td style=\"text-align:left;\">\n");
1653 0 : for (unsigned i=0 ; i<list.size() ; i++) {
1654 0 : if (i>0)
1655 0 : r->rsputs("<br />\n");
1656 0 : std::string s;
1657 0 : cm_msg_get_logfile(list[i].c_str(), 0, &s, NULL, NULL);
1658 0 : r->rsputs(s.c_str());
1659 0 : }
1660 0 : r->rsprintf("\n </td>\n");
1661 0 : r->rsprintf(" </tr>\n");
1662 : }
1663 : }
1664 :
1665 0 : r->rsprintf(" <tr>\n");
1666 0 : r->rsprintf(" <td style=\"text-align:right;\">Image history:</td>\n");
1667 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_history_path("IMAGE").c_str());
1668 0 : r->rsprintf(" </tr>\n");
1669 :
1670 0 : r->rsprintf(" <tr>\n");
1671 0 : r->rsprintf(" <td style=\"text-align:right;\">Resource paths:</td>\n");
1672 0 : r->rsprintf(" <td style=\"text-align:left;\">");
1673 0 : std::vector<std::string> resource_paths = get_resource_paths();
1674 0 : for (unsigned i=0; i<resource_paths.size(); i++) {
1675 0 : if (i>0)
1676 0 : r->rsputs("<br>");
1677 0 : r->rsputs(resource_paths[i].c_str());
1678 0 : std::string exp = cm_expand_env(resource_paths[i].c_str());
1679 : //printf("%d %d [%s] [%s]\n", resource_paths[i].length(), exp.length(), resource_paths[i].c_str(), exp.c_str());
1680 0 : if (exp != resource_paths[i]) {
1681 0 : r->rsputs(" (");
1682 0 : r->rsputs(exp.c_str());
1683 0 : r->rsputs(")");
1684 : }
1685 0 : }
1686 0 : r->rsprintf(" </td>\n");
1687 0 : r->rsprintf(" </tr>\n");
1688 :
1689 0 : std::string path;
1690 :
1691 0 : r->rsprintf(" <tr>\n");
1692 0 : r->rsprintf(" <td style=\"text-align:right;\">midas.css:</td>\n");
1693 0 : if (open_resource_file("midas.css", &path, NULL))
1694 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1695 : else
1696 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1697 0 : r->rsprintf(" </tr>\n");
1698 :
1699 0 : r->rsprintf(" <tr>\n");
1700 0 : r->rsprintf(" <td style=\"text-align:right;\">midas.js:</td>\n");
1701 0 : if (open_resource_file("midas.js", &path, NULL))
1702 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1703 : else
1704 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1705 0 : r->rsprintf(" </tr>\n");
1706 :
1707 0 : r->rsprintf(" <tr>\n");
1708 0 : r->rsprintf(" <td style=\"text-align:right;\">controls.js:</td>\n");
1709 0 : if (open_resource_file("controls.js", &path, NULL))
1710 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1711 : else
1712 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1713 0 : r->rsprintf(" </tr>\n");
1714 :
1715 0 : r->rsprintf(" <tr>\n");
1716 0 : r->rsprintf(" <td style=\"text-align:right;\">mhttpd.js:</td>\n");
1717 0 : if (open_resource_file("mhttpd.js", &path, NULL))
1718 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1719 : else
1720 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1721 0 : r->rsprintf(" </tr>\n");
1722 :
1723 0 : r->rsprintf(" <tr>\n");
1724 0 : r->rsprintf(" <td style=\"text-align:right;\">obsolete.js:</td>\n");
1725 0 : if (open_resource_file("obsolete.js", &path, NULL))
1726 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1727 : else
1728 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1729 0 : r->rsprintf(" </tr>\n");
1730 :
1731 0 : r->rsprintf(" <tr>\n");
1732 0 : r->rsprintf(" <td style=\"text-align:right;\">Obsolete mhttpd.css:</td>\n");
1733 0 : if (open_resource_file("mhttpd.css", &path, NULL))
1734 0 : r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1735 : else
1736 0 : r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1737 0 : r->rsprintf(" </tr>\n");
1738 :
1739 0 : r->rsprintf(" <tr>\n");
1740 0 : r->rsprintf(" <td style=\"text-align:right;\">JSON-RPC schema:</td>\n");
1741 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?mjsonrpc_schema\">json format</a> or <a href=\"?mjsonrpc_schema_text\">text table format</a></td>\n");
1742 0 : r->rsprintf(" </tr>\n");
1743 :
1744 0 : r->rsprintf(" <tr>\n");
1745 0 : r->rsprintf(" <td style=\"text-align:right;\">JavaScript examples:</td>\n");
1746 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=example\">example.html</a></td>\n");
1747 0 : r->rsprintf(" </tr>\n");
1748 :
1749 0 : r->rsprintf(" <tr>\n");
1750 0 : r->rsprintf(" <td style=\"text-align:right;\">Custom page example:</td>\n");
1751 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=custom_example\">custom_example.html</a></td>\n");
1752 0 : r->rsprintf(" </tr>\n");
1753 :
1754 0 : r->rsprintf(" <tr>\n");
1755 0 : r->rsprintf(" <td style=\"text-align:right;\">MPlot custom plot examples:</td>\n");
1756 0 : r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=plot_example\">plot_example.html</a></td>\n");
1757 0 : r->rsprintf(" </tr>\n");
1758 :
1759 0 : r->rsprintf(" </table>\n");
1760 0 : r->rsprintf(" </td>\n");
1761 0 : r->rsprintf(" </tr>\n");
1762 0 : r->rsprintf("</table>\n");
1763 :
1764 0 : r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1765 0 : r->rsprintf(" <tr>\n");
1766 0 : r->rsprintf(" <td class=\"mtableheader\">Contributions</td>\n");
1767 0 : r->rsprintf(" </tr>\n");
1768 0 : r->rsprintf(" <tr>\n");
1769 0 : r->rsprintf(" <td>\n");
1770 0 : r->rsprintf("Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Thomas Lindner - Shuoyi Ma - Rudi Meier - Bill Mills - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Chris Pearson - Renee Poutissou - Stefan Ritt - Zaher Salman - Ryu Sawada - Tamsen Schurman - Ben Smith - Andreas Suter - Jan M. Wouters - Piotr Adam Zolnierczuk\n");
1771 0 : r->rsprintf(" </td>\n");
1772 0 : r->rsprintf(" </tr>\n");
1773 0 : r->rsprintf("</table>\n");
1774 :
1775 0 : r->rsprintf("</div></form>\n");
1776 0 : r->rsprintf("</body></html>\r\n");
1777 0 : }
1778 :
1779 : /*------------------------------------------------------------------*/
1780 :
1781 0 : void show_header(Return* r, const char *title, const char *method, const char *path, int refresh)
1782 : {
1783 : HNDLE hDB;
1784 : time_t now;
1785 : char str[256];
1786 :
1787 0 : cm_get_experiment_database(&hDB, NULL);
1788 :
1789 : /* header */
1790 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1791 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1792 0 : r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1793 0 : r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1794 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1795 :
1796 0 : r->rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
1797 0 : r->rsprintf("<html><head>\n");
1798 :
1799 : /* style sheet */
1800 0 : r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
1801 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1802 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
1803 :
1804 : /* auto refresh */
1805 0 : if (refresh > 0)
1806 0 : r->rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
1807 :
1808 0 : r->rsprintf("<title>%s</title></head>\n", title);
1809 :
1810 0 : mstrlcpy(str, path, sizeof(str));
1811 0 : urlEncode(str, sizeof(str));
1812 :
1813 0 : if (equal_ustring(method, "POST"))
1814 : r->rsprintf
1815 0 : ("<body><form name=\"form1\" method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n\n",
1816 : str);
1817 0 : else if (equal_ustring(method, "GET"))
1818 0 : r->rsprintf("<body><form name=\"form1\" method=\"GET\" action=\"%s\">\n\n", str);
1819 :
1820 : /* title row */
1821 :
1822 0 : std::string exptname;
1823 0 : db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
1824 0 : time(&now);
1825 0 : }
1826 :
1827 : /*------------------------------------------------------------------*/
1828 :
1829 0 : void show_text_header(Return* r)
1830 : {
1831 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1832 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1833 0 : r->rsprintf("Access-Control-Allow-Origin: *\r\n");
1834 0 : r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1835 0 : r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1836 0 : r->rsprintf("Content-Type: text/plain; charset=%s\r\n\r\n", HTTP_ENCODING);
1837 0 : }
1838 :
1839 : /*------------------------------------------------------------------*/
1840 :
1841 0 : void show_error(Return* r, const char *error)
1842 : {
1843 : /* header */
1844 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1845 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1846 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1847 :
1848 0 : r->rsprintf("<html><head>\n");
1849 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1850 0 : r->rsprintf("<title>MIDAS error</title></head>\n");
1851 0 : r->rsprintf("<body><H1>%s</H1></body></html>\n", error);
1852 0 : }
1853 :
1854 : /*------------------------------------------------------------------*/
1855 :
1856 0 : void show_error_404(Return* r, const char *error)
1857 : {
1858 : /* header */
1859 0 : r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1860 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1861 0 : r->rsprintf("Content-Type: text/plain\r\n");
1862 0 : r->rsprintf("\r\n");
1863 :
1864 0 : r->rsprintf("MIDAS error: %s\n", error);
1865 0 : }
1866 :
1867 : /*------------------------------------------------------------------*/
1868 :
1869 0 : void show_navigation_bar(Return* r, const char *cur_page)
1870 : {
1871 0 : r->rsprintf("<script>\n");
1872 0 : r->rsprintf("window.addEventListener(\"load\", function(e) { mhttpd_init('%s', 1000); });\n", cur_page);
1873 0 : r->rsprintf("</script>\n");
1874 :
1875 0 : r->rsprintf("<!-- header and side navigation will be filled in mhttpd_init -->\n");
1876 0 : r->rsprintf("<div id=\"mheader\"></div>\n");
1877 0 : r->rsprintf("<div id=\"msidenav\"></div>\n");
1878 0 : r->rsprintf("<div id=\"mmain\">\n");
1879 0 : }
1880 :
1881 : /*------------------------------------------------------------------*/
1882 :
1883 0 : void check_obsolete_odb(HNDLE hDB, const char* odb_path)
1884 : {
1885 : HNDLE hKey;
1886 0 : int status = db_find_key(hDB, 0, odb_path, &hKey);
1887 0 : if (status == DB_SUCCESS) {
1888 0 : cm_msg(MERROR, "check_obsolete_odb", "ODB \"%s\" is obsolete, please delete it.", odb_path);
1889 : }
1890 0 : }
1891 :
1892 0 : void init_menu_buttons(MVOdb* odb)
1893 : {
1894 : HNDLE hDB;
1895 0 : BOOL true_value = TRUE;
1896 0 : BOOL false_value = FALSE;
1897 0 : int size = sizeof(true_value);
1898 0 : cm_get_experiment_database(&hDB, NULL);
1899 0 : db_get_value(hDB, 0, "/Experiment/Menu/Status", &true_value, &size, TID_BOOL, TRUE);
1900 0 : db_get_value(hDB, 0, "/Experiment/Menu/Start", &false_value, &size, TID_BOOL, TRUE);
1901 0 : db_get_value(hDB, 0, "/Experiment/Menu/Transition", &true_value, &size, TID_BOOL, TRUE);
1902 0 : db_get_value(hDB, 0, "/Experiment/Menu/ODB", &true_value, &size, TID_BOOL, TRUE);
1903 0 : db_get_value(hDB, 0, "/Experiment/Menu/OldODB", &true_value, &size, TID_BOOL, TRUE);
1904 0 : db_get_value(hDB, 0, "/Experiment/Menu/Messages", &true_value, &size, TID_BOOL, TRUE);
1905 0 : db_get_value(hDB, 0, "/Experiment/Menu/Chat", &true_value, &size, TID_BOOL, TRUE);
1906 0 : db_get_value(hDB, 0, "/Experiment/Menu/Elog", &true_value, &size, TID_BOOL, TRUE);
1907 0 : db_get_value(hDB, 0, "/Experiment/Menu/Alarms", &true_value, &size, TID_BOOL, TRUE);
1908 0 : db_get_value(hDB, 0, "/Experiment/Menu/Programs", &true_value, &size, TID_BOOL, TRUE);
1909 0 : db_get_value(hDB, 0, "/Experiment/Menu/Buffers", &true_value, &size, TID_BOOL, TRUE);
1910 0 : db_get_value(hDB, 0, "/Experiment/Menu/History", &true_value, &size, TID_BOOL, TRUE);
1911 0 : db_get_value(hDB, 0, "/Experiment/Menu/OldHistory", &true_value, &size, TID_BOOL, TRUE);
1912 0 : db_get_value(hDB, 0, "/Experiment/Menu/MSCB", &true_value, &size, TID_BOOL, TRUE);
1913 0 : db_get_value(hDB, 0, "/Experiment/Menu/Sequencer", &true_value, &size, TID_BOOL, TRUE);
1914 0 : db_get_value(hDB, 0, "/Experiment/Menu/PySequencer",&true_value, &size, TID_BOOL, TRUE);
1915 0 : db_get_value(hDB, 0, "/Experiment/Menu/Event Dump", &true_value, &size, TID_BOOL, TRUE);
1916 0 : db_get_value(hDB, 0, "/Experiment/Menu/Config", &true_value, &size, TID_BOOL, TRUE);
1917 0 : db_get_value(hDB, 0, "/Experiment/Menu/Example", &false_value, &size, TID_BOOL, TRUE);
1918 0 : db_get_value(hDB, 0, "/Experiment/Menu/Help", &true_value, &size, TID_BOOL, TRUE);
1919 :
1920 : //std::string buf;
1921 : //status = db_get_value_string(hDB, 0, "/Experiment/Menu buttons", 0, &buf, FALSE);
1922 : //if (status == DB_SUCCESS) {
1923 : // cm_msg(MERROR, "init_menu_buttons", "ODB \"/Experiment/Menu buttons\" is obsolete, please delete it.");
1924 : //}
1925 :
1926 0 : check_obsolete_odb(hDB, "/Experiment/Menu buttons");
1927 0 : check_obsolete_odb(hDB, "/Experiment/Menu/OldSequencer");
1928 0 : check_obsolete_odb(hDB, "/Experiment/Menu/NewSequencer");
1929 0 : }
1930 :
1931 : /*------------------------------------------------------------------*/
1932 :
1933 0 : void init_mhttpd_odb(MVOdb* odb)
1934 : {
1935 : HNDLE hDB;
1936 : HNDLE hKey;
1937 : int status;
1938 0 : std::string s;
1939 0 : cm_get_experiment_database(&hDB, NULL);
1940 :
1941 0 : status = db_find_key(hDB, 0, "/Experiment/Base URL", &hKey);
1942 0 : if (status == DB_SUCCESS) {
1943 0 : cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Base URL\" is obsolete, please delete it.");
1944 : }
1945 :
1946 0 : status = db_find_key(hDB, 0, "/Experiment/CSS File", &hKey);
1947 0 : if (status == DB_SUCCESS) {
1948 0 : cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/CSS File\" is obsolete, please delete it.");
1949 : }
1950 :
1951 0 : status = db_find_key(hDB, 0, "/Experiment/JS File", &hKey);
1952 0 : if (status == DB_SUCCESS) {
1953 0 : cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/JS File\" is obsolete, please delete it.");
1954 : }
1955 :
1956 0 : status = db_find_key(hDB, 0, "/Experiment/Start-Stop Buttons", &hKey);
1957 0 : if (status == DB_SUCCESS) {
1958 0 : cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Start-Stop Buttons\" is obsolete, please delete it.");
1959 : }
1960 :
1961 0 : bool xdefault = true;
1962 0 : odb->RB("Experiment/Pause-Resume Buttons", &xdefault, true);
1963 :
1964 : #ifdef HAVE_MONGOOSE616
1965 0 : check_obsolete_odb(hDB, "/Experiment/midas http port");
1966 0 : check_obsolete_odb(hDB, "/Experiment/midas https port");
1967 0 : check_obsolete_odb(hDB, "/Experiment/http redirect to https");
1968 0 : check_obsolete_odb(hDB, "/Experiment/Security/mhttpd hosts");
1969 : #endif
1970 :
1971 0 : status = db_find_key(hDB, 0, "/Logger/Message file", &hKey);
1972 0 : if (status == DB_SUCCESS) {
1973 0 : cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Logger/Message file\" is obsolete, please delete it and use \"/Logger/Message dir\" and \"/Logger/message file date format\" instead.");
1974 : }
1975 :
1976 0 : check_obsolete_odb(hDB, "/Logger/Watchdog timeout");
1977 0 : }
1978 :
1979 : /*------------------------------------------------------------------*/
1980 :
1981 0 : void init_elog_odb()
1982 : {
1983 : HNDLE hDB;
1984 : int size;
1985 : HNDLE hkey;
1986 0 : cm_get_experiment_database(&hDB, NULL);
1987 :
1988 0 : BOOL external_elog = FALSE;
1989 0 : std::string external_elog_url;
1990 :
1991 0 : size = sizeof(external_elog);
1992 0 : db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
1993 0 : db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
1994 :
1995 0 : BOOL allow_delete = FALSE;
1996 0 : BOOL allow_edit = FALSE;
1997 0 : size = sizeof(BOOL);
1998 0 : db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
1999 0 : db_get_value(hDB, 0, "/Elog/Allow edit", &allow_edit, &size, TID_BOOL, TRUE);
2000 : //db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL, TRUE);
2001 :
2002 0 : if (db_find_key(hDB, 0, "/Elog/Buttons", &hkey) != DB_SUCCESS) {
2003 0 : const char def_button[][NAME_LENGTH] = { "8h", "24h", "7d" };
2004 0 : db_set_value(hDB, 0, "/Elog/Buttons", def_button, NAME_LENGTH*3, 3, TID_STRING);
2005 : }
2006 :
2007 :
2008 : /* get type list from ODB */
2009 0 : size = 20 * NAME_LENGTH;
2010 0 : if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS) {
2011 0 : db_set_value(hDB, 0, "/Elog/Types", default_type_list, NAME_LENGTH * 20, 20, TID_STRING);
2012 : }
2013 :
2014 : /* get system list from ODB */
2015 0 : size = 20 * NAME_LENGTH;
2016 0 : if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
2017 0 : db_set_value(hDB, 0, "/Elog/Systems", default_system_list, NAME_LENGTH * 20, 20, TID_STRING);
2018 0 : }
2019 :
2020 : /*------------------------------------------------------------------*/
2021 :
2022 0 : void strencode(Return* r, const char *text)
2023 : {
2024 0 : size_t len = strlen(text);
2025 0 : for (size_t i = 0; i < len; i++) {
2026 0 : switch (text[i]) {
2027 0 : case '\n':
2028 0 : r->rsprintf("<br>\n");
2029 0 : break;
2030 0 : case '<':
2031 0 : r->rsprintf("<");
2032 0 : break;
2033 0 : case '>':
2034 0 : r->rsprintf(">");
2035 0 : break;
2036 0 : case '&':
2037 0 : r->rsprintf("&");
2038 0 : break;
2039 0 : case '\"':
2040 0 : r->rsprintf(""");
2041 0 : break;
2042 0 : default:
2043 0 : r->rsprintf("%c", text[i]);
2044 : }
2045 : }
2046 0 : }
2047 :
2048 : /*------------------------------------------------------------------*/
2049 :
2050 0 : std::string strencode2(const char *text)
2051 : {
2052 0 : std::string b;
2053 0 : size_t len = strlen(text);
2054 0 : for (size_t i = 0; i < len; i++) {
2055 0 : switch (text[i]) {
2056 0 : case '\n':
2057 0 : b += "<br>\n";
2058 0 : break;
2059 0 : case '<':
2060 0 : b += "<";
2061 0 : break;
2062 0 : case '>':
2063 0 : b += ">";
2064 0 : break;
2065 0 : case '&':
2066 0 : b += "&";
2067 0 : break;
2068 0 : case '\"':
2069 0 : b += """;
2070 0 : break;
2071 0 : default:
2072 0 : b += text[i];
2073 0 : break;
2074 : }
2075 : }
2076 0 : return b;
2077 0 : }
2078 :
2079 : /*------------------------------------------------------------------*/
2080 :
2081 0 : void strencode3(Return* r, const char *text)
2082 : {
2083 0 : size_t len = strlen(text);
2084 0 : for (size_t i = 0; i < len; i++) {
2085 0 : switch (text[i]) {
2086 0 : case '<':
2087 0 : r->rsprintf("<");
2088 0 : break;
2089 0 : case '>':
2090 0 : r->rsprintf(">");
2091 0 : break;
2092 0 : case '&':
2093 0 : r->rsprintf("&");
2094 0 : break;
2095 0 : case '\"':
2096 0 : r->rsprintf(""");
2097 0 : break;
2098 0 : default:
2099 0 : r->rsprintf("%c", text[i]);
2100 : }
2101 : }
2102 0 : }
2103 :
2104 : /*------------------------------------------------------------------*/
2105 :
2106 0 : void strencode4(Return* r, const char *text)
2107 : {
2108 0 : size_t len = strlen(text);
2109 0 : for (size_t i = 0; i < len; i++) {
2110 0 : switch (text[i]) {
2111 0 : case '\n':
2112 0 : r->rsprintf("<br>\n");
2113 0 : break;
2114 0 : case '<':
2115 0 : r->rsprintf("<");
2116 0 : break;
2117 0 : case '>':
2118 0 : r->rsprintf(">");
2119 0 : break;
2120 0 : case '&':
2121 0 : r->rsprintf("&");
2122 0 : break;
2123 0 : case '\"':
2124 0 : r->rsprintf(""");
2125 0 : break;
2126 0 : case ' ':
2127 0 : r->rsprintf(" ");
2128 0 : break;
2129 0 : default:
2130 0 : r->rsprintf("%c", text[i]);
2131 : }
2132 : }
2133 0 : }
2134 :
2135 : /*------------------------------------------------------------------*/
2136 :
2137 0 : void gen_odb_attachment(Return* r, const char *path, std::string& bout)
2138 : {
2139 : HNDLE hDB, hkeyroot, hkey;
2140 : KEY key;
2141 : INT i, j, size;
2142 : char data[1024];
2143 : time_t now;
2144 :
2145 0 : cm_get_experiment_database(&hDB, NULL);
2146 0 : db_find_key(hDB, 0, path, &hkeyroot);
2147 0 : assert(hkeyroot);
2148 :
2149 : /* title row */
2150 : //size = sizeof(str);
2151 : //str[0] = 0;
2152 : //db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
2153 0 : time(&now);
2154 :
2155 0 : bout += "<table border=3 cellpadding=1 class=\"dialogTable\">\n";
2156 : char ctimebuf[32];
2157 0 : ctime_r(&now, ctimebuf);
2158 0 : bout += msprintf("<tr><th colspan=2>%s</tr>\n", ctimebuf);
2159 0 : bout += msprintf("<tr><th colspan=2>%s</tr>\n", path);
2160 :
2161 : /* enumerate subkeys */
2162 0 : for (i = 0;; i++) {
2163 0 : db_enum_link(hDB, hkeyroot, i, &hkey);
2164 0 : if (!hkey)
2165 0 : break;
2166 0 : db_get_key(hDB, hkey, &key);
2167 :
2168 : /* resolve links */
2169 0 : if (key.type == TID_LINK) {
2170 0 : db_enum_key(hDB, hkeyroot, i, &hkey);
2171 0 : db_get_key(hDB, hkey, &key);
2172 : }
2173 :
2174 0 : if (key.type == TID_KEY) {
2175 : /* for keys, don't display data value */
2176 0 : bout += msprintf("<tr><td colspan=2>%s</td></tr>\n", key.name);
2177 : } else {
2178 : /* display single value */
2179 0 : if (key.num_values == 1) {
2180 0 : size = sizeof(data);
2181 0 : db_get_data(hDB, hkey, data, &size, key.type);
2182 : //printf("data size %d [%s]\n", size, data);
2183 0 : std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2184 0 : std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2185 :
2186 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2187 0 : data_str = "(empty)";
2188 0 : hex_str = "";
2189 : }
2190 :
2191 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2192 : //sprintf(b, "<tr><td>%s</td><td>%s (%s)</td></tr>\n", key.name, data_str, hex_str);
2193 0 : bout += "<tr><td>";
2194 0 : bout += key.name;
2195 0 : bout += "</td><td>";
2196 0 : bout += data_str;
2197 0 : bout += " (";
2198 0 : bout += hex_str;
2199 0 : bout += ")</td></tr>\n";
2200 : } else {
2201 0 : bout += msprintf("<tr><td>%s</td><td>", key.name);
2202 0 : bout += strencode2(data_str.c_str());
2203 0 : bout += "</td></tr>\n";
2204 : }
2205 0 : } else {
2206 : /* display first value */
2207 0 : bout += msprintf("<tr><td rowspan=%d>%s</td>\n", key.num_values, key.name);
2208 :
2209 0 : for (j = 0; j < key.num_values; j++) {
2210 0 : size = sizeof(data);
2211 0 : db_get_data_index(hDB, hkey, data, &size, j, key.type);
2212 0 : std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2213 0 : std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2214 :
2215 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2216 0 : data_str = "(empty)";
2217 0 : hex_str = "";
2218 : }
2219 :
2220 0 : if (j > 0) {
2221 0 : bout += "<tr>";
2222 : }
2223 :
2224 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2225 : //sprintf(b, "<td>[%d] %s (%s)<br></td></tr>\n", j, data_str, hex_str);
2226 0 : bout += "<td>[";
2227 0 : bout += toString(j);
2228 0 : bout += "] ";
2229 0 : bout += data_str;
2230 0 : bout += " (";
2231 0 : bout += hex_str;
2232 0 : bout += ")<br></td></tr>\n";
2233 : } else {
2234 : //sprintf(b, "<td>[%d] %s<br></td></tr>\n", j, data_str);
2235 0 : bout += "<td>[";
2236 0 : bout += toString(j);
2237 0 : bout += "] ";
2238 0 : bout += data_str;
2239 0 : bout += "<br></td></tr>\n";
2240 : }
2241 0 : }
2242 : }
2243 : }
2244 0 : }
2245 :
2246 0 : bout += "</table>\n";
2247 0 : }
2248 :
2249 : /*------------------------------------------------------------------*/
2250 :
2251 0 : void submit_elog(MVOdb* odb, Param* pp, Return* r, Attachment* a)
2252 : {
2253 : char path[256], path1[256];
2254 : char mail_to[256], mail_from[256], mail_list[256],
2255 : smtp_host[256], tag[80], mail_param[1000];
2256 : char *p, *pitem;
2257 : HNDLE hDB, hkey;
2258 : char att_file[3][256];
2259 : int fh, size, n_mail;
2260 : char mhttpd_full_url[256];
2261 :
2262 0 : cm_get_experiment_database(&hDB, NULL);
2263 0 : mstrlcpy(att_file[0], pp->getparam("attachment0"), sizeof(att_file[0]));
2264 0 : mstrlcpy(att_file[1], pp->getparam("attachment1"), sizeof(att_file[1]));
2265 0 : mstrlcpy(att_file[2], pp->getparam("attachment2"), sizeof(att_file[2]));
2266 :
2267 : /* check for valid attachment files */
2268 0 : for (int i = 0; i < 3; i++) {
2269 : char str[256];
2270 0 : sprintf(str, "attachment%d", i);
2271 : //printf("submit_elog: att %d, [%s] param [%s], size %d\n", i, str, pp->getparam(str), a->_attachment_size[i]);
2272 0 : if (pp->getparam(str) && *pp->getparam(str) && a->attachment_size[i] == 0) {
2273 : /* replace '\' by '/' */
2274 0 : mstrlcpy(path, pp->getparam(str), sizeof(path));
2275 0 : mstrlcpy(path1, path, sizeof(path1));
2276 0 : while (strchr(path, '\\'))
2277 0 : *strchr(path, '\\') = '/';
2278 :
2279 : /* check if valid ODB tree */
2280 0 : if (db_find_key(hDB, 0, path, &hkey) == DB_SUCCESS) {
2281 0 : std::string bout;
2282 0 : gen_odb_attachment(r, path, bout);
2283 0 : int bufsize = bout.length()+1;
2284 0 : char* buf = (char*)M_MALLOC(bufsize);
2285 0 : memcpy(buf, bout.c_str(), bufsize);
2286 0 : mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2287 0 : mstrlcat(att_file[i], ".html", sizeof(att_file[0]));
2288 0 : a->attachment_buffer[i] = buf;
2289 0 : a->attachment_size[i] = bufsize;
2290 0 : }
2291 : /* check if local file */
2292 0 : else if ((fh = open(path1, O_RDONLY | O_BINARY)) >= 0) {
2293 0 : size = lseek(fh, 0, SEEK_END);
2294 0 : char* buf = (char*)M_MALLOC(size);
2295 0 : lseek(fh, 0, SEEK_SET);
2296 0 : int rd = read(fh, buf, size);
2297 0 : if (rd < 0)
2298 0 : rd = 0;
2299 0 : close(fh);
2300 0 : mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2301 0 : a->attachment_buffer[i] = buf;
2302 0 : a->attachment_size[i] = rd;
2303 0 : } else if (strncmp(path, "/HS/", 4) == 0) {
2304 0 : char* buf = (char*)M_MALLOC(100000);
2305 0 : size = 100000;
2306 0 : mstrlcpy(str, path + 4, sizeof(str));
2307 0 : if (strchr(str, '?')) {
2308 0 : p = strchr(str, '?') + 1;
2309 0 : p = strtok(p, "&");
2310 0 : while (p != NULL) {
2311 0 : pitem = p;
2312 0 : p = strchr(p, '=');
2313 0 : if (p != NULL) {
2314 0 : *p++ = 0;
2315 0 : urlDecode(pitem); // parameter name
2316 0 : urlDecode(p); // parameter value
2317 :
2318 0 : pp->setparam(pitem, p);
2319 :
2320 0 : p = strtok(NULL, "&");
2321 : }
2322 : }
2323 0 : *strchr(str, '?') = 0;
2324 : }
2325 0 : show_hist_page(odb, pp, r, "image.gif", buf, &size, 0);
2326 0 : mstrlcpy(att_file[i], str, sizeof(att_file[0]));
2327 0 : a->attachment_buffer[i] = buf;
2328 0 : a->attachment_size[i] = size;
2329 0 : pp->unsetparam("scale");
2330 0 : pp->unsetparam("offset");
2331 0 : pp->unsetparam("width");
2332 0 : pp->unsetparam("index");
2333 : } else {
2334 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2335 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2336 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
2337 :
2338 0 : r->rsprintf("<html><head>\n");
2339 0 : r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
2340 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
2341 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
2342 0 : r->rsprintf("<title>ELog Error</title></head>\n");
2343 0 : r->rsprintf("<i>Error: Attachment file <i>%s</i> not valid.</i><p>\n", pp->getparam(str));
2344 0 : r->rsprintf("Please go back and enter a proper filename (use the <b>Browse</b> button).\n");
2345 0 : r->rsprintf("<body></body></html>\n");
2346 0 : return;
2347 : }
2348 : }
2349 : }
2350 :
2351 0 : int edit = atoi(pp->getparam("edit"));
2352 : //printf("submit_elog: edit [%s] %d, orig [%s]\n", pp->getparam("edit"), edit, pp->getparam("orig"));
2353 :
2354 0 : tag[0] = 0;
2355 0 : if (edit) {
2356 0 : mstrlcpy(tag, pp->getparam("orig"), sizeof(tag));
2357 : }
2358 :
2359 0 : int status = el_submit(atoi(pp->getparam("run")),
2360 : pp->getparam("author"),
2361 : pp->getparam("type"),
2362 : pp->getparam("system"),
2363 : pp->getparam("subject"),
2364 : pp->getparam("text"),
2365 : pp->getparam("orig"),
2366 0 : *pp->getparam("html") ? "HTML" : "plain",
2367 0 : att_file[0], a->attachment_buffer[0], a->attachment_size[0],
2368 0 : att_file[1], a->attachment_buffer[1], a->attachment_size[1],
2369 0 : att_file[2], a->attachment_buffer[2], a->attachment_size[2],
2370 : tag, sizeof(tag));
2371 :
2372 : //printf("el_submit status %d, tag [%s]\n", status, tag);
2373 :
2374 0 : if (status != EL_SUCCESS) {
2375 0 : cm_msg(MERROR, "submit_elog", "el_submit() returned status %d", status);
2376 : }
2377 :
2378 : /* supersede host name with "/Elog/Host name" */
2379 0 : std::string elog_host_name;
2380 0 : db_get_value_string(hDB, 0, "/Elog/Host name", 0, &elog_host_name, TRUE);
2381 :
2382 : // K.O. FIXME: we cannot guess the Elog URL like this because
2383 : // we do not know if access is through a proxy or redirect
2384 : // we do not know if it's http: or https:, etc. Better
2385 : // to read the whole "mhttpd_full_url" string from ODB.
2386 0 : sprintf(mhttpd_full_url, "http://%s/", elog_host_name.c_str());
2387 :
2388 : /* check for mail submissions */
2389 0 : mail_param[0] = 0;
2390 0 : n_mail = 0;
2391 :
2392 0 : for (int index = 0; index <= 1; index++) {
2393 0 : std::string str;
2394 0 : str += "/Elog/Email ";
2395 0 : if (index == 0)
2396 0 : str += pp->getparam("type");
2397 : else
2398 0 : str += pp->getparam("system");
2399 :
2400 0 : if (db_find_key(hDB, 0, str.c_str(), &hkey) == DB_SUCCESS) {
2401 0 : size = sizeof(mail_list);
2402 0 : db_get_data(hDB, hkey, mail_list, &size, TID_STRING);
2403 :
2404 0 : if (db_find_key(hDB, 0, "/Elog/SMTP host", &hkey) != DB_SUCCESS) {
2405 0 : show_error(r, "No SMTP host defined under /Elog/SMTP host");
2406 0 : return;
2407 : }
2408 0 : size = sizeof(smtp_host);
2409 0 : db_get_data(hDB, hkey, smtp_host, &size, TID_STRING);
2410 :
2411 0 : p = strtok(mail_list, ",");
2412 : while (1) {
2413 0 : mstrlcpy(mail_to, p, sizeof(mail_to));
2414 :
2415 0 : std::string exptname;
2416 0 : db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
2417 :
2418 0 : sprintf(mail_from, "MIDAS %s <MIDAS@%s>", exptname.c_str(), elog_host_name.c_str());
2419 :
2420 0 : std::string mail_text;
2421 0 : mail_text += "A new entry has been submitted by ";
2422 0 : mail_text += pp->getparam("author");
2423 0 : mail_text += "\n";
2424 0 : mail_text += "\n";
2425 :
2426 0 : mail_text += "Experiment : ";
2427 0 : mail_text += exptname.c_str();
2428 0 : mail_text += "\n";
2429 :
2430 0 : mail_text += "Type : ";
2431 0 : mail_text += pp->getparam("type");
2432 0 : mail_text += "\n";
2433 :
2434 0 : mail_text += "System : ";
2435 0 : mail_text += pp->getparam("system");
2436 0 : mail_text += "\n";
2437 :
2438 0 : mail_text += "Subject : ";
2439 0 : mail_text += pp->getparam("subject");
2440 0 : mail_text += "\n";
2441 :
2442 0 : mail_text += "Link : ";
2443 0 : mail_text += mhttpd_full_url;
2444 0 : mail_text += "/EL/";
2445 0 : mail_text += tag;
2446 0 : mail_text += "\n";
2447 :
2448 0 : mail_text += "\n";
2449 :
2450 0 : mail_text += pp->getparam("text");
2451 0 : mail_text += "\n";
2452 :
2453 0 : sendmail(elog_host_name.c_str(), smtp_host, mail_from, mail_to, pp->getparam("type"), mail_text.c_str());
2454 :
2455 0 : if (mail_param[0] == 0)
2456 0 : mstrlcpy(mail_param, "?", sizeof(mail_param));
2457 : else
2458 0 : mstrlcat(mail_param, "&", sizeof(mail_param));
2459 0 : sprintf(mail_param + strlen(mail_param), "mail%d=%s", n_mail++, mail_to);
2460 :
2461 0 : p = strtok(NULL, ",");
2462 0 : if (!p)
2463 0 : break;
2464 0 : while (*p == ' ')
2465 0 : p++;
2466 0 : }
2467 : }
2468 0 : }
2469 :
2470 0 : r->rsprintf("HTTP/1.1 302 Found\r\n");
2471 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2472 :
2473 : //if (mail_param[0])
2474 : // r->rsprintf("Location: ../EL/%s?%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2475 : //else
2476 : // r->rsprintf("Location: ../EL/%s\n\n<html>redir</html>\r\n", tag);
2477 :
2478 0 : if (mail_param[0])
2479 0 : r->rsprintf("Location: ?cmd=Show+elog&tag=%s&%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2480 : else
2481 0 : r->rsprintf("Location: ?cmd=Show+elog&tag=%s\n\n<html>redir</html>\r\n", tag);
2482 0 : }
2483 :
2484 : /*------------------------------------------------------------------*/
2485 :
2486 0 : void show_elog_attachment(Param* p, Return* r, const char* path)
2487 : {
2488 : HNDLE hDB;
2489 : int size;
2490 : int status;
2491 : char file_name[256];
2492 :
2493 0 : cm_get_experiment_database(&hDB, NULL);
2494 0 : file_name[0] = 0;
2495 0 : if (hDB > 0) {
2496 0 : size = sizeof(file_name);
2497 0 : memset(file_name, 0, size);
2498 :
2499 0 : status = db_get_value(hDB, 0, "/Logger/Elog dir", file_name, &size, TID_STRING, FALSE);
2500 0 : if (status != DB_SUCCESS)
2501 0 : db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
2502 :
2503 0 : if (file_name[0] != 0)
2504 0 : if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
2505 0 : mstrlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
2506 : }
2507 0 : mstrlcat(file_name, path, sizeof(file_name));
2508 :
2509 0 : int fh = open(file_name, O_RDONLY | O_BINARY);
2510 0 : if (fh > 0) {
2511 0 : lseek(fh, 0, SEEK_END);
2512 0 : int length = TELL(fh);
2513 0 : lseek(fh, 0, SEEK_SET);
2514 :
2515 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2516 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2517 0 : r->rsprintf("Accept-Ranges: bytes\r\n");
2518 : //r->rsprintf("Content-disposition: attachment; filename=%s\r\n", path);
2519 :
2520 0 : r->rsprintf("Content-Type: %s\r\n", get_content_type(file_name).c_str());
2521 :
2522 0 : r->rsprintf("Content-Length: %d\r\n\r\n", length);
2523 :
2524 0 : r->rread(file_name, fh, length);
2525 :
2526 0 : close(fh);
2527 : }
2528 :
2529 0 : return;
2530 : }
2531 :
2532 : /*------------------------------------------------------------------*/
2533 :
2534 0 : BOOL is_editable(char *eq_name, char *var_name)
2535 : {
2536 : HNDLE hDB, hkey;
2537 : KEY key;
2538 : char str[256];
2539 : int i, size;
2540 :
2541 0 : cm_get_experiment_database(&hDB, NULL);
2542 0 : sprintf(str, "/Equipment/%s/Settings/Editable", eq_name);
2543 0 : db_find_key(hDB, 0, str, &hkey);
2544 :
2545 : /* if no editable entry found, use default */
2546 0 : if (!hkey) {
2547 0 : return (equal_ustring(var_name, "Demand") ||
2548 0 : equal_ustring(var_name, "Output") || strncmp(var_name, "D_", 2) == 0);
2549 : }
2550 :
2551 0 : db_get_key(hDB, hkey, &key);
2552 0 : for (i = 0; i < key.num_values; i++) {
2553 0 : size = sizeof(str);
2554 0 : db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
2555 0 : if (equal_ustring(var_name, str))
2556 0 : return TRUE;
2557 : }
2558 0 : return FALSE;
2559 : }
2560 :
2561 : #ifdef OBSOLETE
2562 0 : void show_eqtable_page(Param* pp, Return* r, int refresh)
2563 : {
2564 : int i, j, k, colspan, size, n_var, i_edit, i_set, line;
2565 : char eq_name[32], group[32];
2566 : char group_name[MAX_GROUPS][32], data[256], style[80];
2567 : HNDLE hDB;
2568 : char odb_path[256];
2569 :
2570 0 : cm_get_experiment_database(&hDB, NULL);
2571 :
2572 : /* check if variable to edit */
2573 0 : i_edit = -1;
2574 0 : if (equal_ustring(pp->getparam("cmd"), "Edit"))
2575 0 : i_edit = atoi(pp->getparam("index"));
2576 :
2577 : /* check if variable to set */
2578 0 : i_set = -1;
2579 0 : if (equal_ustring(pp->getparam("cmd"), "Set"))
2580 0 : i_set = atoi(pp->getparam("index"));
2581 :
2582 : /* get equipment and group */
2583 0 : if (pp->getparam("eq"))
2584 0 : mstrlcpy(eq_name, pp->getparam("eq"), sizeof(eq_name));
2585 0 : mstrlcpy(group, "All", sizeof(group));
2586 0 : if (pp->getparam("group") && *pp->getparam("group"))
2587 0 : mstrlcpy(group, pp->getparam("group"), sizeof(group));
2588 :
2589 : #if 0
2590 : /* check for "names" in settings */
2591 : if (eq_name[0]) {
2592 : sprintf(str, "/Equipment/%s/Settings", eq_name);
2593 : HNDLE hkeyset;
2594 : db_find_key(hDB, 0, str, &hkeyset);
2595 : HNDLE hkeynames = 0;
2596 : if (hkeyset) {
2597 : for (i = 0;; i++) {
2598 : db_enum_link(hDB, hkeyset, i, &hkeynames);
2599 :
2600 : if (!hkeynames)
2601 : break;
2602 :
2603 : KEY key;
2604 : db_get_key(hDB, hkeynames, &key);
2605 :
2606 : if (strncmp(key.name, "Names", 5) == 0)
2607 : break;
2608 : }
2609 : }
2610 :
2611 : /* redirect if no names found */
2612 : if (!hkeyset || !hkeynames) {
2613 : /* redirect */
2614 : sprintf(str, "?cmd=odb&odb_path=/Equipment/%s/Variables", eq_name);
2615 : redirect(r, str);
2616 : return;
2617 : }
2618 : }
2619 : #endif
2620 :
2621 0 : show_header(r, "MIDAS slow control", "", group, i_edit == -1 ? refresh : 0);
2622 0 : r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
2623 0 : r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
2624 0 : r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
2625 0 : show_navigation_bar(r, "SC");
2626 :
2627 : /*---- menu buttons ----*/
2628 :
2629 0 : r->rsprintf("<tr><td colspan=15>\n");
2630 :
2631 0 : if (equal_ustring(pp->getparam("cmd"), "Edit"))
2632 0 : r->rsprintf("<input type=submit name=cmd value=Set>\n");
2633 :
2634 0 : r->rsprintf("</tr>\n\n");
2635 0 : r->rsprintf("</table>"); //end header table
2636 :
2637 0 : r->rsprintf("<table class=\"ODBtable\" style=\"max-width:700px;\">"); //body table
2638 :
2639 : /*---- enumerate SC equipment ----*/
2640 :
2641 0 : r->rsprintf("<tr><td class=\"subStatusTitle\" colspan=15><i>Equipment:</i> \n");
2642 :
2643 : HNDLE hkeyeqroot;
2644 0 : db_find_key(hDB, 0, "/Equipment", &hkeyeqroot);
2645 0 : if (hkeyeqroot)
2646 0 : for (i = 0;; i++) {
2647 : HNDLE hkeyeq;
2648 0 : db_enum_link(hDB, hkeyeqroot, i, &hkeyeq);
2649 :
2650 0 : if (!hkeyeq)
2651 0 : break;
2652 :
2653 : KEY eqkey;
2654 0 : db_get_key(hDB, hkeyeq, &eqkey);
2655 :
2656 : HNDLE hkeyset;
2657 0 : db_find_key(hDB, hkeyeq, "Settings", &hkeyset);
2658 0 : if (hkeyset) {
2659 0 : for (j = 0;; j++) {
2660 : HNDLE hkeynames;
2661 0 : db_enum_link(hDB, hkeyset, j, &hkeynames);
2662 :
2663 0 : if (!hkeynames)
2664 0 : break;
2665 :
2666 : KEY key;
2667 0 : db_get_key(hDB, hkeynames, &key);
2668 :
2669 0 : if (strncmp(key.name, "Names", 5) == 0) {
2670 0 : if (equal_ustring(eq_name, eqkey.name))
2671 0 : r->rsprintf("<b>%s</b> ", eqkey.name);
2672 : else {
2673 0 : r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">%s</a> ", urlEncode(eqkey.name).c_str(), eqkey.name);
2674 : }
2675 0 : break;
2676 : }
2677 0 : }
2678 : }
2679 0 : }
2680 0 : r->rsprintf("</tr>\n");
2681 :
2682 0 : if (!eq_name[0]) {
2683 0 : r->rsprintf("</table>");
2684 0 : return;
2685 : }
2686 :
2687 : /*---- display SC ----*/
2688 :
2689 0 : n_var = 0;
2690 0 : std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2691 : HNDLE hkeyeqnames;
2692 0 : db_find_key(hDB, 0, names_path.c_str(), &hkeyeqnames);
2693 :
2694 0 : if (hkeyeqnames) {
2695 :
2696 : /*---- single name array ----*/
2697 0 : r->rsprintf("<tr><td colspan=15><i>Groups:</i> ");
2698 :
2699 : /* "all" group */
2700 0 : if (equal_ustring(group, "All"))
2701 0 : r->rsprintf("<b>All</b> ");
2702 : else
2703 0 : r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> ", urlEncode(eq_name).c_str());
2704 :
2705 : /* collect groups */
2706 :
2707 0 : memset(group_name, 0, sizeof(group_name));
2708 : KEY key;
2709 0 : db_get_key(hDB, hkeyeqnames, &key);
2710 :
2711 0 : for (int level = 0; ; level++) {
2712 0 : bool next_level = false;
2713 0 : for (i = 0; i < key.num_values; i++) {
2714 : char name_str[256];
2715 0 : size = sizeof(name_str);
2716 0 : db_get_data_index(hDB, hkeyeqnames, name_str, &size, i, TID_STRING);
2717 :
2718 0 : char *s = strchr(name_str, '%');
2719 0 : for (int k=0; s && k<level; k++)
2720 0 : s = strchr(s+1, '%');
2721 :
2722 0 : if (s) {
2723 0 : *s = 0;
2724 0 : if (strchr(s+1, '%'))
2725 0 : next_level = true;
2726 :
2727 : //printf("try group [%s] name [%s], level %d, %d\n", name_str, s+1, level, next_level);
2728 :
2729 0 : for (j = 0; j < MAX_GROUPS; j++) {
2730 0 : if (equal_ustring(group_name[j], name_str) || group_name[j][0] == 0)
2731 0 : break;
2732 : }
2733 0 : if ((j < MAX_GROUPS) && (group_name[j][0] == 0))
2734 0 : mstrlcpy(group_name[j], name_str, sizeof(group_name[0]));
2735 : }
2736 : }
2737 :
2738 0 : if (!next_level)
2739 0 : break;
2740 0 : }
2741 :
2742 0 : for (i = 0; i < MAX_GROUPS && group_name[i][0]; i++) {
2743 0 : if (equal_ustring(group_name[i], group))
2744 0 : r->rsprintf("<b>%s</b> ", group_name[i]);
2745 : else {
2746 0 : r->rsprintf("<a href=\"?cmd=eqtable&eq=%s&group=%s\">%s</a> ", urlEncode(eq_name).c_str(), urlEncode(group_name[i]).c_str(), group_name[i]);
2747 : }
2748 : }
2749 :
2750 0 : r->rsprintf("<i>ODB:</i> ");
2751 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> ", urlEncode(eq_name).c_str());
2752 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> ", urlEncode(eq_name).c_str());
2753 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> ", urlEncode(eq_name).c_str());
2754 0 : r->rsprintf("</tr>\n");
2755 :
2756 : /* count variables */
2757 0 : std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2758 : HNDLE hkeyvar;
2759 0 : db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2760 0 : if (!hkeyvar) {
2761 0 : r->rsprintf("</table>");
2762 0 : return;
2763 : }
2764 0 : for (i = 0;; i++) {
2765 : HNDLE hkey;
2766 0 : db_enum_link(hDB, hkeyvar, i, &hkey);
2767 0 : if (!hkey)
2768 0 : break;
2769 0 : }
2770 :
2771 0 : if (i == 0 || i > 15) {
2772 0 : r->rsprintf("</table>");
2773 0 : return;
2774 : }
2775 :
2776 : /* title row */
2777 0 : colspan = 15 - i;
2778 0 : r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=%d>Names", colspan);
2779 :
2780 : /* display entries for this group */
2781 0 : for (int i = 0;; i++) {
2782 : HNDLE hkey;
2783 0 : db_enum_link(hDB, hkeyvar, i, &hkey);
2784 :
2785 0 : if (!hkey)
2786 0 : break;
2787 :
2788 : KEY key;
2789 0 : db_get_key(hDB, hkey, &key);
2790 0 : r->rsprintf("<th>%s", key.name);
2791 0 : }
2792 :
2793 0 : r->rsprintf("</tr>\n");
2794 :
2795 : /* data for current group */
2796 0 : std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2797 0 : int num_values = 0;
2798 : HNDLE hnames_key;
2799 0 : db_find_key(hDB, 0, names_path.c_str(), &hnames_key);
2800 0 : if (hnames_key) {
2801 : KEY names_key;
2802 0 : db_get_key(hDB, hnames_key, &names_key);
2803 0 : num_values = names_key.num_values;
2804 : }
2805 0 : for (int i = 0; i < num_values; i++) {
2806 : char names_str[256];
2807 0 : size = sizeof(names_str);
2808 0 : db_get_data_index(hDB, hnames_key, names_str, &size, i, TID_STRING);
2809 :
2810 : char name[NAME_LENGTH+32];
2811 0 : mstrlcpy(name, names_str, sizeof(name));
2812 :
2813 : //printf("group [%s], name [%s], str [%s]\n", group, name, names_str);
2814 :
2815 0 : if (!equal_ustring(group, "All")) {
2816 : // check if name starts with the name of the group we want to display
2817 0 : char *s = strstr(name, group);
2818 0 : if (s != name)
2819 0 : continue;
2820 0 : if (name[strlen(group)] != '%')
2821 0 : continue;
2822 : }
2823 :
2824 0 : if (strlen(name) < 1)
2825 0 : sprintf(name, "[%d]", i);
2826 :
2827 0 : if (i % 2 == 0)
2828 0 : r->rsprintf("<tr class=\"ODBtableEven\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2829 : else
2830 0 : r->rsprintf("<tr class=\"ODBtableOdd\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2831 :
2832 0 : for (int j = 0;; j++) {
2833 : HNDLE hkey;
2834 0 : db_enum_link(hDB, hkeyvar, j, &hkey);
2835 0 : if (!hkey)
2836 0 : break;
2837 :
2838 : KEY varkey;
2839 0 : db_get_key(hDB, hkey, &varkey);
2840 :
2841 : /* check if "variables" array is shorter than the "names" array */
2842 0 : if (i >= varkey.num_values)
2843 0 : continue;
2844 :
2845 0 : size = sizeof(data);
2846 0 : db_get_data_index(hDB, hkey, data, &size, i, varkey.type);
2847 0 : std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
2848 :
2849 0 : if (is_editable(eq_name, varkey.name)) {
2850 0 : if (n_var == i_set) {
2851 : /* set value */
2852 : char str[256];
2853 0 : mstrlcpy(str, pp->getparam("value"), sizeof(str));
2854 0 : db_sscanf(str, data, &size, 0, varkey.type);
2855 0 : db_set_data_index(hDB, hkey, data, size, i, varkey.type);
2856 :
2857 : /* redirect (so that 'reload' does not reset value) */
2858 0 : r->reset();
2859 0 : redirect(r, group);
2860 0 : return;
2861 : }
2862 0 : if (n_var == i_edit) {
2863 0 : r->rsprintf("<td align=center>");
2864 0 : r->rsprintf("<input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
2865 0 : r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
2866 0 : r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
2867 0 : n_var++;
2868 : } else {
2869 0 : sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, i);
2870 0 : r->rsprintf("<td align=center>");
2871 0 : r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
2872 0 : n_var++;
2873 : }
2874 : } else
2875 0 : r->rsprintf("<td align=center>%s", data_str.c_str());
2876 0 : }
2877 :
2878 0 : r->rsprintf("</tr>\n");
2879 : }
2880 0 : } else {
2881 : /*---- multiple name arrays ----*/
2882 0 : r->rsprintf("<tr><td colspan=15><i>Groups:</i> ");
2883 :
2884 : /* "all" group */
2885 0 : if (equal_ustring(group, "All"))
2886 0 : r->rsprintf("<b>All</b> ");
2887 : else
2888 0 : r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> ", eq_name);
2889 :
2890 : /* groups from Variables tree */
2891 :
2892 0 : std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2893 : HNDLE hkeyvar;
2894 0 : db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2895 :
2896 0 : if (hkeyvar) {
2897 0 : for (int i = 0;; i++) {
2898 : HNDLE hkey;
2899 0 : db_enum_link(hDB, hkeyvar, i, &hkey);
2900 :
2901 0 : if (!hkey)
2902 0 : break;
2903 :
2904 : KEY key;
2905 0 : db_get_key(hDB, hkey, &key);
2906 :
2907 0 : if (equal_ustring(key.name, group)) {
2908 0 : r->rsprintf("<b>%s</b> ", key.name);
2909 : } else {
2910 0 : r->rsprintf("<a href=\"?cmd=eqtable&eq=%s&group=%s\">%s</a> ", urlEncode(eq_name).c_str(), urlEncode(key.name).c_str(), key.name);
2911 : }
2912 0 : }
2913 : }
2914 :
2915 0 : r->rsprintf("<i>ODB:</i> ");
2916 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> ", urlEncode(eq_name).c_str());
2917 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> ", urlEncode(eq_name).c_str());
2918 0 : r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> ", urlEncode(eq_name).c_str());
2919 0 : r->rsprintf("</tr>\n");
2920 :
2921 : /* enumerate variable arrays */
2922 0 : line = 0;
2923 0 : for (i = 0;; i++) {
2924 : HNDLE hkey;
2925 0 : db_enum_link(hDB, hkeyvar, i, &hkey);
2926 :
2927 0 : if (line % 2 == 0)
2928 0 : mstrlcpy(style, "ODBtableEven", sizeof(style));
2929 : else
2930 0 : mstrlcpy(style, "ODBtableOdd", sizeof(style));
2931 :
2932 0 : if (!hkey)
2933 0 : break;
2934 :
2935 : KEY varkey;
2936 0 : db_get_key(hDB, hkey, &varkey);
2937 :
2938 0 : if (!equal_ustring(group, "All") && !equal_ustring(varkey.name, group))
2939 0 : continue;
2940 :
2941 : /* title row */
2942 0 : r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=9>Names<th>%s</tr>\n", varkey.name);
2943 :
2944 0 : if (varkey.type == TID_KEY) {
2945 0 : HNDLE hkeyroot = hkey;
2946 :
2947 : /* enumerate subkeys */
2948 0 : for (j = 0;; j++) {
2949 0 : db_enum_key(hDB, hkeyroot, j, &hkey);
2950 0 : if (!hkey)
2951 0 : break;
2952 :
2953 : KEY key;
2954 0 : db_get_key(hDB, hkey, &key);
2955 :
2956 0 : if (key.type == TID_KEY) {
2957 : /* for keys, don't display data value */
2958 0 : r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<br></tr>\n", style, key.name);
2959 : } else {
2960 : /* display single value */
2961 0 : if (key.num_values == 1) {
2962 0 : size = sizeof(data);
2963 0 : db_get_data(hDB, hkey, data, &size, key.type);
2964 :
2965 0 : std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2966 0 : std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2967 :
2968 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2969 0 : data_str = "(empty)";
2970 0 : hex_str = "";
2971 : }
2972 :
2973 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
2974 : r->rsprintf
2975 0 : ("<tr class=\"%s\" ><td colspan=9>%s<td align=center>%s (%s)<br></tr>\n",
2976 : style, key.name, data_str.c_str(), hex_str.c_str());
2977 : else
2978 0 : r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center>%s<br></tr>\n",
2979 : style, key.name, data_str.c_str());
2980 0 : line++;
2981 0 : } else {
2982 : /* display first value */
2983 0 : r->rsprintf("<tr class=\"%s\"><td colspan=9 rowspan=%d>%s\n", style, key.num_values,
2984 : key.name);
2985 :
2986 0 : for (k = 0; k < key.num_values; k++) {
2987 0 : size = sizeof(data);
2988 0 : db_get_data_index(hDB, hkey, data, &size, k, key.type);
2989 0 : std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2990 0 : std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2991 :
2992 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2993 0 : data_str = "(empty)";
2994 0 : hex_str = "";
2995 : }
2996 :
2997 0 : if (k > 0)
2998 0 : r->rsprintf("<tr>");
2999 :
3000 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
3001 0 : r->rsprintf("<td>[%d] %s (%s)<br></tr>\n", k, data_str.c_str(), hex_str.c_str());
3002 : else
3003 0 : r->rsprintf("<td>[%d] %s<br></tr>\n", k, data_str.c_str());
3004 0 : line++;
3005 0 : }
3006 : }
3007 : }
3008 0 : }
3009 : } else {
3010 : /* data for current group */
3011 0 : std::string names_path = msprintf("/Equipment/%s/Settings/Names %s", eq_name, varkey.name);
3012 : HNDLE hkeyset;
3013 0 : db_find_key(hDB, 0, names_path.c_str(), &hkeyset);
3014 : KEY key;
3015 0 : if (hkeyset)
3016 0 : db_get_key(hDB, hkeyset, &key);
3017 :
3018 0 : if (varkey.num_values > 1000)
3019 0 : r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center><i>... %d values ...</i>",
3020 : style, varkey.name, varkey.num_values);
3021 : else {
3022 0 : for (j = 0; j < varkey.num_values; j++) {
3023 :
3024 0 : if (line % 2 == 0)
3025 0 : mstrlcpy(style, "ODBtableEven", sizeof(style));
3026 : else
3027 0 : mstrlcpy(style, "ODBtableOdd", sizeof(style));
3028 :
3029 : char name[NAME_LENGTH+32];
3030 0 : if (hkeyset && j<key.num_values) {
3031 0 : size = sizeof(name);
3032 0 : db_get_data_index(hDB, hkeyset, name, &size, j, TID_STRING);
3033 : } else {
3034 0 : sprintf(name, "%s[%d]", varkey.name, j);
3035 : }
3036 :
3037 0 : if (strlen(name) < 1) {
3038 0 : sprintf(name, "%s[%d]", varkey.name, j);
3039 : }
3040 :
3041 0 : r->rsprintf("<tr class=\"%s\"><td colspan=9>%s", style, name);
3042 :
3043 0 : size = sizeof(data);
3044 0 : db_get_data_index(hDB, hkey, data, &size, j, varkey.type);
3045 0 : std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
3046 :
3047 0 : if (is_editable(eq_name, varkey.name)) {
3048 0 : if (n_var == i_set) {
3049 : /* set value */
3050 : char str[256];
3051 0 : mstrlcpy(str, pp->getparam("value"), sizeof(str));
3052 0 : db_sscanf(str, data, &size, 0, varkey.type);
3053 0 : db_set_data_index(hDB, hkey, data, size, j, varkey.type);
3054 :
3055 : /* redirect (so that 'reload' does not reset value) */
3056 0 : r->reset();
3057 0 : sprintf(str, "%s", group);
3058 0 : redirect(r, str);
3059 0 : return;
3060 : }
3061 0 : if (n_var == i_edit) {
3062 0 : r->rsprintf("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
3063 0 : r->rsprintf("<input type=submit size=20 name=cmd value=Set></tr>\n");
3064 0 : r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
3065 0 : r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3066 0 : n_var++;
3067 : } else {
3068 0 : sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, j);
3069 :
3070 0 : r->rsprintf("<td align=cernter>");
3071 0 : r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
3072 0 : n_var++;
3073 : }
3074 :
3075 : } else
3076 0 : r->rsprintf("<td align=center>%s\n", data_str.c_str());
3077 0 : r->rsprintf("</tr>\n");
3078 0 : line++;
3079 0 : }
3080 : }
3081 :
3082 0 : r->rsprintf("</tr>\n");
3083 0 : }
3084 0 : }
3085 0 : }
3086 :
3087 0 : r->rsprintf("</table>\n");
3088 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
3089 0 : r->rsprintf("</form>\n");
3090 0 : r->rsprintf("</body></html>\r\n");
3091 0 : }
3092 : #endif
3093 :
3094 : /*------------------------------------------------------------------*/
3095 :
3096 0 : char *find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
3097 : {
3098 : char str[256], *ps, *pt;
3099 : BOOL in_script;
3100 :
3101 0 : *edit = 0;
3102 0 : *tail = 0;
3103 0 : *format = 0;
3104 0 : pwd[0] = 0;
3105 0 : in_script = FALSE;
3106 0 : strcpy(type, "text");
3107 : do {
3108 0 : while (*p && *p != '<')
3109 0 : p++;
3110 :
3111 : /* return if end of string reached */
3112 0 : if (!*p)
3113 0 : return NULL;
3114 :
3115 0 : p++;
3116 0 : while (*p && ((*p == ' ') || iscntrl(*p)))
3117 0 : p++;
3118 :
3119 0 : strncpy(str, p, 6);
3120 0 : str[6] = 0;
3121 0 : if (equal_ustring(str, "script"))
3122 0 : in_script = TRUE;
3123 :
3124 0 : strncpy(str, p, 7);
3125 0 : str[7] = 0;
3126 0 : if (equal_ustring(str, "/script"))
3127 0 : in_script = FALSE;
3128 :
3129 0 : strncpy(str, p, 4);
3130 0 : str[4] = 0;
3131 0 : if (equal_ustring(str, "odb ")) {
3132 0 : ps = p - 1;
3133 0 : p += 4;
3134 0 : while (*p && ((*p == ' ') || iscntrl(*p)))
3135 0 : p++;
3136 :
3137 : do {
3138 0 : strncpy(str, p, 7);
3139 0 : str[7] = 0;
3140 0 : if (equal_ustring(str, "format=")) {
3141 0 : p += 7;
3142 0 : if (*p == '\"') {
3143 0 : p++;
3144 0 : while (*p && *p != '\"')
3145 0 : *format++ = *p++;
3146 0 : *format = 0;
3147 0 : if (*p == '\"')
3148 0 : p++;
3149 : } else {
3150 0 : while (*p && *p != ' ' && *p != '>')
3151 0 : *format++ = *p++;
3152 0 : *format = 0;
3153 : }
3154 :
3155 : } else {
3156 :
3157 0 : strncpy(str, p, 4);
3158 0 : str[4] = 0;
3159 0 : if (equal_ustring(str, "src=")) {
3160 0 : p += 4;
3161 0 : if (*p == '\"') {
3162 0 : p++;
3163 0 : while (*p && *p != '\"')
3164 0 : *path++ = *p++;
3165 0 : *path = 0;
3166 0 : if (*p == '\"')
3167 0 : p++;
3168 : } else {
3169 0 : while (*p && *p != ' ' && *p != '>')
3170 0 : *path++ = *p++;
3171 0 : *path = 0;
3172 : }
3173 : } else {
3174 :
3175 0 : if (in_script)
3176 0 : break;
3177 :
3178 0 : strncpy(str, p, 5);
3179 0 : str[5] = 0;
3180 0 : if (equal_ustring(str, "edit=")) {
3181 0 : p += 5;
3182 :
3183 0 : if (*p == '\"') {
3184 0 : p++;
3185 0 : *edit = atoi(p);
3186 0 : if (*p == '\"')
3187 0 : p++;
3188 : } else {
3189 0 : *edit = atoi(p);
3190 0 : while (*p && *p != ' ' && *p != '>')
3191 0 : p++;
3192 : }
3193 :
3194 : } else {
3195 :
3196 0 : strncpy(str, p, 5);
3197 0 : str[5] = 0;
3198 0 : if (equal_ustring(str, "type=")) {
3199 0 : p += 5;
3200 0 : if (*p == '\"') {
3201 0 : p++;
3202 0 : while (*p && *p != '\"')
3203 0 : *type++ = *p++;
3204 0 : *type = 0;
3205 0 : if (*p == '\"')
3206 0 : p++;
3207 : } else {
3208 0 : while (*p && *p != ' ' && *p != '>')
3209 0 : *type++ = *p++;
3210 0 : *type = 0;
3211 : }
3212 : } else {
3213 0 : strncpy(str, p, 4);
3214 0 : str[4] = 0;
3215 0 : if (equal_ustring(str, "pwd=")) {
3216 0 : p += 4;
3217 0 : if (*p == '\"') {
3218 0 : p++;
3219 0 : while (*p && *p != '\"')
3220 0 : *pwd++ = *p++;
3221 0 : *pwd = 0;
3222 0 : if (*p == '\"')
3223 0 : p++;
3224 : } else {
3225 0 : while (*p && *p != ' ' && *p != '>')
3226 0 : *pwd++ = *p++;
3227 0 : *pwd = 0;
3228 : }
3229 : } else {
3230 0 : if (strchr(p, '=')) {
3231 0 : mstrlcpy(str, p, sizeof(str));
3232 0 : pt = strchr(str, '=')+1;
3233 0 : if (*pt == '\"') {
3234 0 : pt++;
3235 0 : while (*pt && *pt != '\"')
3236 0 : pt++;
3237 0 : if (*pt == '\"')
3238 0 : pt++;
3239 0 : *pt = 0;
3240 : } else {
3241 0 : while (*pt && *pt != ' ' && *pt != '>')
3242 0 : pt++;
3243 0 : *pt = 0;
3244 : }
3245 0 : if (tail[0]) {
3246 0 : mstrlcat(tail, " ", 256);
3247 0 : mstrlcat(tail, str, 256);
3248 : } else {
3249 0 : mstrlcat(tail, str, 256);
3250 : }
3251 0 : p += strlen(str);
3252 : }
3253 : }
3254 : }
3255 : }
3256 : }
3257 : }
3258 :
3259 0 : while (*p && ((*p == ' ') || iscntrl(*p)))
3260 0 : p++;
3261 :
3262 0 : if (*p == '<') {
3263 0 : cm_msg(MERROR, "find_odb_tag", "Invalid odb tag '%s'", ps);
3264 0 : return NULL;
3265 : }
3266 0 : } while (*p != '>');
3267 :
3268 0 : return ps;
3269 : }
3270 :
3271 0 : while (*p && *p != '>')
3272 0 : p++;
3273 :
3274 : } while (1);
3275 :
3276 : }
3277 :
3278 : /*------------------------------------------------------------------*/
3279 :
3280 0 : void show_odb_tag(Param* pp, Return* r, const char *path, const char *keypath1, const char *format, int n_var, int edit, char *type, char *pwd, char *tail)
3281 : {
3282 : int size, index, i_edit, i_set;
3283 : char data[TEXT_SIZE], full_keypath[256], keypath[256], *p;
3284 : HNDLE hDB, hkey;
3285 : KEY key;
3286 :
3287 : /* check if variable to edit */
3288 0 : i_edit = -1;
3289 0 : if (equal_ustring(pp->getparam("cmd"), "Edit"))
3290 0 : i_edit = atoi(pp->getparam("index"));
3291 :
3292 : /* check if variable to set */
3293 0 : i_set = -1;
3294 0 : if (equal_ustring(pp->getparam("cmd"), "Set"))
3295 0 : i_set = atoi(pp->getparam("index"));
3296 :
3297 : /* check if path contains index */
3298 0 : mstrlcpy(full_keypath, keypath1, sizeof(full_keypath));
3299 0 : mstrlcpy(keypath, keypath1, sizeof(keypath));
3300 0 : index = 0;
3301 :
3302 0 : if (strchr(keypath, '[') && strchr(keypath, ']')) {
3303 0 : for (p = strchr(keypath, '[') + 1; *p && *p != ']'; p++)
3304 0 : if (!isdigit(*p))
3305 0 : break;
3306 :
3307 0 : if (*p && *p == ']') {
3308 0 : index = atoi(strchr(keypath, '[') + 1);
3309 0 : *strchr(keypath, '[') = 0;
3310 : }
3311 : }
3312 :
3313 0 : cm_get_experiment_database(&hDB, NULL);
3314 0 : db_find_key(hDB, 0, keypath, &hkey);
3315 0 : if (!hkey)
3316 0 : r->rsprintf("<b>Key \"%s\" not found in ODB</b>\n", keypath);
3317 : else {
3318 0 : db_get_key(hDB, hkey, &key);
3319 0 : size = sizeof(data);
3320 0 : db_get_data_index(hDB, hkey, data, &size, index, key.type);
3321 :
3322 0 : std::string data_str;
3323 0 : if (format && strlen(format)>0)
3324 0 : data_str = db_sprintff(format, data, key.item_size, 0, key.type);
3325 : else
3326 0 : data_str= db_sprintf(data, key.item_size, 0, key.type);
3327 :
3328 0 : if (equal_ustring(type, "checkbox")) {
3329 :
3330 0 : if (pp->isparam("cbi"))
3331 0 : i_set = atoi(pp->getparam("cbi"));
3332 0 : if (n_var == i_set) {
3333 : /* toggle state */
3334 0 : if (key.type == TID_BOOL) {
3335 0 : if (data_str[0] == 'y')
3336 0 : data_str = "n";
3337 : else
3338 0 : data_str = "y";
3339 : } else {
3340 0 : if (atoi(data_str.c_str()) > 0)
3341 0 : data_str = "0";
3342 : else
3343 0 : data_str = "1";
3344 : }
3345 :
3346 0 : db_sscanf(data_str.c_str(), data, &size, 0, key.type);
3347 0 : db_set_data_index(hDB, hkey, data, size, index, key.type);
3348 : }
3349 :
3350 0 : std::string options;
3351 0 : if (data_str[0] == 'y' || atoi(data_str.c_str()) > 0)
3352 0 : options += "checked ";
3353 0 : if (!edit)
3354 0 : options += "disabled ";
3355 : else {
3356 0 : if (edit == 1) {
3357 0 : options += "onClick=\"o=document.createElement('input');o.type='hidden';o.name='cbi';o.value='";
3358 0 : options += msprintf("%d", n_var);
3359 0 : options += "';document.form1.appendChild(o);";
3360 0 : options += "document.form1.submit();\" ";
3361 : }
3362 : }
3363 :
3364 0 : if (tail[0])
3365 0 : options += tail;
3366 :
3367 0 : r->rsprintf("<input type=\"checkbox\" %s>\n", options.c_str());
3368 :
3369 0 : } else { // checkbox
3370 :
3371 0 : if (edit == 1) {
3372 0 : if (n_var == i_set) {
3373 : /* set value */
3374 : char str[256];
3375 0 : mstrlcpy(str, pp->getparam("value"), sizeof(str));
3376 0 : db_sscanf(str, data, &size, 0, key.type);
3377 0 : db_set_data_index(hDB, hkey, data, size, index, key.type);
3378 :
3379 : /* read back value */
3380 0 : size = sizeof(data);
3381 0 : db_get_data_index(hDB, hkey, data, &size, index, key.type);
3382 0 : data_str = db_sprintf(data, key.item_size, 0, key.type);
3383 : }
3384 :
3385 0 : if (n_var == i_edit) {
3386 0 : r->rsprintf("<input type=text size=10 maxlength=80 name=value value=\"%s\">\n", data_str.c_str());
3387 0 : r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
3388 0 : r->rsprintf("<input type=hidden name=index value=%d>\n", n_var);
3389 0 : r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3390 : } else {
3391 0 : if (edit == 2) {
3392 : /* edit handling through user supplied JavaScript */
3393 0 : r->rsprintf("<a href=\"#\" %s>", tail);
3394 : } else {
3395 : /* edit handling through form submission */
3396 0 : if (pwd[0]) {
3397 0 : r->rsprintf("<a onClick=\"promptpwd('%s?cmd=Edit&index=%d&pnam=%s')\" href=\"#\">", path, n_var, pwd);
3398 : } else {
3399 0 : r->rsprintf("<a href=\"%s?cmd=Edit&index=%d\" %s>", path, n_var, tail);
3400 : }
3401 : }
3402 :
3403 0 : r->rsputs(data_str.c_str());
3404 0 : r->rsprintf("</a>");
3405 : }
3406 0 : } else if (edit == 2) {
3407 0 : r->rsprintf("<a href=\"#\" onclick=\"ODBEdit('%s')\">\n", full_keypath);
3408 0 : r->rsputs(data_str.c_str());
3409 0 : r->rsprintf("</a>");
3410 : }
3411 : else
3412 0 : r->rsputs(data_str.c_str());
3413 : }
3414 0 : }
3415 0 : }
3416 :
3417 : /*------------------------------------------------------------------*/
3418 :
3419 : /* add labels using following syntax under /Custom/Images/<name.gif>/Labels/<name>:
3420 :
3421 : [Name] [Description] [Example]
3422 :
3423 : Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3424 : Format Formt for float/double %1.2f Deg. C
3425 : Font Font to use small | medium | giant
3426 : X X-position in pixel 90
3427 : Y Y-position from top 67
3428 : Align horizontal align left/center/right left
3429 : FGColor Foreground color RRGGBB 000000
3430 : BGColor Background color RRGGBB FFFFFF
3431 : */
3432 :
3433 : static const char *cgif_label_str[] = {
3434 : "Src = STRING : [256] ",
3435 : "Format = STRING : [32] %1.1f",
3436 : "Font = STRING : [32] Medium",
3437 : "X = INT : 0",
3438 : "Y = INT : 0",
3439 : "Align = INT : 0",
3440 : "FGColor = STRING : [8] 000000",
3441 : "BGColor = STRING : [8] FFFFFF",
3442 : NULL
3443 : };
3444 :
3445 : typedef struct {
3446 : char src[256];
3447 : char format[32];
3448 : char font[32];
3449 : int x, y, align;
3450 : char fgcolor[8];
3451 : char bgcolor[8];
3452 : } CGIF_LABEL;
3453 :
3454 : /* add labels using following syntax under /Custom/Images/<name.gif>/Bars/<name>:
3455 :
3456 : [Name] [Description] [Example]
3457 :
3458 : Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3459 : X X-position in pixel 90
3460 : Y Y-position from top 67
3461 : Width Width in pixel 20
3462 : Height Height in pixel 100
3463 : Direction 0(vertical)/1(horiz.) 0
3464 : Axis Draw axis 0(none)/1(left)/2(right) 1
3465 : Logscale Draw logarithmic axis n
3466 : Min Min value for axis 0
3467 : Max Max value for axis 10
3468 : FGColor Foreground color RRGGBB 000000
3469 : BGColor Background color RRGGBB FFFFFF
3470 : BDColor Border color RRGGBB 808080
3471 : */
3472 :
3473 : static const char *cgif_bar_str[] = {
3474 : "Src = STRING : [256] ",
3475 : "X = INT : 0",
3476 : "Y = INT : 0",
3477 : "Width = INT : 10",
3478 : "Height = INT : 100",
3479 : "Direction = INT : 0",
3480 : "Axis = INT : 1",
3481 : "Logscale = BOOL : n",
3482 : "Min = DOUBLE : 0",
3483 : "Max = DOUBLE : 10",
3484 : "FGColor = STRING : [8] 000000",
3485 : "BGColor = STRING : [8] FFFFFF",
3486 : "BDColor = STRING : [8] 808080",
3487 : NULL
3488 : };
3489 :
3490 : typedef struct {
3491 : char src[256];
3492 : int x, y, width, height, direction, axis;
3493 : BOOL logscale;
3494 : double min, max;
3495 : char fgcolor[8];
3496 : char bgcolor[8];
3497 : char bdcolor[8];
3498 : } CGIF_BAR;
3499 :
3500 : /*------------------------------------------------------------------*/
3501 :
3502 0 : int evaluate_src(char *key, char *src, double *fvalue)
3503 : {
3504 : HNDLE hDB, hkeyval;
3505 : KEY vkey;
3506 : int i, n, size, ivalue;
3507 : char str[256], data[256];
3508 :
3509 0 : cm_get_experiment_database(&hDB, NULL);
3510 :
3511 : /* separate source from operators */
3512 0 : for (i=0 ; i<(int)strlen(src) ; i++)
3513 0 : if (src[i] == '>' || src[i] == '&')
3514 : break;
3515 0 : strncpy(str, src, i);
3516 0 : str[i] = 0;
3517 :
3518 : /* strip trailing blanks */
3519 0 : while (strlen(str) > 0 && str[strlen(str)-1] == ' ')
3520 0 : str[strlen(str)-1] = 0;
3521 :
3522 0 : db_find_key(hDB, 0, str, &hkeyval);
3523 0 : if (!hkeyval) {
3524 0 : cm_msg(MERROR, "evaluate_src", "Invalid Src key \"%s\" for Fill \"%s\"",
3525 : src, key);
3526 0 : return 0;
3527 : }
3528 :
3529 0 : db_get_key(hDB, hkeyval, &vkey);
3530 0 : size = sizeof(data);
3531 0 : db_get_value(hDB, 0, src, data, &size, vkey.type, FALSE);
3532 0 : std::string value = db_sprintf(data, size, 0, vkey.type);
3533 0 : if (equal_ustring(value.c_str(), "NAN"))
3534 0 : return 0;
3535 :
3536 0 : if (vkey.type == TID_BOOL) {
3537 0 : *fvalue = (value[0] == 'y');
3538 : } else
3539 0 : *fvalue = atof(value.c_str());
3540 :
3541 : /* evaluate possible operators */
3542 : do {
3543 0 : if (src[i] == '>' && src[i+1] == '>') {
3544 0 : i+=2;
3545 0 : n = atoi(src+i);
3546 0 : while (src[i] == ' ' || isdigit(src[i]))
3547 0 : i++;
3548 0 : ivalue = (int)*fvalue;
3549 0 : ivalue >>= n;
3550 0 : *fvalue = ivalue;
3551 : }
3552 :
3553 0 : if (src[i] == '&') {
3554 0 : i+=1;
3555 0 : while (src[i] == ' ')
3556 0 : i++;
3557 0 : if (src[i] == '0' && src[i+1] == 'x')
3558 0 : sscanf(src+2+i, "%x", &n);
3559 : else
3560 0 : n = atoi(src+i);
3561 0 : while (src[i] == ' ' || isxdigit(src[i]) || src[i] == 'x')
3562 0 : i++;
3563 0 : ivalue = (int)*fvalue;
3564 0 : ivalue &= n;
3565 0 : *fvalue = ivalue;
3566 : }
3567 :
3568 0 : } while (src[i]);
3569 :
3570 0 : return 1;
3571 0 : }
3572 :
3573 : /*------------------------------------------------------------------*/
3574 :
3575 0 : std::string add_custom_path(const std::string& filename)
3576 : {
3577 : // do not append custom path to absolute filenames
3578 :
3579 0 : if (filename[0] == '/')
3580 0 : return filename;
3581 0 : if (filename[0] == DIR_SEPARATOR)
3582 0 : return filename;
3583 :
3584 : HNDLE hDB;
3585 0 : cm_get_experiment_database(&hDB, NULL);
3586 :
3587 0 : std::string custom_path = "";
3588 :
3589 0 : int status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
3590 :
3591 0 : if (status != DB_SUCCESS)
3592 0 : return filename;
3593 :
3594 0 : if (custom_path.length() < 1)
3595 0 : return filename;
3596 :
3597 0 : if ((custom_path == DIR_SEPARATOR_STR) || !strchr(custom_path.c_str(), DIR_SEPARATOR)) {
3598 0 : cm_msg(MERROR, "add_custom_path", "ODB /Custom/Path has a forbidden value \"%s\", please change it", custom_path.c_str());
3599 0 : return filename;
3600 : }
3601 :
3602 0 : custom_path = ss_replace_env_variables(custom_path);
3603 :
3604 0 : std::string full_filename = custom_path;
3605 0 : if (full_filename[full_filename.length()-1] != DIR_SEPARATOR)
3606 0 : full_filename += DIR_SEPARATOR_STR;
3607 0 : full_filename += filename;
3608 :
3609 0 : return full_filename;
3610 0 : }
3611 :
3612 : /*------------------------------------------------------------------*/
3613 :
3614 0 : void show_custom_file(Return* r, const char *name)
3615 : {
3616 : char str[256];
3617 0 : std::string filename;
3618 : HNDLE hDB;
3619 :
3620 0 : cm_get_experiment_database(&hDB, NULL);
3621 :
3622 : HNDLE hkey;
3623 0 : sprintf(str, "/Custom/%s", name);
3624 0 : db_find_key(hDB, 0, str, &hkey);
3625 :
3626 0 : if (!hkey) {
3627 0 : sprintf(str, "/Custom/%s&", name);
3628 0 : db_find_key(hDB, 0, str, &hkey);
3629 0 : if (!hkey) {
3630 0 : sprintf(str, "/Custom/%s!", name);
3631 0 : db_find_key(hDB, 0, str, &hkey);
3632 : }
3633 : }
3634 :
3635 0 : if(!hkey){
3636 0 : sprintf(str,"show_custom_file: Invalid custom page: \"/Custom/%s\" not found in ODB", name);
3637 0 : show_error_404(r, str);
3638 0 : return;
3639 : }
3640 :
3641 : int status;
3642 : KEY key;
3643 :
3644 0 : status = db_get_key(hDB, hkey, &key);
3645 :
3646 0 : if (status != DB_SUCCESS) {
3647 : char errtext[512];
3648 0 : sprintf(errtext, "show_custom_file: Error: db_get_key() for \"%s\" status %d", str, status);
3649 0 : show_error_404(r, errtext);
3650 0 : return;
3651 : }
3652 :
3653 0 : int size = key.total_size;
3654 0 : char* ctext = (char*)malloc(size);
3655 :
3656 0 : status = db_get_data(hDB, hkey, ctext, &size, TID_STRING);
3657 :
3658 0 : if (status != DB_SUCCESS) {
3659 : char errtext[512];
3660 0 : sprintf(errtext, "show_custom_file: Error: db_get_data() for \"%s\" status %d", str, status);
3661 0 : show_error_404(r, errtext);
3662 0 : free(ctext);
3663 0 : return;
3664 : }
3665 :
3666 0 : filename = add_custom_path(ctext);
3667 :
3668 0 : free(ctext);
3669 :
3670 0 : send_file(r, filename, true);
3671 :
3672 0 : return;
3673 0 : }
3674 :
3675 : /*------------------------------------------------------------------*/
3676 :
3677 0 : void show_custom_gif(Return* rr, const char *name)
3678 : {
3679 : char str[256], data[256], src[256];
3680 : int i, index, length, status, size, width, height, bgcol, fgcol, bdcol, r, g, b, x, y;
3681 : HNDLE hDB, hkeygif, hkeyroot, hkey, hkeyval;
3682 : double fvalue, ratio;
3683 : KEY key, vkey;
3684 : gdImagePtr im;
3685 : gdGifBuffer gb;
3686 : gdFontPtr pfont;
3687 : FILE *f;
3688 : CGIF_LABEL label;
3689 : CGIF_BAR bar;
3690 :
3691 0 : cm_get_experiment_database(&hDB, NULL);
3692 :
3693 : /* find image description in ODB */
3694 0 : sprintf(str, "/Custom/Images/%s", name);
3695 0 : db_find_key(hDB, 0, str, &hkeygif);
3696 0 : if (!hkeygif) {
3697 :
3698 : // If we don't have Images directory,
3699 : // then just treat this like any other custom file.
3700 0 : show_custom_file(rr, name);
3701 0 : return;
3702 : }
3703 :
3704 : /* load background image */
3705 0 : std::string filename;
3706 0 : db_get_value_string(hDB, hkeygif, "Background", 0, &filename, FALSE);
3707 :
3708 0 : std::string full_filename = add_custom_path(filename);
3709 :
3710 0 : f = fopen(full_filename.c_str(), "rb");
3711 0 : if (f == NULL) {
3712 0 : sprintf(str, "show_custom_gif: Cannot open file \"%s\"", full_filename.c_str());
3713 0 : show_error_404(rr, str);
3714 0 : return;
3715 : }
3716 :
3717 0 : im = gdImageCreateFromGif(f);
3718 0 : fclose(f);
3719 :
3720 0 : if (im == NULL) {
3721 0 : sprintf(str, "show_custom_gif: File \"%s\" is not a GIF image", filename.c_str());
3722 0 : show_error_404(rr, str);
3723 0 : return;
3724 : }
3725 :
3726 0 : cm_get_experiment_database(&hDB, NULL);
3727 :
3728 : /*---- draw labels ----------------------------------------------*/
3729 :
3730 0 : db_find_key(hDB, hkeygif, "Labels", &hkeyroot);
3731 0 : if (hkeyroot) {
3732 0 : for (index = 0;; index++) {
3733 0 : db_enum_key(hDB, hkeyroot, index, &hkey);
3734 0 : if (!hkey)
3735 0 : break;
3736 0 : db_get_key(hDB, hkey, &key);
3737 :
3738 0 : size = sizeof(label);
3739 0 : status = db_get_record1(hDB, hkey, &label, &size, 0, strcomb1(cgif_label_str).c_str());
3740 0 : if (status != DB_SUCCESS) {
3741 0 : cm_msg(MERROR, "show_custom_gif", "Cannot open data record for label \"%s\"",
3742 : key.name);
3743 0 : continue;
3744 : }
3745 :
3746 0 : if (label.src[0] == 0) {
3747 0 : cm_msg(MERROR, "show_custom_gif", "Empty Src key for label \"%s\"", key.name);
3748 0 : continue;
3749 : }
3750 :
3751 0 : db_find_key(hDB, 0, label.src, &hkeyval);
3752 0 : if (!hkeyval) {
3753 0 : cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for label \"%s\"",
3754 : label.src, key.name);
3755 0 : continue;
3756 : }
3757 :
3758 0 : db_get_key(hDB, hkeyval, &vkey);
3759 0 : size = sizeof(data);
3760 0 : status = db_get_value(hDB, 0, label.src, data, &size, vkey.type, FALSE);
3761 :
3762 0 : std::string value;
3763 :
3764 0 : if (label.format[0]) {
3765 0 : if (vkey.type == TID_FLOAT)
3766 0 : value = msprintf(label.format, *(((float *) data)));
3767 0 : else if (vkey.type == TID_DOUBLE)
3768 0 : value = msprintf(label.format, *(((double *) data)));
3769 0 : else if (vkey.type == TID_INT)
3770 0 : value = msprintf(label.format, *(((INT *) data)));
3771 0 : else if (vkey.type == TID_BOOL) {
3772 0 : if (strstr(label.format, "%c"))
3773 0 : value = msprintf(label.format, *(((INT *) data)) ? 'y' : 'n');
3774 : else
3775 0 : value = msprintf(label.format, *(((INT *) data)));
3776 : } else
3777 0 : value = db_sprintf(data, size, 0, vkey.type);
3778 : } else
3779 0 : value = db_sprintf(data, size, 0, vkey.type);
3780 :
3781 0 : sscanf(label.fgcolor, "%02x%02x%02x", &r, &g, &b);
3782 0 : fgcol = gdImageColorAllocate(im, r, g, b);
3783 0 : if (fgcol == -1)
3784 0 : fgcol = gdImageColorClosest(im, r, g, b);
3785 :
3786 0 : sscanf(label.bgcolor, "%02x%02x%02x", &r, &g, &b);
3787 0 : bgcol = gdImageColorAllocate(im, r, g, b);
3788 0 : if (bgcol == -1)
3789 0 : bgcol = gdImageColorClosest(im, r, g, b);
3790 :
3791 : /* select font */
3792 0 : if (equal_ustring(label.font, "Small"))
3793 0 : pfont = gdFontSmall;
3794 0 : else if (equal_ustring(label.font, "Medium"))
3795 0 : pfont = gdFontMediumBold;
3796 0 : else if (equal_ustring(label.font, "Giant"))
3797 0 : pfont = gdFontGiant;
3798 : else
3799 0 : pfont = gdFontMediumBold;
3800 :
3801 0 : width = value.length() * pfont->w + 5 + 5;
3802 0 : height = pfont->h + 2 + 2;
3803 :
3804 0 : if (label.align == 0) {
3805 : /* left */
3806 0 : gdImageFilledRectangle(im, label.x, label.y, label.x + width,
3807 0 : label.y + height, bgcol);
3808 0 : gdImageRectangle(im, label.x, label.y, label.x + width, label.y + height,
3809 : fgcol);
3810 0 : gdImageString(im, pfont, label.x + 5, label.y + 2, value.c_str(), fgcol);
3811 0 : } else if (label.align == 1) {
3812 : /* center */
3813 0 : gdImageFilledRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3814 0 : label.y + height, bgcol);
3815 0 : gdImageRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3816 0 : label.y + height, fgcol);
3817 0 : gdImageString(im, pfont, label.x + 5 - width / 2, label.y + 2, value.c_str(), fgcol);
3818 : } else {
3819 : /* right */
3820 0 : gdImageFilledRectangle(im, label.x - width, label.y, label.x,
3821 0 : label.y + height, bgcol);
3822 0 : gdImageRectangle(im, label.x - width, label.y, label.x, label.y + height,
3823 : fgcol);
3824 0 : gdImageString(im, pfont, label.x - width + 5, label.y + 2, value.c_str(), fgcol);
3825 : }
3826 0 : }
3827 : }
3828 :
3829 : /*---- draw bars ------------------------------------------------*/
3830 :
3831 0 : db_find_key(hDB, hkeygif, "Bars", &hkeyroot);
3832 0 : if (hkeyroot) {
3833 0 : for (index = 0;; index++) {
3834 0 : db_enum_key(hDB, hkeyroot, index, &hkey);
3835 0 : if (!hkey)
3836 0 : break;
3837 0 : db_get_key(hDB, hkey, &key);
3838 :
3839 0 : size = sizeof(bar);
3840 0 : status = db_get_record1(hDB, hkey, &bar, &size, 0, strcomb1(cgif_bar_str).c_str());
3841 0 : if (status != DB_SUCCESS) {
3842 0 : cm_msg(MERROR, "show_custom_gif", "Cannot open data record for bar \"%s\"",
3843 : key.name);
3844 0 : continue;
3845 : }
3846 :
3847 0 : if (bar.src[0] == 0) {
3848 0 : cm_msg(MERROR, "show_custom_gif", "Empty Src key for bar \"%s\"", key.name);
3849 0 : continue;
3850 : }
3851 :
3852 0 : db_find_key(hDB, 0, bar.src, &hkeyval);
3853 0 : if (!hkeyval) {
3854 0 : cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for bar \"%s\"",
3855 : bar.src, key.name);
3856 0 : continue;
3857 : }
3858 :
3859 0 : db_get_key(hDB, hkeyval, &vkey);
3860 0 : size = sizeof(data);
3861 0 : status = db_get_value(hDB, 0, bar.src, data, &size, vkey.type, FALSE);
3862 0 : std::string value = db_sprintf(data, size, 0, vkey.type);
3863 0 : if (equal_ustring(value.c_str(), "NAN"))
3864 0 : continue;
3865 :
3866 0 : fvalue = atof(value.c_str());
3867 :
3868 0 : sscanf(bar.fgcolor, "%02x%02x%02x", &r, &g, &b);
3869 0 : fgcol = gdImageColorAllocate(im, r, g, b);
3870 0 : if (fgcol == -1)
3871 0 : fgcol = gdImageColorClosest(im, r, g, b);
3872 :
3873 0 : sscanf(bar.bgcolor, "%02x%02x%02x", &r, &g, &b);
3874 0 : bgcol = gdImageColorAllocate(im, r, g, b);
3875 0 : if (bgcol == -1)
3876 0 : bgcol = gdImageColorClosest(im, r, g, b);
3877 :
3878 0 : sscanf(bar.bdcolor, "%02x%02x%02x", &r, &g, &b);
3879 0 : bdcol = gdImageColorAllocate(im, r, g, b);
3880 0 : if (bdcol == -1)
3881 0 : bdcol = gdImageColorClosest(im, r, g, b);
3882 :
3883 0 : if (bar.min == bar.max)
3884 0 : bar.max += 1;
3885 :
3886 0 : if (bar.logscale) {
3887 0 : if (fvalue < 1E-20)
3888 0 : fvalue = 1E-20;
3889 0 : ratio = (log(fvalue) - log(bar.min)) / (log(bar.max) - log(bar.min));
3890 : } else
3891 0 : ratio = (fvalue - bar.min) / (bar.max - bar.min);
3892 0 : if (ratio < 0)
3893 0 : ratio = 0;
3894 0 : if (ratio > 1)
3895 0 : ratio = 1;
3896 :
3897 0 : if (bar.direction == 0) {
3898 : /* vertical */
3899 0 : ratio = (bar.height - 2) - ratio * (bar.height - 2);
3900 0 : r = (int) (ratio + 0.5);
3901 :
3902 0 : gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.width,
3903 0 : bar.y + bar.height, bgcol);
3904 0 : gdImageRectangle(im, bar.x, bar.y, bar.x + bar.width, bar.y + bar.height,
3905 : bdcol);
3906 0 : gdImageFilledRectangle(im, bar.x + 1, bar.y + r + 1, bar.x + bar.width - 1,
3907 0 : bar.y + bar.height - 1, fgcol);
3908 :
3909 0 : if (bar.axis == 1)
3910 0 : vaxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.height, bar.height, -3,
3911 : -5, -7, -8, 0, bar.min, bar.max, bar.logscale);
3912 0 : else if (bar.axis == 2)
3913 0 : vaxis(im, gdFontSmall, bdcol, 0, bar.x + bar.width, bar.y + bar.height,
3914 : bar.height, 3, 5, 7, 10, 0, bar.min, bar.max, bar.logscale);
3915 :
3916 : } else {
3917 : /* horizontal */
3918 0 : ratio = ratio * (bar.height - 2);
3919 0 : r = (int) (ratio + 0.5);
3920 :
3921 0 : gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.height,
3922 0 : bar.y + bar.width, bgcol);
3923 0 : gdImageRectangle(im, bar.x, bar.y, bar.x + bar.height, bar.y + bar.width,
3924 : bdcol);
3925 0 : gdImageFilledRectangle(im, bar.x + 1, bar.y + 1, bar.x + r,
3926 0 : bar.y + bar.width - 1, fgcol);
3927 :
3928 0 : if (bar.axis == 1)
3929 0 : haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y, bar.height, -3, -5, -7, -18,
3930 : 0, bar.min, bar.max);
3931 0 : else if (bar.axis == 2)
3932 0 : haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.width, bar.height, 3,
3933 : 5, 7, 8, 0, bar.min, bar.max);
3934 : }
3935 0 : }
3936 : }
3937 :
3938 : /*---- draw fills -----------------------------------------------*/
3939 :
3940 0 : db_find_key(hDB, hkeygif, "Fills", &hkeyroot);
3941 0 : if (hkeyroot) {
3942 0 : for (index = 0;; index++) {
3943 0 : db_enum_key(hDB, hkeyroot, index, &hkey);
3944 0 : if (!hkey)
3945 0 : break;
3946 0 : db_get_key(hDB, hkey, &key);
3947 :
3948 0 : size = sizeof(src);
3949 0 : src[0] = 0;
3950 0 : db_get_value(hDB, hkey, "Src", src, &size, TID_STRING, TRUE);
3951 :
3952 0 : if (src[0] == 0) {
3953 0 : cm_msg(MERROR, "show_custom_gif", "Empty Src key for Fill \"%s\"", key.name);
3954 0 : continue;
3955 : }
3956 :
3957 0 : if (!evaluate_src(key.name, src, &fvalue))
3958 0 : continue;
3959 :
3960 0 : x = y = 0;
3961 0 : size = sizeof(x);
3962 0 : db_get_value(hDB, hkey, "X", &x, &size, TID_INT, TRUE);
3963 0 : db_get_value(hDB, hkey, "Y", &y, &size, TID_INT, TRUE);
3964 :
3965 0 : size = sizeof(data);
3966 0 : status = db_get_value(hDB, hkey, "Limits", data, &size, TID_DOUBLE, FALSE);
3967 0 : if (status != DB_SUCCESS) {
3968 0 : cm_msg(MERROR, "show_custom_gif", "No \"Limits\" entry for Fill \"%s\"",
3969 : key.name);
3970 0 : continue;
3971 : }
3972 0 : for (i = 0; i < size / (int) sizeof(double); i++)
3973 0 : if (*((double *) data + i) > fvalue)
3974 0 : break;
3975 0 : if (i > 0)
3976 0 : i--;
3977 :
3978 0 : db_find_key(hDB, hkey, "Fillcolors", &hkeyval);
3979 0 : if (!hkeyval) {
3980 0 : cm_msg(MERROR, "show_custom_gif", "No \"Fillcolors\" entry for Fill \"%s\"",
3981 : key.name);
3982 0 : continue;
3983 : }
3984 :
3985 0 : size = sizeof(data);
3986 0 : strcpy(data, "FFFFFF");
3987 0 : status = db_get_data_index(hDB, hkeyval, data, &size, i, TID_STRING);
3988 0 : if (status == DB_SUCCESS) {
3989 0 : sscanf(data, "%02x%02x%02x", &r, &g, &b);
3990 0 : fgcol = gdImageColorAllocate(im, r, g, b);
3991 0 : if (fgcol == -1)
3992 0 : fgcol = gdImageColorClosest(im, r, g, b);
3993 0 : gdImageFill(im, x, y, fgcol);
3994 : }
3995 : }
3996 : }
3997 :
3998 : /* generate GIF */
3999 0 : gdImageInterlace(im, 1);
4000 0 : gdImageGif(im, &gb);
4001 0 : gdImageDestroy(im);
4002 0 : length = gb.size;
4003 :
4004 0 : rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
4005 0 : rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
4006 :
4007 0 : rr->rsprintf("Content-Type: image/gif\r\n");
4008 0 : rr->rsprintf("Content-Length: %d\r\n", length);
4009 0 : rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
4010 0 : rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
4011 :
4012 0 : rr->rmemcpy(gb.data, length);
4013 0 : }
4014 :
4015 :
4016 :
4017 : /*------------------------------------------------------------------*/
4018 :
4019 0 : void do_jrpc_rev0(Param* p, Return* r)
4020 : {
4021 : static RPC_LIST rpc_list[] = {
4022 : { 9999, "mhttpd_jrpc_rev0", {
4023 : {TID_STRING, RPC_IN}, // arg0
4024 : {TID_STRING, RPC_IN}, // arg1
4025 : {TID_STRING, RPC_IN}, // arg2
4026 : {TID_STRING, RPC_IN}, // arg3
4027 : {TID_STRING, RPC_IN}, // arg4
4028 : {TID_STRING, RPC_IN}, // arg5
4029 : {TID_STRING, RPC_IN}, // arg6
4030 : {TID_STRING, RPC_IN}, // arg7
4031 : {TID_STRING, RPC_IN}, // arg8
4032 : {TID_STRING, RPC_IN}, // arg9
4033 : {0}} },
4034 : { 0 }
4035 : };
4036 :
4037 0 : int count = 0, substring = 0, rpc;
4038 :
4039 0 : const char *xname = p->getparam("name");
4040 0 : const char *srpc = p->getparam("rpc");
4041 :
4042 0 : if (!srpc || !xname) {
4043 0 : show_text_header(r);
4044 0 : r->rsprintf("<INVALID_ARGUMENTS>");
4045 0 : return;
4046 : }
4047 :
4048 : char sname[256];
4049 0 : mstrlcpy(sname, xname, sizeof(sname));
4050 :
4051 0 : if (sname[strlen(sname)-1]=='*') {
4052 0 : sname[strlen(sname)-1] = 0;
4053 0 : substring = 1;
4054 : }
4055 :
4056 0 : rpc = atoi(srpc);
4057 :
4058 0 : if (rpc<RPC_MIN_ID || rpc>RPC_MAX_ID) {
4059 0 : show_text_header(r);
4060 0 : r->rsprintf("<INVALID_RPC_ID>");
4061 0 : return;
4062 : }
4063 :
4064 0 : rpc_list[0].id = rpc;
4065 0 : rpc_register_functions(rpc_list, NULL);
4066 :
4067 0 : show_text_header(r);
4068 0 : r->rsprintf("calling rpc %d | ", rpc);
4069 :
4070 : if (1) {
4071 : int status, i;
4072 : char str[256];
4073 : HNDLE hDB, hrootkey, hsubkey, hkey;
4074 :
4075 0 : cm_get_experiment_database(&hDB, NULL);
4076 :
4077 : /* find client which exports FCNA function */
4078 0 : status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4079 0 : if (status == DB_SUCCESS) {
4080 0 : for (i=0; ; i++) {
4081 0 : status = db_enum_key(hDB, hrootkey, i, &hsubkey);
4082 0 : if (status == DB_NO_MORE_SUBKEYS)
4083 0 : break;
4084 :
4085 0 : sprintf(str, "RPC/%d", rpc);
4086 0 : status = db_find_key(hDB, hsubkey, str, &hkey);
4087 0 : if (status == DB_SUCCESS) {
4088 : char client_name[NAME_LENGTH];
4089 : HNDLE hconn;
4090 : int size;
4091 :
4092 0 : size = sizeof(client_name);
4093 0 : status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4094 0 : if (status != DB_SUCCESS)
4095 0 : continue;
4096 :
4097 0 : if (strlen(sname) > 0) {
4098 0 : if (substring) {
4099 0 : if (strstr(client_name, sname) != client_name)
4100 0 : continue;
4101 : } else {
4102 0 : if (strcmp(sname, client_name) != 0)
4103 0 : continue;
4104 : }
4105 : }
4106 :
4107 0 : count++;
4108 :
4109 0 : r->rsprintf("client %s", client_name);
4110 :
4111 0 : status = cm_connect_client(client_name, &hconn);
4112 0 : r->rsprintf(" %d", status);
4113 :
4114 0 : if (status == RPC_SUCCESS) {
4115 0 : status = rpc_client_call(hconn, rpc,
4116 : p->getparam("arg0"),
4117 : p->getparam("arg1"),
4118 : p->getparam("arg2"),
4119 : p->getparam("arg3"),
4120 : p->getparam("arg4"),
4121 : p->getparam("arg5"),
4122 : p->getparam("arg6"),
4123 : p->getparam("arg7"),
4124 : p->getparam("arg8"),
4125 : p->getparam("arg9")
4126 : );
4127 0 : r->rsprintf(" %d", status);
4128 :
4129 : //status = cm_disconnect_client(hconn, FALSE);
4130 0 : r->rsprintf(" %d", status);
4131 : }
4132 :
4133 0 : r->rsprintf(" | ");
4134 : }
4135 0 : }
4136 : }
4137 : }
4138 :
4139 0 : r->rsprintf("rpc %d, called %d clients\n", rpc, count);
4140 : }
4141 :
4142 : /*------------------------------------------------------------------*/
4143 :
4144 0 : void do_jrpc_rev1(Param* p, Return* r)
4145 : {
4146 : static RPC_LIST rpc_list[] = {
4147 : { 9998, "mhttpd_jrpc_rev1", {
4148 : {TID_STRING, RPC_OUT}, // return string
4149 : {TID_INT, RPC_IN}, // return string max length
4150 : {TID_STRING, RPC_IN}, // arg0
4151 : {TID_STRING, RPC_IN}, // arg1
4152 : {TID_STRING, RPC_IN}, // arg2
4153 : {TID_STRING, RPC_IN}, // arg3
4154 : {TID_STRING, RPC_IN}, // arg4
4155 : {TID_STRING, RPC_IN}, // arg5
4156 : {TID_STRING, RPC_IN}, // arg6
4157 : {TID_STRING, RPC_IN}, // arg7
4158 : {TID_STRING, RPC_IN}, // arg8
4159 : {TID_STRING, RPC_IN}, // arg9
4160 : {0}} },
4161 : { 0 }
4162 : };
4163 :
4164 0 : int status, substring = 0, rpc;
4165 :
4166 0 : const char *xname = p->getparam("name");
4167 0 : const char *srpc = p->getparam("rpc");
4168 :
4169 0 : if (!srpc || !xname) {
4170 0 : show_text_header(r);
4171 0 : r->rsprintf("<INVALID_ARGUMENTS>");
4172 0 : return;
4173 : }
4174 :
4175 : char sname[256];
4176 0 : mstrlcpy(sname, xname, sizeof(sname));
4177 :
4178 0 : if (sname[strlen(sname)-1]=='*') {
4179 0 : sname[strlen(sname)-1] = 0;
4180 0 : substring = 1;
4181 : }
4182 :
4183 0 : rpc = atoi(srpc);
4184 :
4185 0 : if (rpc<RPC_MIN_ID || rpc>RPC_MAX_ID) {
4186 0 : show_text_header(r);
4187 0 : r->rsprintf("<INVALID_RPC_ID>");
4188 0 : return;
4189 : }
4190 :
4191 0 : rpc_list[0].id = rpc;
4192 0 : status = rpc_register_functions(rpc_list, NULL);
4193 :
4194 : //printf("cm_register_functions() for format \'%s\' status %d\n", sformat, status);
4195 :
4196 0 : show_text_header(r);
4197 :
4198 0 : std::string reply_header;
4199 0 : std::string reply_body;
4200 :
4201 : //r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4202 : //r->rsprintf("<!-- created by MHTTPD on (timestamp) -->\n");
4203 : //r->rsprintf("<jrpc_rev1>\n");
4204 : //r->rsprintf(" <rpc>%d</rpc>\n", rpc);
4205 :
4206 : if (1) {
4207 : HNDLE hDB, hrootkey, hsubkey, hkey;
4208 :
4209 0 : cm_get_experiment_database(&hDB, NULL);
4210 :
4211 0 : int buf_length = 1024;
4212 :
4213 0 : int max_reply_length = atoi(p->getparam("max_reply_length"));
4214 0 : if (max_reply_length > buf_length)
4215 0 : buf_length = max_reply_length;
4216 :
4217 0 : char* buf = (char*)malloc(buf_length);
4218 :
4219 0 : assert(buf != NULL);
4220 :
4221 : /* find client which exports our RPC function */
4222 0 : status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4223 0 : if (status == DB_SUCCESS) {
4224 0 : for (int i=0; ; i++) {
4225 0 : status = db_enum_key(hDB, hrootkey, i, &hsubkey);
4226 0 : if (status == DB_NO_MORE_SUBKEYS)
4227 0 : break;
4228 :
4229 : char str[256];
4230 0 : sprintf(str, "RPC/%d", rpc);
4231 0 : status = db_find_key(hDB, hsubkey, str, &hkey);
4232 0 : if (status == DB_SUCCESS) {
4233 : char client_name[NAME_LENGTH];
4234 : HNDLE hconn;
4235 : int size;
4236 :
4237 0 : size = sizeof(client_name);
4238 0 : status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4239 0 : if (status != DB_SUCCESS)
4240 0 : continue;
4241 :
4242 0 : if (strlen(sname) > 0) {
4243 0 : if (substring) {
4244 0 : if (strstr(client_name, sname) != client_name)
4245 0 : continue;
4246 : } else {
4247 0 : if (strcmp(sname, client_name) != 0)
4248 0 : continue;
4249 : }
4250 : }
4251 :
4252 : //r->rsprintf(" <client>\n");
4253 : //r->rsprintf(" <name>%s</name>\n", client_name);
4254 :
4255 0 : int connect_status = -1;
4256 0 : int call_status = -1;
4257 0 : int call_length = 0;
4258 0 : int disconnect_status = -1;
4259 :
4260 0 : connect_status = cm_connect_client(client_name, &hconn);
4261 :
4262 : //r->rsprintf(" <connect_status>%d</connect_status>\n", status);
4263 :
4264 0 : if (connect_status == RPC_SUCCESS) {
4265 0 : buf[0] = 0;
4266 :
4267 0 : call_status = rpc_client_call(hconn, rpc,
4268 : buf,
4269 : buf_length,
4270 : p->getparam("arg0"),
4271 : p->getparam("arg1"),
4272 : p->getparam("arg2"),
4273 : p->getparam("arg3"),
4274 : p->getparam("arg4"),
4275 : p->getparam("arg5"),
4276 : p->getparam("arg6"),
4277 : p->getparam("arg7"),
4278 : p->getparam("arg8"),
4279 : p->getparam("arg9")
4280 : );
4281 :
4282 : //r->rsprintf(" <rpc_status>%d</rpc_status>\n", status);
4283 : ////r->rsprintf(" <data>%s</data>\n", buf);
4284 : //r->rsputs("<data>");
4285 : //r->rsputs(buf);
4286 : //r->rsputs("</data>\n");
4287 :
4288 0 : if (call_status == RPC_SUCCESS) {
4289 0 : call_length = strlen(buf);
4290 0 : reply_body += buf;
4291 : }
4292 :
4293 : //disconnect_status = cm_disconnect_client(hconn, FALSE);
4294 : //r->rsprintf(" <disconnect_status>%d</disconnect_status>\n", status);
4295 : }
4296 :
4297 : //r->rsprintf(" </client>\n");
4298 :
4299 0 : if (reply_header.length() > 0)
4300 0 : reply_header += " | ";
4301 :
4302 : char tmp[256];
4303 0 : sprintf(tmp, "%s %d %d %d %d", client_name, connect_status, call_status, disconnect_status, call_length);
4304 0 : reply_header += tmp;
4305 : }
4306 0 : }
4307 : }
4308 :
4309 0 : free(buf);
4310 : }
4311 :
4312 : //r->rsprintf(" <called_clients>%d</called_clients>\n", count);
4313 : //r->rsprintf("</jrpc_rev1>\n");
4314 :
4315 0 : if (reply_header.length() > 0) {
4316 0 : r->rsputs(reply_header.c_str());
4317 0 : r->rsputs(" || ");
4318 0 : r->rsputs(reply_body.c_str());
4319 0 : r->rsputs("\n");
4320 : }
4321 0 : }
4322 :
4323 : /*------------------------------------------------------------------*/
4324 :
4325 0 : void do_jrpc(Param* p, Return* r)
4326 : {
4327 : int status;
4328 :
4329 0 : const char *name = p->getparam("name");
4330 0 : const char *cmd = p->getparam("rcmd");
4331 0 : const char *args = p->getparam("rarg");
4332 :
4333 0 : if (!name || !cmd || !args) {
4334 0 : show_text_header(r);
4335 0 : r->rsprintf("<INVALID_ARGUMENTS>");
4336 0 : return;
4337 : }
4338 :
4339 0 : show_text_header(r);
4340 :
4341 0 : int buf_length = 1024;
4342 :
4343 0 : int max_reply_length = atoi(p->getparam("max_reply_length"));
4344 0 : if (max_reply_length > buf_length)
4345 0 : buf_length = max_reply_length;
4346 :
4347 0 : char* buf = (char*)malloc(buf_length);
4348 0 : assert(buf != NULL);
4349 :
4350 0 : buf[0] = 0;
4351 :
4352 : HNDLE hconn;
4353 :
4354 0 : status = cm_connect_client(name, &hconn);
4355 :
4356 0 : if (status != RPC_SUCCESS) {
4357 0 : r->rsprintf("<RPC_CONNECT_ERROR>%d</RPC_CONNECT_ERROR>", status);
4358 0 : free(buf);
4359 0 : return;
4360 : }
4361 :
4362 0 : status = rpc_client_call(hconn, RPC_JRPC, cmd, args, buf, buf_length);
4363 :
4364 0 : if (status != RPC_SUCCESS) {
4365 0 : r->rsprintf("<RPC_CALL_ERROR>%d</RPC_CALL_ERROR>", status);
4366 0 : free(buf);
4367 0 : return;
4368 : }
4369 :
4370 0 : r->rsprintf("%s", buf);
4371 :
4372 : //status = cm_disconnect_client(hconn, FALSE);
4373 :
4374 0 : free(buf);
4375 : }
4376 :
4377 : /*------------------------------------------------------------------*/
4378 :
4379 0 : void output_key(Param* p, Return* r, HNDLE hkey, int index, const char *format)
4380 : {
4381 : int size, i;
4382 : HNDLE hDB, hsubkey;
4383 : KEY key;
4384 : char data[TEXT_SIZE];
4385 :
4386 0 : cm_get_experiment_database(&hDB, NULL);
4387 :
4388 0 : db_get_key(hDB, hkey, &key);
4389 0 : if (key.type == TID_KEY) {
4390 0 : for (i=0 ; ; i++) {
4391 0 : db_enum_key(hDB, hkey, i, &hsubkey);
4392 0 : if (!hsubkey)
4393 0 : break;
4394 0 : output_key(p, r, hsubkey, -1, format);
4395 : }
4396 : } else {
4397 0 : if (key.item_size <= (int)sizeof(data)) {
4398 0 : size = sizeof(data);
4399 0 : db_get_data(hDB, hkey, data, &size, key.type);
4400 0 : if (index == -1) {
4401 0 : for (i=0 ; i<key.num_values ; i++) {
4402 0 : if (p->isparam("name") && atoi(p->getparam("name")) == 1) {
4403 0 : if (key.num_values == 1)
4404 0 : r->rsprintf("%s:", key.name);
4405 : else
4406 0 : r->rsprintf("%s[%d]:", key.name, i);
4407 : }
4408 0 : std::string data_str;
4409 0 : if (format && format[0])
4410 0 : data_str = db_sprintff(format, data, key.item_size, i, key.type);
4411 : else
4412 0 : data_str = db_sprintf(data, key.item_size, i, key.type);
4413 0 : r->rsputs(data_str.c_str());
4414 0 : if (i<key.num_values-1)
4415 0 : r->rsputs("\n");
4416 0 : }
4417 : } else {
4418 0 : if (p->isparam("name") && atoi(p->getparam("name")) == 1)
4419 0 : r->rsprintf("%s[%d]:", key.name, index);
4420 0 : if (index >= key.num_values)
4421 0 : r->rsputs("<DB_OUT_OF_RANGE>");
4422 : else {
4423 0 : std::string data_str;
4424 0 : if (p->isparam("format"))
4425 0 : data_str = db_sprintff(p->getparam("format"), data, key.item_size, index, key.type);
4426 : else
4427 0 : data_str = db_sprintf(data, key.item_size, index, key.type);
4428 0 : r->rsputs(data_str.c_str());
4429 0 : }
4430 : }
4431 0 : r->rsputs("\n");
4432 : }
4433 : }
4434 0 : }
4435 :
4436 : /*------------------------------------------------------------------*/
4437 :
4438 0 : bool starts_with(const std::string& s1, const char* s2)
4439 : {
4440 0 : if (s1.length() < strlen(s2))
4441 0 : return false;
4442 0 : return (strncasecmp(s1.c_str(), s2, strlen(s2)) == 0);
4443 : }
4444 :
4445 : //static bool ends_with_char(const std::string& s, char c)
4446 : //{
4447 : // if (s.length() < 1)
4448 : // return false;
4449 : // return s[s.length()-1] == c;
4450 : //}
4451 :
4452 : /*------------------------------------------------------------------*/
4453 :
4454 0 : void javascript_commands(Param* p, Return* r, const char *cookie_cpwd)
4455 : {
4456 : int status;
4457 : int size, i, n, index, type;
4458 : unsigned int t;
4459 : char str[TEXT_SIZE], format[256], facility[256], user[256];
4460 : HNDLE hDB, hkey;
4461 : KEY key;
4462 : char data[TEXT_SIZE];
4463 :
4464 0 : cm_get_experiment_database(&hDB, NULL);
4465 :
4466 : // process common parameters
4467 :
4468 0 : const int ENCODING_NONE = 0;
4469 0 : const int ENCODING_ODB = 1;
4470 0 : const int ENCODING_XML = 2;
4471 0 : const int ENCODING_JSON = 3;
4472 :
4473 0 : std::string cmd_parameter;
4474 0 : std::string encoding_parameter;
4475 0 : int encoding = ENCODING_NONE; // default encoding
4476 0 : bool jsonp = false; // default is no JSONP wrapper
4477 0 : std::string jsonp_callback; // default is no JSONP
4478 0 : bool single = false; // single encoding
4479 0 : bool multiple = false; // multiple encoding
4480 0 : std::vector<std::string> odb; // multiple odb parameters
4481 : //HNDLE hodb; // ODB handle for single odb parameter
4482 : //std::vector<HNDLE> hodbm; // ODB handle for multiple odb parameter
4483 :
4484 0 : if (p->isparam("cmd")) {
4485 0 : cmd_parameter = p->getparam("cmd");
4486 : }
4487 :
4488 0 : if (p->isparam("encoding")) {
4489 0 : encoding_parameter = p->getparam("encoding");
4490 : }
4491 :
4492 0 : if (encoding_parameter.length() > 0) {
4493 0 : if (starts_with(encoding_parameter, "odb"))
4494 0 : encoding = ENCODING_ODB;
4495 0 : else if (starts_with(encoding_parameter, "xml"))
4496 0 : encoding = ENCODING_XML;
4497 0 : else if (starts_with(encoding_parameter, "json"))
4498 0 : encoding = ENCODING_JSON;
4499 : }
4500 :
4501 0 : if (encoding == ENCODING_JSON) {
4502 0 : if (p->isparam("callback")) {
4503 0 : jsonp = true;
4504 0 : jsonp_callback = p->getparam("callback");
4505 : }
4506 : }
4507 :
4508 0 : if (p->isparam("odb")) {
4509 0 : single = true;
4510 0 : odb.push_back(p->getparam("odb"));
4511 : }
4512 :
4513 0 : if (p->isparam("odb0")) {
4514 0 : multiple = true;
4515 0 : for (int i=0 ; ; i++) {
4516 : char ppath[256];
4517 0 : sprintf(ppath, "odb%d", i);
4518 0 : if (!p->isparam(ppath))
4519 0 : break;
4520 0 : odb.push_back(p->getparam(ppath));
4521 0 : }
4522 : }
4523 :
4524 : if (/* DISABLES CODE */ (0)) {
4525 : printf("command [%s], encoding %d [%s], jsonp %d, single %d, multiple %d, odb array size %d\n", cmd_parameter.c_str(), encoding, encoding_parameter.c_str(), jsonp, single, multiple, (int)odb.size());
4526 : }
4527 :
4528 : /* process "jset" command */
4529 0 : if (equal_ustring(p->getparam("cmd"), "jset")) {
4530 :
4531 0 : if (*p->getparam("pnam")) {
4532 0 : std::string ppath;
4533 0 : ppath += "/Custom/Pwd/";
4534 0 : ppath += p->getparam("pnam");
4535 0 : str[0] = 0;
4536 0 : db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
4537 0 : if (!equal_ustring(cookie_cpwd, str)) {
4538 0 : show_text_header(r);
4539 0 : r->rsprintf("Invalid password!");
4540 0 : return;
4541 : }
4542 0 : }
4543 0 : mstrlcpy(str, p->getparam("odb"), sizeof(str));
4544 0 : if (strchr(str, '[')) {
4545 0 : if (*(strchr(str, '[')+1) == '*')
4546 0 : index = -1;
4547 : else
4548 0 : index = atoi(strchr(str, '[')+1);
4549 0 : *strchr(str, '[') = 0;
4550 : } else
4551 0 : index = 0;
4552 :
4553 0 : if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS && p->isparam("value")) {
4554 0 : db_get_key(hDB, hkey, &key);
4555 0 : memset(data, 0, sizeof(data));
4556 0 : if (key.item_size <= (int)sizeof(data)) {
4557 0 : if (index == -1) {
4558 0 : const char* ptr = p->getparam("value");
4559 0 : for (i=0 ; ptr != NULL ; i++) {
4560 0 : size = sizeof(data);
4561 0 : db_sscanf(ptr, data, &size, 0, key.type);
4562 0 : if (strchr(data, ','))
4563 0 : *strchr(data, ',') = 0;
4564 0 : db_set_data_index(hDB, hkey, data, key.item_size, i, key.type);
4565 0 : ptr = strchr(ptr, ',');
4566 0 : if (ptr != NULL)
4567 0 : ptr++;
4568 : }
4569 : } else {
4570 0 : size = sizeof(data);
4571 0 : db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4572 :
4573 : /* extend data size for single string if necessary */
4574 0 : if ((key.type == TID_STRING || key.type == TID_LINK)
4575 0 : && (int) strlen(data) + 1 > key.item_size && key.num_values == 1) {
4576 0 : key.item_size = strlen(data) + 1;
4577 0 : db_set_data(hDB, hkey, data, key.item_size, 1, key.type);
4578 : } else
4579 0 : db_set_data_index(hDB, hkey, data, key.item_size, index, key.type);
4580 : }
4581 : }
4582 : } else {
4583 0 : if (p->isparam("value") && p->isparam("type") && p->isparam("len")) {
4584 0 : int type = atoi(p->getparam("type"));
4585 0 : if (type == 0) {
4586 0 : show_text_header(r);
4587 0 : r->rsprintf("Invalid type %d!", type);
4588 0 : return;
4589 : }
4590 0 : db_create_key(hDB, 0, str, type);
4591 0 : db_find_key(hDB, 0, str, &hkey);
4592 0 : if (!hkey) {
4593 0 : show_text_header(r);
4594 0 : r->rsprintf("Cannot create \'%s\' type %d", str, type);
4595 0 : return;
4596 : }
4597 0 : db_get_key(hDB, hkey, &key);
4598 0 : memset(data, 0, sizeof(data));
4599 0 : size = sizeof(data);
4600 0 : db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4601 0 : if (key.type == TID_STRING)
4602 0 : db_set_data(hDB, hkey, data, atoi(p->getparam("len")), 1, TID_STRING);
4603 : else {
4604 0 : for (i=0 ; i<atoi(p->getparam("len")) ; i++)
4605 0 : db_set_data_index(hDB, hkey, data, rpc_tid_size(key.type), i, key.type);
4606 : }
4607 : }
4608 : }
4609 :
4610 0 : show_text_header(r);
4611 0 : r->rsprintf("OK");
4612 0 : return;
4613 : }
4614 :
4615 : /* process "jget" command */
4616 0 : if (equal_ustring(p->getparam("cmd"), "jget")) {
4617 :
4618 0 : if (p->isparam("odb")) {
4619 0 : mstrlcpy(str, p->getparam("odb"), sizeof(str));
4620 0 : if (strchr(str, '[')) {
4621 0 : if (*(strchr(str, '[')+1) == '*')
4622 0 : index = -1;
4623 : else
4624 0 : index = atoi(strchr(str, '[')+1);
4625 0 : *strchr(str, '[') = 0;
4626 : } else
4627 0 : index = 0;
4628 :
4629 0 : show_text_header(r);
4630 :
4631 0 : status = db_find_key(hDB, 0, str, &hkey);
4632 :
4633 0 : if (status == DB_SUCCESS)
4634 0 : output_key(p, r, hkey, index, p->getparam("format"));
4635 : else
4636 0 : r->rsputs("<DB_NO_KEY>");
4637 : }
4638 :
4639 0 : if (p->isparam("odb0")) {
4640 0 : show_text_header(r);
4641 0 : for (i=0 ; ; i++) {
4642 : char ppath[256];
4643 0 : sprintf(ppath, "odb%d", i);
4644 0 : sprintf(format, "format%d", i);
4645 0 : if (p->isparam(ppath)) {
4646 0 : mstrlcpy(str, p->getparam(ppath), sizeof(str));
4647 0 : if (strchr(str, '[')) {
4648 0 : if (*(strchr(str, '[')+1) == '*')
4649 0 : index = -1;
4650 : else
4651 0 : index = atoi(strchr(str, '[')+1);
4652 0 : *strchr(str, '[') = 0;
4653 : } else
4654 0 : index = 0;
4655 0 : if (i > 0)
4656 0 : r->rsputs("$#----#$\n");
4657 0 : if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS)
4658 0 : output_key(p, r, hkey, index, p->getparam(format));
4659 : else
4660 0 : r->rsputs("<DB_NO_KEY>");
4661 :
4662 : } else
4663 0 : break;
4664 0 : }
4665 : }
4666 :
4667 0 : return;
4668 : }
4669 :
4670 : /* process "jcopy" command */
4671 0 : if (equal_ustring(p->getparam("cmd"), "jcopy")) {
4672 :
4673 0 : bool fmt_odb = false;
4674 0 : bool fmt_xml = false;
4675 0 : bool fmt_json = true;
4676 0 : bool fmt_jsonp = false;
4677 0 : int follow_links = 1;
4678 0 : int save_keys = 1;
4679 0 : int recurse = 1;
4680 0 : const char* fmt = NULL;
4681 0 : const char* jsonp_callback = "callback";
4682 :
4683 0 : if (p->isparam("encoding")) {
4684 0 : fmt = p->getparam("encoding");
4685 0 : } else if (p->isparam("format")) {
4686 0 : fmt = p->getparam("format");
4687 : }
4688 :
4689 0 : if (fmt) {
4690 0 : fmt_odb = (equal_ustring(fmt, "odb") > 0);
4691 0 : fmt_xml = (equal_ustring(fmt, "xml") > 0);
4692 0 : fmt_json = (strstr(fmt, "json") != NULL);
4693 :
4694 0 : if (fmt_odb)
4695 0 : fmt_xml = fmt_json = false;
4696 0 : if (fmt_xml)
4697 0 : fmt_odb = fmt_json = false;
4698 0 : if (fmt_json)
4699 0 : fmt_odb = fmt_xml = false;
4700 :
4701 0 : if (fmt_json)
4702 0 : fmt_jsonp = (strstr(fmt, "-p") != NULL);
4703 0 : if (fmt_jsonp && p->isparam("callback"))
4704 0 : jsonp_callback = p->getparam("callback");
4705 0 : if (fmt_json && strstr(fmt, "-nofollowlinks"))
4706 0 : follow_links = 0;
4707 0 : if (fmt_json && strstr(fmt, "-nokeys"))
4708 0 : save_keys = 2;
4709 0 : if (fmt_json && strstr(fmt, "-nolastwritten"))
4710 0 : save_keys = 0;
4711 0 : if (fmt_json && strstr(fmt, "-norecurse"))
4712 0 : recurse = 0;
4713 : }
4714 :
4715 0 : if (p->isparam("odb")) {
4716 0 : mstrlcpy(str, p->getparam("odb"), sizeof(str));
4717 :
4718 0 : show_text_header(r);
4719 :
4720 0 : if (fmt_json)
4721 0 : status = db_find_link(hDB, 0, str, &hkey);
4722 : else
4723 0 : status = db_find_key(hDB, 0, str, &hkey);
4724 0 : if (status == DB_SUCCESS) {
4725 :
4726 0 : if (fmt_jsonp) {
4727 0 : r->rsputs(jsonp_callback);
4728 0 : r->rsputs("(");
4729 : }
4730 :
4731 0 : int end = 0;
4732 0 : int bufsize = WEB_BUFFER_SIZE;
4733 0 : char* buf = (char *)malloc(bufsize);
4734 :
4735 0 : if (fmt_xml)
4736 0 : db_copy_xml(hDB, hkey, buf, &bufsize, true);
4737 0 : else if (fmt_json)
4738 0 : db_copy_json_obsolete(hDB, hkey, &buf, &bufsize, &end, save_keys, follow_links, recurse);
4739 : else
4740 0 : db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4741 :
4742 0 : r->rsputs(buf);
4743 0 : free(buf);
4744 :
4745 0 : if (fmt_jsonp) {
4746 0 : r->rsputs(");\n");
4747 : }
4748 : } else
4749 0 : r->rsputs("<DB_NO_KEY>");
4750 : }
4751 :
4752 0 : if (p->isparam("odb0")) {
4753 0 : show_text_header(r);
4754 0 : if (fmt_jsonp) {
4755 0 : r->rsputs(jsonp_callback);
4756 0 : r->rsputs("(");
4757 : }
4758 0 : if (fmt_xml) {
4759 0 : r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4760 0 : r->rsputs("<jcopy>\n");
4761 0 : r->rsputs("<data>\n");
4762 0 : } else if (fmt_json)
4763 0 : r->rsputs("[\n");
4764 : else
4765 0 : r->rsputs("");
4766 0 : for (int i=0 ; ; i++) {
4767 : char ppath[256];
4768 0 : sprintf(ppath, "odb%d", i);
4769 0 : if (!p->isparam(ppath))
4770 0 : break;
4771 0 : mstrlcpy(str, p->getparam(ppath), sizeof(str));
4772 :
4773 0 : if (i > 0) {
4774 0 : if (fmt_xml)
4775 0 : r->rsputs("</data>\n<data>\n");
4776 0 : else if (fmt_json)
4777 0 : r->rsputs(",\n");
4778 : else
4779 0 : r->rsputs("$#----#$\n");
4780 : }
4781 :
4782 0 : if (fmt_json)
4783 0 : status = db_find_link(hDB, 0, str, &hkey);
4784 : else
4785 0 : status = db_find_key(hDB, 0, str, &hkey);
4786 0 : if (status != DB_SUCCESS) {
4787 0 : if (fmt_xml)
4788 0 : r->rsputs("<DB_NO_KEY/>\n");
4789 0 : else if (fmt_json) {
4790 : char tmp[256];
4791 0 : sprintf(tmp, "{ \"/error\" : %d }\n", status);
4792 0 : r->rsputs(tmp);
4793 : } else
4794 0 : r->rsputs("<DB_NO_KEY>\n");
4795 0 : continue;
4796 0 : }
4797 :
4798 0 : int end = 0;
4799 0 : int bufsize = WEB_BUFFER_SIZE;
4800 0 : char* buf = (char *)malloc(bufsize);
4801 :
4802 0 : if (fmt_xml) {
4803 0 : db_copy_xml(hDB, hkey, buf, &bufsize, true);
4804 0 : const char* s = strstr(buf, "-->");
4805 0 : if (s)
4806 0 : s+=4;
4807 : else
4808 0 : s = buf;
4809 0 : r->rsputs(s);
4810 0 : } else if (fmt_json) {
4811 0 : db_copy_json_obsolete(hDB, hkey, &buf, &bufsize, &end, save_keys, follow_links, recurse);
4812 0 : r->rsputs(buf);
4813 : } else {
4814 0 : db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4815 0 : r->rsputs(buf);
4816 : }
4817 :
4818 0 : free(buf);
4819 0 : }
4820 :
4821 0 : if (fmt_xml)
4822 0 : r->rsputs("</data>\n</jcopy>\n");
4823 0 : else if (fmt_json)
4824 0 : r->rsputs("]\n");
4825 : else
4826 0 : r->rsputs("");
4827 :
4828 0 : if (fmt_jsonp) {
4829 0 : r->rsputs(");\n");
4830 : }
4831 : }
4832 0 : return;
4833 : }
4834 :
4835 : /* process "jkey" command */
4836 0 : if (equal_ustring(p->getparam("cmd"), "jkey")) {
4837 :
4838 : // test:
4839 : // curl "http://localhost:8080?cmd=jkey&odb0=/runinfo/run+number&odb1=/nonexistant&odb2=/&encoding=json&callback=aaa"
4840 :
4841 0 : show_text_header(r);
4842 :
4843 0 : if (jsonp) {
4844 0 : r->rsputs(jsonp_callback.c_str());
4845 0 : r->rsputs("(");
4846 : }
4847 :
4848 0 : if (multiple) {
4849 0 : switch (encoding) {
4850 0 : default:
4851 0 : break;
4852 0 : case ENCODING_JSON:
4853 0 : r->rsprintf("[ ");
4854 0 : break;
4855 : }
4856 : }
4857 :
4858 0 : for (unsigned i=0; i<odb.size(); i++) {
4859 0 : status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
4860 0 : if (status == DB_SUCCESS)
4861 0 : status = db_get_key(hDB, hkey, &key);
4862 0 : switch (encoding) {
4863 0 : default:
4864 0 : if (multiple && i>0)
4865 0 : r->rsputs("$#----#$\n");
4866 0 : if (status == DB_SUCCESS) {
4867 0 : r->rsprintf("%s\n", key.name);
4868 0 : r->rsprintf("TID_%s\n", rpc_tid_name(key.type));
4869 0 : r->rsprintf("%d\n", key.num_values);
4870 0 : r->rsprintf("%d\n", key.item_size);
4871 0 : r->rsprintf("%d\n", key.last_written);
4872 : } else {
4873 0 : r->rsputs("<DB_NO_KEY>\n");
4874 : }
4875 0 : break;
4876 0 : case ENCODING_JSON:
4877 0 : if (multiple && i>0)
4878 0 : r->rsprintf(", ");
4879 0 : if (status == DB_SUCCESS) {
4880 0 : r->rsprintf("{ ");
4881 0 : r->rsprintf("\"name\":\"%s\",", key.name);
4882 0 : r->rsprintf("\"type\":%d,", key.type);
4883 0 : r->rsprintf("\"type_name\":\"TID_%s\",", rpc_tid_name(key.type));
4884 0 : r->rsprintf("\"num_values\":%d,", key.num_values);
4885 0 : r->rsprintf("\"item_size\":%d,", key.item_size);
4886 0 : r->rsprintf("\"last_written\":%d", key.last_written);
4887 0 : r->rsprintf(" }");
4888 : } else {
4889 0 : r->rsprintf("{ \"/error\":%d }", status);
4890 : }
4891 0 : break;
4892 : }
4893 : }
4894 :
4895 0 : if (multiple) {
4896 0 : switch (encoding) {
4897 0 : default:
4898 0 : break;
4899 0 : case ENCODING_JSON:
4900 0 : r->rsprintf(" ]");
4901 0 : break;
4902 : }
4903 : }
4904 :
4905 0 : if (jsonp) {
4906 0 : r->rsputs(");\n");
4907 : }
4908 :
4909 0 : return;
4910 : }
4911 :
4912 : /* process "jcreate" command */
4913 0 : if (equal_ustring(p->getparam("cmd"), "jcreate")) {
4914 :
4915 : // test:
4916 : // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
4917 : // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo&type=7"
4918 : // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo70&type=7&arraylen=10"
4919 : // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s&type=12&strlen=32"
4920 : // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s5&type=12&strlen=32&arraylen=5"
4921 : // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo12s5x&type0=12&strlen0=32&arraylen0=5"
4922 :
4923 :
4924 0 : show_text_header(r);
4925 :
4926 0 : if (jsonp) {
4927 0 : r->rsputs(jsonp_callback.c_str());
4928 0 : r->rsputs("(");
4929 : }
4930 :
4931 0 : if (multiple) {
4932 : switch (encoding) {
4933 0 : default:
4934 : case ENCODING_JSON:
4935 0 : r->rsprintf("[ ");
4936 0 : break;
4937 : }
4938 : }
4939 :
4940 0 : for (unsigned i=0; i<odb.size(); i++) {
4941 0 : HNDLE hkey = 0;
4942 0 : int type = 0;
4943 0 : int arraylength = 0;
4944 0 : int strlength = 0;
4945 :
4946 0 : if (single) {
4947 0 : type = atoi(p->getparam("type"));
4948 0 : arraylength = atoi(p->getparam("arraylen"));
4949 0 : strlength = atoi(p->getparam("strlen"));
4950 : }
4951 0 : else if (multiple) {
4952 : char buf[256];
4953 0 : sprintf(buf, "type%d", i);
4954 0 : type = atoi(p->getparam(buf));
4955 0 : sprintf(buf, "arraylen%d", i);
4956 0 : arraylength = atoi(p->getparam(buf));
4957 0 : sprintf(buf, "strlen%d", i);
4958 0 : strlength = atoi(p->getparam(buf));
4959 : }
4960 :
4961 0 : status = db_create_key(hDB, 0, odb[i].c_str(), type);
4962 :
4963 0 : if (status == DB_SUCCESS) {
4964 0 : status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
4965 : }
4966 :
4967 0 : if (status == DB_SUCCESS && hkey && type == TID_STRING && strlength > 0) {
4968 0 : char* s = (char*)calloc(strlength, 1); // initialized to zero
4969 0 : status = db_set_data(hDB, hkey, s, strlength, 1, TID_STRING);
4970 0 : free(s);
4971 : }
4972 :
4973 0 : if (status == DB_SUCCESS && hkey && arraylength > 1) {
4974 0 : status = db_set_num_values(hDB, hkey, arraylength);
4975 : }
4976 :
4977 : switch (encoding) {
4978 0 : default:
4979 : case ENCODING_JSON:
4980 0 : if (multiple && i>0)
4981 0 : r->rsprintf(", ");
4982 0 : r->rsprintf("%d", status);
4983 0 : break;
4984 : }
4985 : }
4986 :
4987 0 : if (multiple) {
4988 : switch (encoding) {
4989 0 : default:
4990 : case ENCODING_JSON:
4991 0 : r->rsprintf(" ]");
4992 0 : break;
4993 : }
4994 : }
4995 :
4996 0 : if (jsonp) {
4997 0 : r->rsputs(");\n");
4998 : }
4999 :
5000 0 : return;
5001 : }
5002 :
5003 : /* process "jresize" command */
5004 0 : if (equal_ustring(p->getparam("cmd"), "jresize")) {
5005 :
5006 : // test:
5007 :
5008 : // curl "http://localhost:8080?cmd=jresize&odb=/test/foo70&arraylen=5"
5009 : // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&arraylen=5"
5010 : // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=16"
5011 : // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=30&arraylen=10"
5012 :
5013 0 : show_text_header(r);
5014 :
5015 0 : if (jsonp) {
5016 0 : r->rsputs(jsonp_callback.c_str());
5017 0 : r->rsputs("(");
5018 : }
5019 :
5020 0 : if (multiple) {
5021 : switch (encoding) {
5022 0 : default:
5023 : case ENCODING_JSON:
5024 0 : r->rsprintf("[ ");
5025 0 : break;
5026 : }
5027 : }
5028 :
5029 0 : for (unsigned i=0; i<odb.size(); i++) {
5030 : HNDLE hkey;
5031 : KEY key;
5032 0 : int arraylength = 0;
5033 0 : int strlength = 0;
5034 :
5035 0 : if (single) {
5036 0 : arraylength = atoi(p->getparam("arraylen"));
5037 0 : strlength = atoi(p->getparam("strlen"));
5038 : }
5039 0 : else if (multiple) {
5040 : char buf[256];
5041 0 : sprintf(buf, "arraylen%d", i);
5042 0 : arraylength = atoi(p->getparam(buf));
5043 0 : sprintf(buf, "strlen%d", i);
5044 0 : strlength = atoi(p->getparam(buf));
5045 : }
5046 :
5047 0 : status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5048 :
5049 0 : if (status == DB_SUCCESS && hkey) {
5050 0 : status = db_get_key(hDB, hkey, &key);
5051 : }
5052 :
5053 0 : if (status == DB_SUCCESS && hkey && key.type == TID_STRING && strlength > 0) {
5054 0 : int oldsize = key.item_size * key.num_values;
5055 0 : char* olddata = (char*)malloc(oldsize);
5056 0 : int size = oldsize;
5057 0 : status = db_get_data(hDB, hkey, olddata, &size, TID_STRING);
5058 :
5059 0 : if (status == DB_SUCCESS) {
5060 0 : int newsize = strlength * key.num_values;
5061 0 : char* s = (char*)calloc(newsize, 1); // initialized to zero
5062 0 : for (int k=0; k<key.num_values; k++) {
5063 0 : mstrlcpy(s + strlength*k, olddata + key.item_size*k, strlength);
5064 : }
5065 :
5066 0 : status = db_set_data(hDB, hkey, s, newsize, key.num_values, TID_STRING);
5067 0 : free(s);
5068 : }
5069 :
5070 0 : free(olddata);
5071 : }
5072 :
5073 0 : if (status == DB_SUCCESS && hkey && arraylength > 0) {
5074 0 : status = db_set_num_values(hDB, hkey, arraylength);
5075 : }
5076 :
5077 : switch (encoding) {
5078 0 : default:
5079 : case ENCODING_JSON:
5080 0 : if (multiple && i>0)
5081 0 : r->rsprintf(", ");
5082 0 : r->rsprintf("%d", status);
5083 0 : break;
5084 : }
5085 : }
5086 :
5087 0 : if (multiple) {
5088 : switch (encoding) {
5089 0 : default:
5090 : case ENCODING_JSON:
5091 0 : r->rsprintf(" ]");
5092 0 : break;
5093 : }
5094 : }
5095 :
5096 0 : if (jsonp) {
5097 0 : r->rsputs(");\n");
5098 : }
5099 :
5100 0 : return;
5101 : }
5102 :
5103 : /* process "jrename" command */
5104 0 : if (equal_ustring(p->getparam("cmd"), "jrename")) {
5105 :
5106 : // test:
5107 : // curl "http://localhost:8080?cmd=jrename&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
5108 : // curl "http://localhost:8080?cmd=jrename&odb=/test/foo&name=foofoo"
5109 :
5110 0 : show_text_header(r);
5111 :
5112 0 : if (jsonp) {
5113 0 : r->rsputs(jsonp_callback.c_str());
5114 0 : r->rsputs("(");
5115 : }
5116 :
5117 0 : if (multiple) {
5118 : switch (encoding) {
5119 0 : default:
5120 : case ENCODING_JSON:
5121 0 : r->rsprintf("[ ");
5122 0 : break;
5123 : }
5124 : }
5125 :
5126 0 : for (unsigned i=0; i<odb.size(); i++) {
5127 0 : const char* name = NULL;
5128 0 : if (single)
5129 0 : name = p->getparam("name");
5130 0 : else if (multiple) {
5131 : char buf[256];
5132 0 : sprintf(buf, "name%d", i);
5133 0 : name = p->getparam(buf);
5134 : }
5135 0 : status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5136 0 : if (status == DB_SUCCESS) {
5137 0 : status = db_rename_key(hDB, hkey, name);
5138 : }
5139 : switch (encoding) {
5140 0 : default:
5141 : case ENCODING_JSON:
5142 0 : if (multiple && i>0)
5143 0 : r->rsprintf(", ");
5144 0 : r->rsprintf("%d", status);
5145 0 : break;
5146 : }
5147 : }
5148 :
5149 0 : if (multiple) {
5150 : switch (encoding) {
5151 0 : default:
5152 : case ENCODING_JSON:
5153 0 : r->rsprintf(" ]");
5154 0 : break;
5155 : }
5156 : }
5157 :
5158 0 : if (jsonp) {
5159 0 : r->rsputs(");\n");
5160 : }
5161 :
5162 0 : return;
5163 : }
5164 :
5165 : /* process "jlink" command */
5166 0 : if (equal_ustring(p->getparam("cmd"), "jlink")) {
5167 :
5168 : // test:
5169 : // curl "http://localhost:8080?cmd=jlink&odb=/test/link&dest=/test/foo"
5170 : // curl "http://localhost:8080?cmd=jlink&odb0=/test/link0&dest0=/test/foo&odb1=/test/link1&dest1=/test/foo"
5171 :
5172 0 : show_text_header(r);
5173 :
5174 0 : if (jsonp) {
5175 0 : r->rsputs(jsonp_callback.c_str());
5176 0 : r->rsputs("(");
5177 : }
5178 :
5179 0 : if (multiple) {
5180 : switch (encoding) {
5181 0 : default:
5182 : case ENCODING_JSON:
5183 0 : r->rsprintf("[ ");
5184 0 : break;
5185 : }
5186 : }
5187 :
5188 0 : for (unsigned i=0; i<odb.size(); i++) {
5189 0 : const char* dest = NULL;
5190 0 : if (single)
5191 0 : dest = p->getparam("dest");
5192 0 : else if (multiple) {
5193 : char buf[256];
5194 0 : sprintf(buf, "dest%d", i);
5195 0 : dest = p->getparam(buf);
5196 : }
5197 :
5198 0 : status = db_create_link(hDB, 0, odb[i].c_str(), dest);
5199 :
5200 : switch (encoding) {
5201 : default:
5202 : case ENCODING_JSON:
5203 0 : if (multiple && i>0)
5204 0 : r->rsprintf(", ");
5205 0 : r->rsprintf("%d", status);
5206 0 : break;
5207 : }
5208 : }
5209 :
5210 0 : if (multiple) {
5211 : switch (encoding) {
5212 0 : default:
5213 : case ENCODING_JSON:
5214 0 : r->rsprintf(" ]");
5215 0 : break;
5216 : }
5217 : }
5218 :
5219 0 : if (jsonp) {
5220 0 : r->rsputs(");\n");
5221 : }
5222 :
5223 0 : return;
5224 : }
5225 :
5226 : /* process "jreorder" command */
5227 0 : if (equal_ustring(p->getparam("cmd"), "jreorder")) {
5228 :
5229 : // test:
5230 : // curl "http://localhost:8080?cmd=jreorder&odb0=/test/foo&index0=0&odb1=/test/bar&index1=1"
5231 : // curl "http://localhost:8080?cmd=jreorder&odb=/test/bar&index=0"
5232 :
5233 0 : show_text_header(r);
5234 :
5235 0 : if (jsonp) {
5236 0 : r->rsputs(jsonp_callback.c_str());
5237 0 : r->rsputs("(");
5238 : }
5239 :
5240 0 : if (multiple) {
5241 : switch (encoding) {
5242 0 : default:
5243 : case ENCODING_JSON:
5244 0 : r->rsprintf("[ ");
5245 0 : break;
5246 : }
5247 : }
5248 :
5249 0 : for (unsigned i=0; i<odb.size(); i++) {
5250 0 : int index = 0;
5251 0 : if (single)
5252 0 : index = atoi(p->getparam("index"));
5253 0 : else if (multiple) {
5254 : char buf[256];
5255 0 : sprintf(buf, "index%d", i);
5256 0 : index = atoi(p->getparam(buf));
5257 : }
5258 :
5259 0 : status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5260 0 : if (status == DB_SUCCESS) {
5261 0 : status = db_reorder_key(hDB, hkey, index);
5262 : }
5263 :
5264 : switch (encoding) {
5265 0 : default:
5266 : case ENCODING_JSON:
5267 0 : if (multiple && i>0)
5268 0 : r->rsprintf(", ");
5269 0 : r->rsprintf("%d", status);
5270 0 : break;
5271 : }
5272 : }
5273 :
5274 0 : if (multiple) {
5275 : switch (encoding) {
5276 0 : default:
5277 : case ENCODING_JSON:
5278 0 : r->rsprintf(" ]");
5279 0 : break;
5280 : }
5281 : }
5282 :
5283 0 : if (jsonp) {
5284 0 : r->rsputs(");\n");
5285 : }
5286 :
5287 0 : return;
5288 : }
5289 :
5290 : /* process "jdelete" command */
5291 0 : if (equal_ustring(p->getparam("cmd"), "jdelete")) {
5292 :
5293 : // test:
5294 : // curl "http://localhost:8080?cmd=jdelete&odb0=/test/foo&odb1=/nonexistant&odb2=/test/bar&encoding=json&callback=aaa"
5295 : // curl "http://localhost:8080?cmd=jdelete&odb=/test/foo"
5296 :
5297 0 : show_text_header(r);
5298 :
5299 0 : if (jsonp) {
5300 0 : r->rsputs(jsonp_callback.c_str());
5301 0 : r->rsputs("(");
5302 : }
5303 :
5304 0 : if (multiple) {
5305 : switch (encoding) {
5306 0 : default:
5307 : case ENCODING_JSON:
5308 0 : r->rsprintf("[ ");
5309 0 : break;
5310 : }
5311 : }
5312 :
5313 0 : for (unsigned i=0; i<odb.size(); i++) {
5314 0 : BOOL follow_links = 0;
5315 0 : status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
5316 0 : if (status == DB_SUCCESS) {
5317 0 : status = db_delete_key(hDB, hkey, follow_links);
5318 : }
5319 : switch (encoding) {
5320 0 : default:
5321 : case ENCODING_JSON:
5322 0 : if (multiple && i>0)
5323 0 : r->rsprintf(", ");
5324 0 : r->rsprintf("%d", status);
5325 0 : break;
5326 : }
5327 : }
5328 :
5329 0 : if (multiple) {
5330 : switch (encoding) {
5331 0 : default:
5332 : case ENCODING_JSON:
5333 0 : r->rsprintf(" ]");
5334 0 : break;
5335 : }
5336 : }
5337 :
5338 0 : if (jsonp) {
5339 0 : r->rsputs(");\n");
5340 : }
5341 :
5342 0 : return;
5343 : }
5344 :
5345 : /* process "jmsg" command */
5346 0 : if (equal_ustring(p->getparam("cmd"), "jmsg")) {
5347 :
5348 0 : if (p->getparam("f") && *p->getparam("f"))
5349 0 : mstrlcpy(facility, p->getparam("f"), sizeof(facility));
5350 : else
5351 0 : mstrlcpy(facility, "midas", sizeof(facility));
5352 :
5353 0 : n = 1;
5354 0 : if (p->getparam("n") && *p->getparam("n"))
5355 0 : n = atoi(p->getparam("n"));
5356 :
5357 0 : t = 0;
5358 0 : if (p->getparam("t") && p->getparam("t"))
5359 0 : t = atoi(p->getparam("t"));
5360 :
5361 0 : show_text_header(r);
5362 0 : char* messages = NULL;
5363 0 : int num_messages = 0;
5364 0 : cm_msg_retrieve2(facility, t, n, &messages, &num_messages);
5365 0 : if (messages) {
5366 0 : r->rsputs(messages);
5367 0 : free(messages);
5368 : }
5369 0 : return;
5370 : }
5371 :
5372 : /* process "jgenmsg" command */
5373 0 : if (equal_ustring(p->getparam("cmd"), "jgenmsg")) {
5374 :
5375 0 : if (p->getparam("facility") && *p->getparam("facility"))
5376 0 : mstrlcpy(facility, p->getparam("facility"), sizeof(facility));
5377 : else
5378 0 : mstrlcpy(facility, "midas", sizeof(facility));
5379 :
5380 0 : if (p->getparam("user") && *p->getparam("user"))
5381 0 : mstrlcpy(user, p->getparam("user"), sizeof(user));
5382 : else
5383 0 : mstrlcpy(user, "javascript_commands", sizeof(user));
5384 :
5385 0 : if (p->getparam("type") && *p->getparam("type"))
5386 0 : type = atoi(p->getparam("type"));
5387 : else
5388 0 : type = MT_INFO;
5389 :
5390 0 : if (p->getparam("msg") && *p->getparam("msg")) {
5391 0 : cm_msg1(type, __FILE__, __LINE__, facility, user, "%s", p->getparam("msg"));
5392 : }
5393 :
5394 0 : show_text_header(r);
5395 0 : r->rsputs("Message successfully created\n");
5396 0 : return;
5397 : }
5398 :
5399 : /* process "jalm" command */
5400 0 : if (equal_ustring(p->getparam("cmd"), "jalm")) {
5401 :
5402 0 : show_text_header(r);
5403 0 : std::string alarms;
5404 0 : al_get_alarms(&alarms);
5405 0 : r->rsputs(alarms.c_str());
5406 0 : return;
5407 0 : }
5408 :
5409 : /* process "jrpc" command */
5410 0 : if (equal_ustring(p->getparam("cmd"), "jrpc_rev0")) {
5411 0 : do_jrpc_rev0(p, r);
5412 0 : return;
5413 : }
5414 :
5415 : /* process "jrpc" command */
5416 0 : if (equal_ustring(p->getparam("cmd"), "jrpc_rev1")) {
5417 0 : do_jrpc_rev1(p, r);
5418 0 : return;
5419 : }
5420 :
5421 : /* process "jrpc" command */
5422 0 : if (equal_ustring(p->getparam("cmd"), "jrpc")) {
5423 0 : do_jrpc(p, r);
5424 0 : return;
5425 : }
5426 0 : }
5427 :
5428 : /*------------------------------------------------------------------*/
5429 :
5430 0 : void show_custom_page(Param* pp, Return* r, const char *cookie_cpwd)
5431 : {
5432 : int size, n_var, index, edit;
5433 : char keypath[256], type[32], *p, *ps;
5434 : char pwd[256], tail[256];
5435 : HNDLE hDB, hkey;
5436 : KEY key;
5437 : char data[TEXT_SIZE];
5438 :
5439 0 : std::string path = pp->getparam("page");
5440 :
5441 0 : if (path[0] == 0) {
5442 0 : show_error_404(r, "show_custom_page: Invalid custom page: \"page\" parameter is empty");
5443 0 : return;
5444 : }
5445 :
5446 0 : if (strstr(path.c_str(), "..")) {
5447 0 : std::string str;
5448 0 : str += "Invalid custom page name \'";
5449 0 : str += path;
5450 0 : str += "\' contains \'..\'";
5451 0 : show_error_404(r, str.c_str());
5452 0 : return;
5453 0 : }
5454 :
5455 0 : if (strstr(path.c_str(), ".gif")) {
5456 0 : show_custom_gif(r, path.c_str());
5457 0 : return;
5458 : }
5459 :
5460 0 : if (strchr(path.c_str(), '.')) {
5461 0 : show_custom_file(r, path.c_str());
5462 0 : return;
5463 : }
5464 :
5465 0 : cm_get_experiment_database(&hDB, NULL);
5466 :
5467 0 : std::string xpath = std::string("/Custom/") + path;
5468 0 : db_find_key(hDB, 0, xpath.c_str(), &hkey);
5469 0 : if (!hkey) {
5470 0 : xpath = std::string("/Custom/") + path + "&";
5471 0 : db_find_key(hDB, 0, xpath.c_str(), &hkey);
5472 0 : if (!hkey) {
5473 0 : xpath = std::string("/Custom/") + path + "!";
5474 0 : db_find_key(hDB, 0, xpath.c_str(), &hkey);
5475 : }
5476 : }
5477 :
5478 0 : if (hkey) {
5479 : char* ctext;
5480 : int status;
5481 :
5482 0 : status = db_get_key(hDB, hkey, &key);
5483 0 : assert(status == DB_SUCCESS);
5484 0 : size = key.total_size;
5485 0 : ctext = (char*)malloc(size);
5486 0 : status = db_get_data(hDB, hkey, ctext, &size, TID_STRING);
5487 0 : if (status != DB_SUCCESS) {
5488 0 : std::string errtext = msprintf("show_custom_page: Error: db_get_data() for \"%s\" status %d", xpath.c_str(), status);
5489 0 : show_error_404(r, errtext.c_str());
5490 0 : free(ctext);
5491 0 : return;
5492 0 : }
5493 :
5494 0 : std::string content_type = "text/html";
5495 :
5496 : /* check for link */
5497 0 : if (std::string(ctext).substr(0, 5) == "?cmd=") {
5498 0 : redirect(r, ctext);
5499 0 : free(ctext);
5500 0 : return;
5501 : }
5502 :
5503 : /* check if filename */
5504 0 : if (strchr(ctext, '\n') == 0) {
5505 0 : std::string full_filename = add_custom_path(ctext);
5506 0 : int fh = open(full_filename.c_str(), O_RDONLY | O_BINARY);
5507 0 : if (fh < 0) {
5508 0 : std::string str = msprintf("show_custom_page: Cannot open file \"%s\", open() errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5509 0 : show_error_404(r, str.c_str());
5510 0 : free(ctext);
5511 0 : return;
5512 0 : }
5513 0 : free(ctext);
5514 0 : ctext = NULL;
5515 0 : off_t off = lseek(fh, 0, SEEK_END);
5516 0 : if (off < 0) {
5517 0 : std::string str = msprintf("show_custom_page: Cannot open file \"%s\", lseek(SEEK_END) errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5518 0 : show_error_404(r, str.c_str());
5519 0 : free(ctext);
5520 0 : close(fh);
5521 0 : return;
5522 0 : }
5523 0 : size_t size = off;
5524 0 : lseek(fh, 0, SEEK_SET);
5525 0 : ctext = (char*)malloc(size+1);
5526 0 : ssize_t rd = read(fh, ctext, size);
5527 0 : if (rd > 0) {
5528 0 : ctext[rd] = 0; // make sure string is zero-terminated
5529 0 : size = rd;
5530 : } else {
5531 0 : ctext[0] = 0;
5532 0 : size = 0;
5533 : }
5534 0 : close(fh);
5535 :
5536 0 : content_type = get_content_type(full_filename.c_str());
5537 0 : }
5538 :
5539 : /* check for valid password */
5540 0 : if (equal_ustring(pp->getparam("cmd"), "Edit")) {
5541 0 : p = ps = ctext;
5542 0 : n_var = 0;
5543 : do {
5544 : char format[256];
5545 :
5546 0 : p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5547 0 : if (p == NULL)
5548 0 : break;
5549 0 : ps = strchr(p, '>') + 1;
5550 :
5551 0 : if (pwd[0] && n_var == atoi(pp->getparam("index"))) {
5552 : char str[256];
5553 0 : size = NAME_LENGTH;
5554 0 : mstrlcpy(str, path.c_str(), sizeof(str)); // FIXME: overflows "str"
5555 0 : if (strlen(str)>0 && str[strlen(str)-1] == '&')
5556 0 : str[strlen(str)-1] = 0;
5557 0 : std::string ppath;
5558 0 : ppath += "/Custom/Pwd/";
5559 0 : if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5560 0 : ppath += pp->getparam("pnam");
5561 : } else {
5562 0 : ppath += str;
5563 : }
5564 0 : str[0] = 0;
5565 0 : db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
5566 0 : if (!equal_ustring(cookie_cpwd, str)) {
5567 0 : show_error_404(r, "show_custom_page: Invalid password!");
5568 0 : free(ctext);
5569 0 : return;
5570 : } else
5571 0 : break;
5572 0 : }
5573 :
5574 0 : n_var++;
5575 0 : } while (p != NULL);
5576 : }
5577 :
5578 : /* process toggle command */
5579 0 : if (equal_ustring(pp->getparam("cmd"), "Toggle")) {
5580 :
5581 0 : if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5582 0 : std::string ppath;
5583 0 : ppath += "/Custom/Pwd/";
5584 0 : ppath += pp->getparam("pnam");
5585 0 : std::string str;
5586 0 : db_get_value_string(hDB, 0, ppath.c_str(), 0, &str, TRUE, 256);
5587 0 : if (!equal_ustring(cookie_cpwd, str.c_str())) {
5588 0 : show_error_404(r, "show_custom_page: Invalid password!");
5589 0 : free(ctext);
5590 0 : return;
5591 : }
5592 0 : }
5593 0 : std::string podb = pp->getparam("odb");
5594 0 : std::string::size_type pos = podb.find('[');
5595 0 : if (pos != std::string::npos) {
5596 0 : index = atoi(podb.substr(pos+1).c_str());
5597 0 : podb.resize(pos);
5598 : //printf("found index %d in [%s] [%s]\n", index, pp->getparam("odb"), podb.c_str());
5599 : } else
5600 0 : index = 0;
5601 :
5602 0 : if (db_find_key(hDB, 0, podb.c_str(), &hkey)) {
5603 0 : db_get_key(hDB, hkey, &key);
5604 0 : memset(data, 0, sizeof(data));
5605 0 : if (key.item_size <= (int)sizeof(data)) {
5606 0 : size = sizeof(data);
5607 0 : db_get_data_index(hDB, hkey, data, &size, index, key.type);
5608 0 : std::string data_str = db_sprintf(data, size, 0, key.type);
5609 0 : if (atoi(data_str.c_str()) == 0)
5610 0 : db_sscanf("1", data, &size, 0, key.type);
5611 : else
5612 0 : db_sscanf("0", data, &size, 0, key.type);
5613 0 : db_set_data_index(hDB, hkey, data, key.item_size, index, key.type);
5614 0 : }
5615 : }
5616 :
5617 : /* redirect (so that 'reload' does not toggle again) */
5618 0 : redirect(r, path.c_str());
5619 0 : free(ctext);
5620 0 : return;
5621 0 : }
5622 :
5623 : /* HTTP header */
5624 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
5625 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5626 0 : r->rsprintf("Content-Type: %s; charset=%s\r\n\r\n", content_type.c_str(), HTTP_ENCODING);
5627 :
5628 : /* interprete text, replace <odb> tags with ODB values */
5629 0 : p = ps = ctext;
5630 0 : n_var = 0;
5631 : do {
5632 : char format[256];
5633 0 : p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5634 0 : if (p != NULL)
5635 0 : *p = 0;
5636 0 : r->rsputs(ps);
5637 :
5638 0 : if (p == NULL)
5639 0 : break;
5640 0 : ps = strchr(p + 1, '>') + 1;
5641 :
5642 0 : show_odb_tag(pp, r, path.c_str(), keypath, format, n_var, edit, type, pwd, tail);
5643 0 : n_var++;
5644 :
5645 0 : } while (p != NULL);
5646 :
5647 0 : if (equal_ustring(pp->getparam("cmd"), "Set") || pp->isparam("cbi")) {
5648 : /* redirect (so that 'reload' does not change value) */
5649 0 : r->reset();
5650 0 : redirect(r, path.c_str());
5651 : }
5652 :
5653 0 : free(ctext);
5654 0 : ctext = NULL;
5655 0 : } else {
5656 0 : std::string str = msprintf("Invalid custom page: Page \"%s\" not found in ODB", path.c_str());
5657 0 : show_error_404(r, str.c_str());
5658 0 : return;
5659 0 : }
5660 0 : }
5661 :
5662 : /*------------------------------------------------------------------*/
5663 :
5664 0 : static void show_cnaf_page(Param* p, Return* rr)
5665 : {
5666 : char str[256];
5667 : int c, n, a, f, d, q, x, r, ia, id, w;
5668 : int i, size, status;
5669 : HNDLE hDB, hrootkey, hsubkey, hkey;
5670 :
5671 : static char client_name[NAME_LENGTH];
5672 : static HNDLE hconn = 0;
5673 :
5674 0 : cm_get_experiment_database(&hDB, NULL);
5675 :
5676 : /* find FCNA server if not specified */
5677 0 : if (hconn == 0) {
5678 : /* find client which exports FCNA function */
5679 0 : status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
5680 0 : if (status == DB_SUCCESS) {
5681 0 : for (i = 0;; i++) {
5682 0 : status = db_enum_key(hDB, hrootkey, i, &hsubkey);
5683 0 : if (status == DB_NO_MORE_SUBKEYS)
5684 0 : break;
5685 :
5686 0 : sprintf(str, "RPC/%d", RPC_CNAF16);
5687 0 : status = db_find_key(hDB, hsubkey, str, &hkey);
5688 0 : if (status == DB_SUCCESS) {
5689 0 : size = sizeof(client_name);
5690 0 : db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
5691 0 : break;
5692 : }
5693 : }
5694 : }
5695 :
5696 0 : if (client_name[0]) {
5697 0 : status = cm_connect_client(client_name, &hconn);
5698 0 : if (status != RPC_SUCCESS)
5699 0 : hconn = 0;
5700 : }
5701 : }
5702 :
5703 : /* header */
5704 0 : rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
5705 0 : rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5706 0 : rr->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
5707 :
5708 0 : rr->rsprintf("<html><head>\n");
5709 0 : rr->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
5710 0 : rr->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
5711 0 : rr->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
5712 0 : rr->rsprintf("<title>MIDAS CAMAC interface</title></head>\n");
5713 0 : rr->rsprintf("<body><form method=\"GET\" action=\"CNAF\">\n\n");
5714 :
5715 : /* title row */
5716 :
5717 0 : size = sizeof(str);
5718 0 : str[0] = 0;
5719 0 : db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
5720 :
5721 0 : rr->rsprintf("<table border=3 cellpadding=1>\n");
5722 0 : rr->rsprintf("<tr><th colspan=3>MIDAS experiment \"%s\"", str);
5723 :
5724 0 : if (client_name[0] == 0)
5725 0 : rr->rsprintf("<th colspan=3 class=\"redLight\">No CAMAC server running</tr>\n");
5726 0 : else if (hconn == 0)
5727 0 : rr->rsprintf("<th colspan=3 class=\"redLight\">Cannot connect to %s</tr>\n", client_name);
5728 : else
5729 0 : rr->rsprintf("<th colspan=3>CAMAC server: %s</tr>\n", client_name);
5730 :
5731 : /* default values */
5732 0 : c = n = 1;
5733 0 : a = f = d = q = x = 0;
5734 0 : r = 1;
5735 0 : ia = id = w = 0;
5736 :
5737 : /*---- menu buttons ----*/
5738 :
5739 0 : rr->rsprintf("<tr><td colspan=3>\n");
5740 0 : rr->rsprintf("<input type=submit name=cmd value=Execute>\n");
5741 :
5742 0 : rr->rsprintf("<td colspan=3>\n");
5743 0 : rr->rsprintf("<input type=submit name=cmd value=ODB>\n");
5744 0 : rr->rsprintf("<input type=submit name=cmd value=Status>\n");
5745 0 : rr->rsprintf("<input type=submit name=cmd value=Help>\n");
5746 0 : rr->rsprintf("</tr>\n\n");
5747 :
5748 : /* header */
5749 0 : rr->rsprintf("<tr><th>N");
5750 0 : rr->rsprintf("<th>A");
5751 0 : rr->rsprintf("<th>F");
5752 0 : rr->rsprintf("<th colspan=3>Data");
5753 :
5754 : /* execute commands */
5755 0 : size = sizeof(d);
5756 :
5757 0 : const char* cmd = p->getparam("cmd");
5758 0 : if (equal_ustring(cmd, "C cycle")) {
5759 0 : rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5760 : &q);
5761 :
5762 0 : rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">C cycle executed sucessfully</tr>\n");
5763 0 : } else if (equal_ustring(cmd, "Z cycle")) {
5764 0 : rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_ZINIT, 0, 0, 0, 0, 0, &d, &size, &x,
5765 : &q);
5766 :
5767 0 : rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">Z cycle executed sucessfully</tr>\n");
5768 0 : } else if (equal_ustring(cmd, "Clear inhibit")) {
5769 0 : rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5770 : &q);
5771 :
5772 : rr->rsprintf
5773 0 : ("<tr><td colspan=6 class=\"greenLight\">Clear inhibit executed sucessfully</tr>\n");
5774 0 : } else if (equal_ustring(cmd, "Set inhibit")) {
5775 0 : rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_SET, 0, 0, 0, 0, 0, &d, &size, &x,
5776 : &q);
5777 :
5778 : rr->rsprintf
5779 0 : ("<tr><td colspan=6 class=\"greenLight\">Set inhibit executed sucessfully</tr>\n");
5780 0 : } else if (equal_ustring(cmd, "Execute")) {
5781 0 : c = atoi(p->getparam("C"));
5782 0 : n = atoi(p->getparam("N"));
5783 0 : a = atoi(p->getparam("A"));
5784 0 : f = atoi(p->getparam("F"));
5785 0 : r = atoi(p->getparam("R"));
5786 0 : w = atoi(p->getparam("W"));
5787 0 : id = atoi(p->getparam("ID"));
5788 0 : ia = atoi(p->getparam("IA"));
5789 :
5790 0 : const char* pd = p->getparam("D");
5791 0 : if (strncmp(pd, "0x", 2) == 0)
5792 0 : sscanf(pd + 2, "%x", &d);
5793 : else
5794 0 : d = atoi(p->getparam("D"));
5795 :
5796 : /* limit repeat range */
5797 0 : if (r == 0)
5798 0 : r = 1;
5799 0 : if (r > 100)
5800 0 : r = 100;
5801 0 : if (w > 1000)
5802 0 : w = 1000;
5803 :
5804 0 : for (i = 0; i < r; i++) {
5805 0 : status = SUCCESS;
5806 :
5807 0 : if (hconn) {
5808 0 : size = sizeof(d);
5809 : status =
5810 0 : rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x,
5811 : &q);
5812 :
5813 0 : if (status == RPC_NET_ERROR) {
5814 : /* try to reconnect */
5815 : //cm_disconnect_client(hconn, FALSE);
5816 0 : status = cm_connect_client(client_name, &hconn);
5817 0 : if (status != RPC_SUCCESS) {
5818 0 : hconn = 0;
5819 0 : client_name[0] = 0;
5820 : }
5821 :
5822 0 : if (hconn) {
5823 0 : status = rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x, &q);
5824 : }
5825 : }
5826 : }
5827 :
5828 0 : if (status != SUCCESS) {
5829 : rr->rsprintf
5830 0 : ("<tr><td colspan=6 class=\"redLight\">Error executing function, code = %d</tr>",
5831 : status);
5832 : } else {
5833 0 : rr->rsprintf("<tr align=center><td>%d", n);
5834 0 : rr->rsprintf("<td>%d", a);
5835 0 : rr->rsprintf("<td>%d", f);
5836 0 : rr->rsprintf("<td colspan=3>%d / 0x%04X Q%d X%d", d, d, q, x);
5837 : }
5838 :
5839 0 : d += id;
5840 0 : a += ia;
5841 :
5842 0 : if (w > 0)
5843 0 : ss_sleep(w);
5844 : }
5845 : }
5846 :
5847 : /* input fields */
5848 : rr->rsprintf
5849 0 : ("<tr align=center><td><input type=text size=3 name=N value=%d>\n",
5850 : n);
5851 0 : rr->rsprintf("<td><input type=text size=3 name=A value=%d>\n", a);
5852 0 : rr->rsprintf("<td><input type=text size=3 name=F value=%d>\n", f);
5853 : rr->rsprintf
5854 0 : ("<td colspan=3><input type=text size=8 name=D value=%d></tr>\n",
5855 : d);
5856 :
5857 : /* control fields */
5858 0 : rr->rsprintf("<tr><td colspan=2>Repeat");
5859 0 : rr->rsprintf("<td><input type=text size=3 name=R value=%d>\n", r);
5860 :
5861 : rr->rsprintf
5862 0 : ("<td align=center colspan=3><input type=submit name=cmd value=\"C cycle\">\n");
5863 0 : rr->rsprintf("<input type=submit name=cmd value=\"Z cycle\">\n");
5864 :
5865 0 : rr->rsprintf("<tr><td colspan=2>Repeat delay [ms]");
5866 0 : rr->rsprintf("<td><input type=text size=3 name=W value=%d>\n", w);
5867 :
5868 : rr->rsprintf
5869 0 : ("<td align=center colspan=3><input type=submit name=cmd value=\"Set inhibit\">\n");
5870 0 : rr->rsprintf("<input type=submit name=cmd value=\"Clear inhibit\">\n");
5871 :
5872 0 : rr->rsprintf("<tr><td colspan=2>Data increment");
5873 0 : rr->rsprintf("<td><input type=text size=3 name=ID value=%d>\n", id);
5874 :
5875 : rr->rsprintf
5876 0 : ("<td colspan=3 align=center>Branch <input type=text size=3 name=B value=0>\n");
5877 :
5878 0 : rr->rsprintf("<tr><td colspan=2>A increment");
5879 0 : rr->rsprintf("<td><input type=text size=3 name=IA value=%d>\n", ia);
5880 :
5881 : rr->rsprintf
5882 0 : ("<td colspan=3 align=center>Crate <input type=text size=3 name=C value=%d>\n",
5883 : c);
5884 :
5885 0 : rr->rsprintf("</table></body>\r\n");
5886 0 : }
5887 :
5888 : /*------------------------------------------------------------------*/
5889 :
5890 : #ifdef HAVE_MSCB
5891 :
5892 : typedef struct {
5893 : signed char id;
5894 : char name[32];
5895 : } NAME_TABLE;
5896 :
5897 : static const NAME_TABLE prefix_table[] = {
5898 : {PRFX_PICO, "pico",},
5899 : {PRFX_NANO, "nano",},
5900 : {PRFX_MICRO, "micro",},
5901 : {PRFX_MILLI, "milli",},
5902 : {PRFX_NONE, "",},
5903 : {PRFX_KILO, "kilo",},
5904 : {PRFX_MEGA, "mega",},
5905 : {PRFX_GIGA, "giga",},
5906 : {PRFX_TERA, "tera",},
5907 : {99}
5908 : };
5909 :
5910 : static const NAME_TABLE unit_table[] = {
5911 :
5912 : {UNIT_METER, "meter",},
5913 : {UNIT_GRAM, "gram",},
5914 : {UNIT_SECOND, "second",},
5915 : {UNIT_MINUTE, "minute",},
5916 : {UNIT_HOUR, "hour",},
5917 : {UNIT_AMPERE, "ampere",},
5918 : {UNIT_KELVIN, "kelvin",},
5919 : {UNIT_CELSIUS, "deg. celsius",},
5920 : {UNIT_FARENHEIT, "deg. farenheit",},
5921 :
5922 : {UNIT_HERTZ, "hertz",},
5923 : {UNIT_PASCAL, "pascal",},
5924 : {UNIT_BAR, "bar",},
5925 : {UNIT_WATT, "watt",},
5926 : {UNIT_VOLT, "volt",},
5927 : {UNIT_OHM, "ohm",},
5928 : {UNIT_TESLA, "tesls",},
5929 : {UNIT_LITERPERSEC, "liter/sec",},
5930 : {UNIT_RPM, "RPM",},
5931 : {UNIT_FARAD, "farad",},
5932 :
5933 : {UNIT_BOOLEAN, "boolean",},
5934 : {UNIT_BYTE, "byte",},
5935 : {UNIT_WORD, "word",},
5936 : {UNIT_DWORD, "dword",},
5937 : {UNIT_ASCII, "ascii",},
5938 : {UNIT_STRING, "string",},
5939 : {UNIT_BAUD, "baud",},
5940 :
5941 : {UNIT_PERCENT, "percent",},
5942 : {UNIT_PPM, "RPM",},
5943 : {UNIT_COUNT, "counts",},
5944 : {UNIT_FACTOR, "factor",},
5945 : {0}
5946 : };
5947 :
5948 : /*------------------------------------------------------------------*/
5949 :
5950 0 : void print_mscb_var(char *value, char *evalue, char *unit, MSCB_INFO_VAR *info_chn, void *pdata)
5951 : {
5952 : char str[80];
5953 : signed short sdata;
5954 : unsigned short usdata;
5955 : signed int idata;
5956 : unsigned int uidata;
5957 : float fdata;
5958 : int i;
5959 :
5960 0 : value[0] = 0;
5961 0 : evalue[0] = 0;
5962 :
5963 0 : if (info_chn->unit == UNIT_STRING) {
5964 0 : memset(str, 0, sizeof(str));
5965 0 : strncpy(str, (char *)pdata, info_chn->width);
5966 0 : for (i = 0; i < (int) strlen(str); i++)
5967 0 : switch (str[i]) {
5968 0 : case 1:
5969 0 : strcat(value, "\\001");
5970 0 : break;
5971 0 : case 2:
5972 0 : strcat(value, "\\002");
5973 0 : break;
5974 0 : case 9:
5975 0 : strcat(value, "\\t");
5976 0 : break;
5977 0 : case 10:
5978 0 : strcat(value, "\\n");
5979 0 : break;
5980 0 : case 13:
5981 0 : strcat(value, "\\r");
5982 0 : break;
5983 0 : default:
5984 0 : value[strlen(value) + 1] = 0;
5985 0 : value[strlen(value)] = str[i];
5986 0 : break;
5987 : }
5988 0 : mstrlcpy(evalue, value, 256);
5989 : } else {
5990 0 : switch (info_chn->width) {
5991 0 : case 0:
5992 0 : strcpy(value, "0");
5993 0 : strcpy(evalue, "0");
5994 0 : break;
5995 :
5996 0 : case 1:
5997 0 : if (info_chn->flags & MSCBF_SIGNED) {
5998 0 : sprintf(value, "%d (0x%02X/", *((signed char *)pdata), *((signed char *)pdata));
5999 0 : sprintf(evalue, "%d", *((signed char *)pdata));
6000 : } else {
6001 0 : sprintf(value, "%u (0x%02X/", *((unsigned char *)pdata), *((unsigned char *)pdata));
6002 0 : sprintf(evalue, "%u", *((unsigned char *)pdata));
6003 : }
6004 :
6005 0 : for (i = 0; i < 8; i++)
6006 0 : if (*((unsigned char *)pdata) & (0x80 >> i))
6007 0 : sprintf(value + strlen(value), "1");
6008 : else
6009 0 : sprintf(value + strlen(value), "0");
6010 0 : sprintf(value + strlen(value), ")");
6011 0 : break;
6012 :
6013 0 : case 2:
6014 0 : if (info_chn->flags & MSCBF_SIGNED) {
6015 0 : sdata = *((signed short *)pdata);
6016 0 : WORD_SWAP(&sdata);
6017 0 : sprintf(value, "%d (0x%04X)", sdata, sdata);
6018 0 : sprintf(evalue, "%d", sdata);
6019 : } else {
6020 0 : usdata = *((unsigned short *)pdata);
6021 0 : WORD_SWAP(&usdata);
6022 0 : sprintf(value, "%u (0x%04X)", usdata, usdata);
6023 0 : sprintf(evalue, "%u", usdata);
6024 : }
6025 0 : break;
6026 :
6027 0 : case 4:
6028 0 : if (info_chn->flags & MSCBF_FLOAT) {
6029 0 : fdata = *((float *)pdata);
6030 0 : DWORD_SWAP(&fdata);
6031 0 : sprintf(value, "%1.6lg", fdata);
6032 0 : sprintf(evalue, "%1.6lg", fdata);
6033 : } else {
6034 0 : if (info_chn->flags & MSCBF_SIGNED) {
6035 0 : idata = *((signed int *)pdata);
6036 0 : DWORD_SWAP(&idata);
6037 0 : sprintf(value, "%d (0x%08X)", idata, idata);
6038 0 : sprintf(evalue, "%d", idata);
6039 : } else {
6040 0 : uidata = *((unsigned int *)pdata);
6041 0 : DWORD_SWAP(&uidata);
6042 0 : sprintf(value, "%u (0x%08X)", uidata, uidata);
6043 0 : sprintf(evalue, "%u", uidata);
6044 : }
6045 : }
6046 0 : break;
6047 : }
6048 : }
6049 :
6050 : /* evaluate prefix */
6051 0 : unit[0] = 0;
6052 0 : if (info_chn->prefix) {
6053 0 : for (i = 0; prefix_table[i].id != 99; i++)
6054 0 : if ((unsigned char)prefix_table[i].id == info_chn->prefix)
6055 0 : break;
6056 0 : if (prefix_table[i].id)
6057 0 : strcpy(unit, prefix_table[i].name);
6058 : }
6059 :
6060 : /* evaluate unit */
6061 0 : if (info_chn->unit && info_chn->unit != UNIT_STRING) {
6062 0 : for (i = 0; unit_table[i].id; i++)
6063 0 : if ((unsigned char)unit_table[i].id == info_chn->unit)
6064 0 : break;
6065 0 : if (unit_table[i].id)
6066 0 : strcat(unit, unit_table[i].name);
6067 : }
6068 0 : }
6069 :
6070 0 : static int cmp_int(const void *a, const void *b)
6071 : {
6072 0 : return *((int *)a) > *((int *)b);
6073 : }
6074 :
6075 : /*------------------------------------------------------------------*/
6076 :
6077 0 : void create_mscb_tree()
6078 : {
6079 : HNDLE hDB, hKeySubm, hKeyEq, hKeyAdr, hKey, hKeyDev;
6080 : KEY key;
6081 : int i, j, k, l, size, address[1000], dev_badr[1000], dev_adr[1000], dev_chn[1000],
6082 : n_address, n_dev_adr;
6083 : char mscb_dev[256], mscb_pwd[32], eq_name[32];
6084 :
6085 0 : cm_get_experiment_database(&hDB, NULL);
6086 :
6087 0 : db_create_key(hDB, 0, "MSCB/Submaster", TID_KEY);
6088 0 : db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6089 0 : assert(hKeySubm);
6090 :
6091 : /*---- go through equipment list ----*/
6092 0 : db_find_key(hDB, 0, "Equipment", &hKeyEq);
6093 0 : if (hKeyEq) {
6094 0 : for (i=0 ; ; i++) {
6095 0 : db_enum_key(hDB, hKeyEq, i, &hKey);
6096 0 : if (!hKey)
6097 0 : break;
6098 0 : db_get_key(hDB, hKey, &key);
6099 0 : strcpy(eq_name, key.name);
6100 0 : db_find_key(hDB, hKey, "Settings/Devices", &hKeyDev);
6101 0 : if (hKeyDev) {
6102 0 : for (j=0 ;; j++) {
6103 0 : db_enum_key(hDB, hKeyDev, j, &hKey);
6104 0 : if (!hKey)
6105 0 : break;
6106 :
6107 0 : if (db_find_key(hDB, hKey, "MSCB Address", &hKeyAdr) == DB_SUCCESS) {
6108 : /* mscbdev type of device */
6109 0 : size = sizeof(mscb_dev);
6110 0 : if (db_get_value(hDB, hKey, "Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6111 0 : continue;
6112 0 : size = sizeof(mscb_pwd);
6113 0 : if (db_get_value(hDB, hKey, "Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6114 0 : continue;
6115 :
6116 0 : size = sizeof(dev_adr);
6117 0 : db_get_data(hDB, hKeyAdr, dev_adr, &size, TID_INT);
6118 0 : n_dev_adr = size / sizeof(int);
6119 0 : } else if (db_find_key(hDB, hKey, "Block Address", &hKeyAdr) == DB_SUCCESS) {
6120 : /* mscbhvr type of device */
6121 0 : size = sizeof(mscb_dev);
6122 0 : if (db_get_value(hDB, hKey, "MSCB Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6123 0 : continue;
6124 0 : size = sizeof(mscb_pwd);
6125 0 : if (db_get_value(hDB, hKey, "MSCB Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6126 0 : continue;
6127 :
6128 0 : n_dev_adr = 0;
6129 0 : size = sizeof(dev_badr);
6130 0 : db_get_data(hDB, hKeyAdr, dev_badr, &size, TID_INT);
6131 0 : size = sizeof(dev_chn);
6132 0 : if (db_get_value(hDB, hKey, "Block Channels", dev_chn, &size, TID_INT, FALSE) == DB_SUCCESS) {
6133 0 : for (k=0 ; k<size/(int)sizeof(int) && n_dev_adr < (int)(sizeof(dev_adr)/sizeof(int)) ; k++) {
6134 0 : for (l=0 ; l<dev_chn[k] ; l++)
6135 0 : dev_adr[n_dev_adr++] = dev_badr[k]+l;
6136 : }
6137 : }
6138 : } else
6139 0 : continue;
6140 :
6141 : /* create or open submaster entry */
6142 0 : db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
6143 0 : if (!hKey) {
6144 0 : db_create_key(hDB, hKeySubm, mscb_dev, TID_KEY);
6145 0 : db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
6146 0 : assert(hKey);
6147 : }
6148 :
6149 : /* get old address list */
6150 0 : size = sizeof(address);
6151 0 : if (db_get_value(hDB, hKey, "Address", address, &size, TID_INT, FALSE) == DB_SUCCESS)
6152 0 : n_address = size / sizeof(int);
6153 : else
6154 0 : n_address = 0;
6155 :
6156 : /* merge with new address list */
6157 0 : for (k=0 ; k<n_dev_adr ; k++) {
6158 0 : for (l=0 ; l<n_address ; l++)
6159 0 : if (address[l] == dev_adr[k])
6160 0 : break;
6161 :
6162 0 : if (l == n_address)
6163 0 : address[n_address++] = dev_adr[k];
6164 : }
6165 :
6166 : /* sort address list */
6167 0 : qsort(address, n_address, sizeof(int), cmp_int);
6168 :
6169 : /* store new address list */
6170 0 : db_set_value(hDB, hKey, "Pwd", mscb_pwd, 32, 1, TID_STRING);
6171 0 : db_set_value(hDB, hKey, "Comment", eq_name, 32, 1, TID_STRING);
6172 0 : db_set_value(hDB, hKey, "Address", address, n_address*sizeof(int), n_address, TID_INT);
6173 : }
6174 : }
6175 : }
6176 : }
6177 0 : }
6178 :
6179 : /*------------------------------------------------------------------*/
6180 :
6181 0 : void show_mscb_page(Param* p, Return* r, int refresh)
6182 : {
6183 : int i, j, n, ind, fi, fd, status, size, n_addr, cur_node, adr, show_hidden;
6184 : unsigned int uptime;
6185 : BOOL comment_created;
6186 : float fvalue;
6187 : char *pd;
6188 : char dbuf[256], evalue[256], unit[256], cur_subm_name[256];
6189 : HNDLE hDB, hKeySubm, hKeyCurSubm, hKey, hKeyAddr, hKeyComm;
6190 : KEY key;
6191 : MSCB_INFO info;
6192 : MSCB_INFO_VAR info_var;
6193 : int ping_addr[0x10000];
6194 :
6195 0 : cm_get_experiment_database(&hDB, NULL);
6196 :
6197 0 : status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6198 0 : if (!hKeySubm)
6199 0 : create_mscb_tree();
6200 :
6201 0 : mstrlcpy(cur_subm_name, p->getparam("subm"), sizeof(cur_subm_name));
6202 0 : if (cur_subm_name[0] == 0) {
6203 0 : db_enum_key(hDB, hKeySubm, 0, &hKeyCurSubm);
6204 0 : if (!hKeyCurSubm) {
6205 : char errorstr[256];
6206 0 : sprintf(errorstr, "No submaster defined under /MSCB/Submaster");
6207 0 : show_error(r, errorstr);
6208 0 : return;
6209 : }
6210 0 : db_get_key(hDB, hKeyCurSubm, &key);
6211 0 : strcpy(cur_subm_name, key.name);
6212 : } else
6213 0 : db_find_key(hDB, hKeySubm, cur_subm_name, &hKeyCurSubm);
6214 :
6215 0 : if (p->isparam("node"))
6216 0 : cur_node = atoi(p->getparam("node"));
6217 : else
6218 0 : cur_node = -1;
6219 :
6220 : /* perform MSCB rescan */
6221 0 : if (p->isparam("mcmd") && equal_ustring(p->getparam("mcmd"), "Rescan") && p->isparam("subm")) {
6222 : /* create Pwd and Comment if not there */
6223 : char tmp[32];
6224 0 : size = 32;
6225 0 : tmp[0] = 0;
6226 0 : db_get_value(hDB, hKeyCurSubm, "Pwd", (void *)tmp, &size, TID_STRING, true);
6227 0 : tmp[0] = 0;
6228 0 : db_get_value(hDB, hKeyCurSubm, "Comment", (void *)tmp, &size, TID_STRING, true);
6229 :
6230 0 : db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6231 0 : std::vector<int> addr;
6232 0 : std::vector<char> node_comment;
6233 0 : if (hKeyAddr) {
6234 : /* get current address array */
6235 0 : db_get_key(hDB, hKeyAddr, &key);
6236 0 : n_addr = key.num_values;
6237 0 : addr.resize(n_addr);
6238 0 : size = sizeof(int)*n_addr;
6239 0 : db_get_data(hDB, hKeyAddr, addr.data(), &size, TID_INT);
6240 : } else {
6241 : /* create new address array */
6242 0 : db_create_key(hDB, hKeyCurSubm, "Address", TID_INT);
6243 0 : db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6244 0 : n_addr = 0;
6245 0 : addr.resize(1);
6246 : }
6247 :
6248 0 : comment_created = FALSE;
6249 0 : db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6250 0 : if (hKeyComm) {
6251 : /* get current node comments */
6252 0 : db_get_key(hDB, hKeyComm, &key);
6253 0 : node_comment.resize(32*key.num_values);
6254 0 : size = 32*key.num_values;
6255 0 : db_get_data(hDB, hKeyComm, node_comment.data(), &size, TID_STRING);
6256 : } else {
6257 : /* create new comment array */
6258 0 : db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6259 0 : db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6260 0 : node_comment.resize(32);
6261 0 : comment_created = TRUE;
6262 : }
6263 :
6264 0 : fd = mscb_init(cur_subm_name, 0, "", FALSE);
6265 0 : if (fd >= 0) {
6266 : /* fill table of possible addresses */
6267 0 : for (i=0 ; i<0x10000 ; i++)
6268 0 : ping_addr[i] = 0;
6269 0 : for (i=0 ; i<1000 ; i++) // 0..999
6270 0 : ping_addr[i] = 1;
6271 0 : for (i=0 ; i<0x10000 ; i+=100) // 100, 200, ...
6272 0 : ping_addr[i] = 1;
6273 0 : for (i=0 ; i<0x10000 ; i+= 0x100)
6274 0 : ping_addr[i] = 1; // 256, 512, ...
6275 0 : for (i=0xFF00 ; i<0x10000 ; i++)
6276 0 : ping_addr[i] = 1; // 0xFF00-0xFFFF
6277 :
6278 0 : for (ind = n = 0; ind < 0x10000; ind++) {
6279 0 : if (!ping_addr[ind])
6280 0 : continue;
6281 :
6282 0 : status = mscb_ping(fd, (unsigned short) ind, 1, 0);
6283 0 : if (status == MSCB_SUCCESS) {
6284 :
6285 : /* node found, search next 100 as well */
6286 0 : for (j=ind; j<ind+100 && j<0x10000 ; j++)
6287 0 : if (j >= 0)
6288 0 : ping_addr[j] = 1;
6289 :
6290 0 : status = mscb_info(fd, (unsigned short) ind, &info);
6291 :
6292 0 : if (status == MSCB_SUCCESS) {
6293 : /* check if node already in list */
6294 0 : for (j=0 ; j<n_addr ; j++)
6295 0 : if (addr[j] == ind)
6296 0 : break;
6297 0 : if (j == n_addr) {
6298 0 : addr.resize(n_addr+1);
6299 0 : addr[n_addr] = ind;
6300 0 : node_comment.resize(32*(n_addr+1));
6301 : /* use node name as default comment */
6302 0 : strncpy(node_comment.data()+n_addr*32, info.node_name, 32);
6303 0 : n_addr ++;
6304 0 : } else if (comment_created) {
6305 0 : node_comment.resize(32*n_addr);
6306 : /* use node name as default comment */
6307 0 : strncpy(node_comment.data()+j*32, info.node_name, 32);
6308 : }
6309 : }
6310 : }
6311 : }
6312 :
6313 0 : db_set_data(hDB, hKeyAddr, addr.data(), n_addr*sizeof(int), n_addr, TID_INT);
6314 0 : db_set_data(hDB, hKeyComm, node_comment.data(), n_addr*32, n_addr, TID_STRING);
6315 :
6316 : char redirstr[512];
6317 0 : sprintf(redirstr, "?cmd=mscb&subm=%s", cur_subm_name);
6318 0 : redirect(r, redirstr);
6319 0 : return;
6320 :
6321 : } else {
6322 : char errorstr[512];
6323 0 : sprintf(errorstr, "Cannot talk to submaster \"%s\"", cur_subm_name);
6324 0 : show_error(r, errorstr);
6325 0 : return;
6326 : }
6327 0 : }
6328 :
6329 : /* write data to node */
6330 0 : if (p->isparam("subm") && p->isparam("node") &&
6331 0 : p->isparam("idx") && p->isparam("value")) {
6332 0 : i = atoi(p->getparam("idx"));
6333 : char value[256];
6334 0 : mstrlcpy(value, p->getparam("value"), sizeof(value));
6335 :
6336 0 : fd = mscb_init(cur_subm_name, 0, "", FALSE);
6337 0 : if (fd >= 0) {
6338 0 : status = mscb_info_variable(fd,
6339 : (unsigned short) cur_node, (unsigned char) i, &info_var);
6340 0 : if (status == MSCB_SUCCESS) {
6341 0 : if (info_var.unit == UNIT_STRING) {
6342 : char valstr[256];
6343 0 : mstrlcpy(valstr, value, sizeof(valstr));
6344 0 : if (strlen(valstr) > 0 && valstr[strlen(valstr) - 1] == '\n')
6345 0 : valstr[strlen(valstr) - 1] = 0;
6346 :
6347 0 : status = mscb_write(fd, (unsigned short) cur_node,
6348 0 : (unsigned char) i, valstr, strlen(valstr) + 1);
6349 : } else {
6350 0 : if (info_var.flags & MSCBF_FLOAT) {
6351 0 : fvalue = (float) atof(value);
6352 0 : memcpy(&dbuf, &fvalue, sizeof(float));
6353 : } else {
6354 0 : if (value[1] == 'x')
6355 0 : sscanf(value + 2, "%x", (int *)&dbuf);
6356 : else
6357 0 : *((int *)dbuf) = atoi(value);
6358 : }
6359 :
6360 0 : status = mscb_write(fd, (unsigned short) cur_node,
6361 0 : (unsigned char) i, dbuf, info_var.width);
6362 : }
6363 : }
6364 : }
6365 : char redirstr[512];
6366 0 : sprintf(redirstr, "?cmd=mscb&subm=%s&node=%d", cur_subm_name, cur_node);
6367 0 : redirect(r, redirstr);
6368 0 : return;
6369 : }
6370 :
6371 0 : if (p->isparam("hidden"))
6372 0 : show_hidden = atoi(p->getparam("hidden"));
6373 : else
6374 0 : show_hidden = FALSE;
6375 :
6376 0 : show_header(r, "MSCB", "GET", "./", refresh);
6377 0 : r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6378 0 : r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6379 0 : show_navigation_bar(r, "MSCB");
6380 :
6381 : /* style sheet */
6382 0 : r->rsprintf("<style type=\"text/css\">\r\n");
6383 0 : r->rsprintf("select { width:150px; background-color:#FFFFE0; font-size:12px; }\r\n");
6384 0 : r->rsprintf(".subm {\r\n");
6385 0 : r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6386 0 : r->rsprintf(" padding:5px;\r\n");
6387 0 : r->rsprintf(" vertical-align:top;\r\n");
6388 0 : r->rsprintf(" font-size:16px;\r\n");
6389 0 : r->rsprintf(" border-right:1px solid #808080;\r\n");
6390 0 : r->rsprintf("}\r\n");
6391 0 : r->rsprintf(".node {\r\n");
6392 0 : r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6393 0 : r->rsprintf(" padding:5px;\r\n");
6394 0 : r->rsprintf(" vertical-align:top;\r\n");
6395 0 : r->rsprintf(" font-size:16px;\r\n");
6396 0 : r->rsprintf(" border-right:1px solid #808080;\r\n");
6397 0 : r->rsprintf("}\r\n");
6398 0 : r->rsprintf(".vars {\r\n");
6399 0 : r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6400 0 : r->rsprintf(" padding:5px;\r\n");
6401 0 : r->rsprintf(" vertical-align:top;\r\n");
6402 0 : r->rsprintf(" font-size:10px;\r\n");
6403 0 : r->rsprintf("}\r\n");
6404 0 : r->rsprintf(".v1 {\r\n");
6405 0 : r->rsprintf(" padding:3px;\r\n");
6406 0 : r->rsprintf(" font-weight:bold;\r\n");
6407 0 : r->rsprintf(" font-size:12px;\r\n");
6408 0 : r->rsprintf("}\r\n");
6409 0 : r->rsprintf(".v2 {\r\n");
6410 0 : r->rsprintf(" background-color:#F0F0F0;\r\n");
6411 0 : r->rsprintf(" padding:3px;\r\n");
6412 0 : r->rsprintf(" font-size:12px;\r\n");
6413 0 : r->rsprintf(" border:1px solid #808080;\r\n");
6414 0 : r->rsprintf(" border-right:1px solid #FFFFFF;\r\n");
6415 0 : r->rsprintf(" border-bottom:1px solid #FFFFFF;\r\n");
6416 0 : r->rsprintf("}\r\n");
6417 0 : r->rsprintf(".v3 {\r\n");
6418 0 : r->rsprintf(" padding:3px;\r\n");
6419 0 : r->rsprintf(" font-size:12px;\r\n");
6420 0 : r->rsprintf("}\r\n");
6421 0 : r->rsprintf("</style>\r\n\r\n");
6422 :
6423 : /* javascript */
6424 0 : r->rsprintf("<script type=\"text/javascript\">\r\n");
6425 0 : r->rsprintf("function mscb_edit(index, value)\r\n");
6426 0 : r->rsprintf("{\r\n");
6427 0 : r->rsprintf(" var new_value = prompt('Please enter new value', value);\r\n");
6428 0 : r->rsprintf(" if (new_value != undefined) {\r\n");
6429 0 : r->rsprintf(" window.location.search = '?cmd=mscb&subm=%s&node=%d&idx='+index+'&value='+new_value;\n", cur_subm_name, cur_node);
6430 0 : r->rsprintf(" }\n");
6431 0 : r->rsprintf("}\r\n");
6432 0 : r->rsprintf("</script>\r\n\r\n");
6433 :
6434 : /*---- main content ----*/
6435 :
6436 0 : r->rsprintf("<table class=\"mtable\">"); //main table
6437 0 : r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>MSCB</th><tr>");
6438 :
6439 : /*---- menu buttons ----*/
6440 :
6441 0 : r->rsprintf("<tr><td colspan=2>\n");
6442 0 : r->rsprintf("<table width=100%%><tr>\n");
6443 0 : r->rsprintf("<td><input type=button value=Reload onclick=\"window.location.search='?cmd=mscb&subm=%s&node=%d&rnd=%d'\"></td>\n", cur_subm_name, cur_node, rand());
6444 :
6445 0 : r->rsprintf("<tr><td colspan=\"2\" cellpadding=\"0\" cellspacing=\"0\">\r\n");
6446 :
6447 0 : status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6448 0 : if (status != DB_SUCCESS) {
6449 0 : r->rsprintf("<h1>No MSCB Submasters defined in ODB</h1>\r\n");
6450 0 : r->rsprintf("</td></tr>\r\n");
6451 0 : r->rsprintf("</table>\r\n"); //submaster table
6452 0 : r->rsprintf("</td></tr>\r\n");
6453 0 : r->rsprintf("</table>\r\n"); //main table
6454 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
6455 0 : r->rsprintf("</form>\n");
6456 0 : r->rsprintf("</body></html>\r\n");
6457 0 : return;
6458 : }
6459 :
6460 0 : r->rsprintf("<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"0\">");
6461 :
6462 : /*---- submaster list ----*/
6463 0 : r->rsprintf("<tr><td class=\"subm\">\r\n");
6464 0 : r->rsprintf("Submaster<hr>\r\n");
6465 :
6466 : /* count submasters */
6467 0 : for (i = 0;;i++) {
6468 0 : db_enum_key(hDB, hKeySubm, i, &hKey);
6469 0 : if (!hKey)
6470 0 : break;
6471 : }
6472 0 : if (i<2)
6473 0 : i = 2;
6474 :
6475 0 : r->rsprintf("<select name=\"subm\" id=\"subm\" size=%d ", i);
6476 0 : r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm='+document.getElementById('subm').value;\">\r\n");
6477 0 : hKeyCurSubm = 0;
6478 0 : for (i = 0;;i++) {
6479 0 : db_enum_key(hDB, hKeySubm, i, &hKey);
6480 0 : if (!hKey)
6481 0 : break;
6482 0 : db_get_key(hDB, hKey, &key);
6483 : char str[NAME_LENGTH+10+256];
6484 0 : mstrlcpy(str, key.name, sizeof(str));
6485 : char comment[256];
6486 0 : size = sizeof(comment);
6487 0 : if (db_get_value(hDB, hKey, "Comment", comment, &size, TID_STRING, FALSE) == DB_SUCCESS) {
6488 0 : mstrlcat(str, ": ", sizeof(str));
6489 0 : mstrlcat(str, comment, sizeof(str));
6490 : }
6491 :
6492 0 : if ((cur_subm_name[0] && equal_ustring(cur_subm_name, key.name)) ||
6493 0 : (cur_subm_name[0] == 0 && i == 0)) {
6494 0 : r->rsprintf("<option value=\"%s\" selected>%s</option>\r\n", key.name, str);
6495 0 : hKeyCurSubm = hKey;
6496 : } else
6497 0 : r->rsprintf("<option value=\"%s\">%s</option>\r\n", key.name, str);
6498 0 : }
6499 0 : r->rsprintf("</select>\r\n");
6500 :
6501 : /*---- node list ----*/
6502 0 : r->rsprintf("<td class=\"node\">\r\n");
6503 0 : r->rsprintf("Node ");
6504 :
6505 0 : r->rsprintf("<script type=\"text/javascript\">\n");
6506 0 : r->rsprintf("<!--\n");
6507 0 : r->rsprintf("function rescan()\n");
6508 0 : r->rsprintf("{\n");
6509 0 : r->rsprintf(" flag = confirm('Rescan can take up to one minute.');\n");
6510 0 : r->rsprintf(" if (flag == true)\n");
6511 0 : r->rsprintf(" window.location.href = '?cmd=mscb&mcmd=Rescan&subm=%s';\n", cur_subm_name);
6512 0 : r->rsprintf("}\n");
6513 0 : r->rsprintf("//-->\n");
6514 0 : r->rsprintf("</script>\n");
6515 :
6516 0 : r->rsprintf("<input type=button name=cmd value=\"Rescan\" onClick=\"rescan();\">");
6517 0 : r->rsprintf("<hr>\r\n");
6518 :
6519 0 : if (!hKeyCurSubm) {
6520 0 : r->rsprintf("No submaster found in ODB\r\n");
6521 0 : r->rsprintf("</td></tr>\r\n");
6522 0 : r->rsprintf("</table>\r\n"); //inner submaster table
6523 0 : r->rsprintf("</td></tr>\r\n");
6524 0 : r->rsprintf("</table>\r\n"); //submaster table
6525 0 : r->rsprintf("</td></tr>\r\n");
6526 0 : r->rsprintf("</table>\r\n"); //main table
6527 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
6528 0 : r->rsprintf("</form>\n");
6529 0 : r->rsprintf("</body></html>\r\n");
6530 0 : return;
6531 : }
6532 :
6533 0 : db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6534 0 : db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6535 :
6536 0 : i = 10;
6537 0 : if (hKeyAddr) {
6538 0 : db_get_key(hDB, hKeyAddr, &key);
6539 0 : i = key.num_values;
6540 :
6541 0 : if (hKeyComm == 0) {
6542 0 : db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6543 0 : db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6544 : }
6545 0 : db_get_key(hDB, hKeyComm, &key);
6546 0 : if (key.num_values < i) {
6547 0 : char str[32] = "";
6548 0 : for (int j=key.num_values ; j<i ; j++)
6549 0 : db_set_data_index(hDB, hKeyComm, str, 32, j, TID_STRING);
6550 : }
6551 : }
6552 0 : if (i < 2)
6553 0 : i = 2;
6554 :
6555 0 : r->rsprintf("<select name=\"node\" id=\"node\" size=%d ", i);
6556 0 : r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm=%s&node='+document.getElementById('node').value;\">\r\n", cur_subm_name);
6557 :
6558 0 : if (hKeyAddr) {
6559 0 : db_get_key(hDB, hKeyAddr, &key);
6560 0 : size = sizeof(adr);
6561 :
6562 : /* check if current node is in list */
6563 0 : for (i = 0; i<key.num_values ;i++) {
6564 0 : size = sizeof(adr);
6565 0 : db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6566 0 : if (adr == cur_node)
6567 0 : break;
6568 : }
6569 0 : if (i == key.num_values) // if not found, use first one in list
6570 0 : db_get_data_index(hDB, hKeyAddr, &cur_node, &size, 0, TID_INT);
6571 :
6572 0 : for (i = 0; i<key.num_values ;i++) {
6573 : char str[100+256];
6574 0 : size = sizeof(adr);
6575 0 : db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6576 0 : if (hKeyComm) {
6577 : char comment[256];
6578 0 : size = sizeof(comment);
6579 0 : db_get_data_index(hDB, hKeyComm, comment, &size, i, TID_STRING);
6580 0 : sprintf(str, "%d: %s", adr, comment);
6581 : } else {
6582 0 : sprintf(str, "%d", adr);
6583 : }
6584 0 : if (cur_node == 0 && i == 0)
6585 0 : cur_node = adr;
6586 0 : if (adr == cur_node)
6587 0 : r->rsprintf("<option selected>%s</option>\r\n", str);
6588 : else
6589 0 : r->rsprintf("<option>%s</option>\r\n", str);
6590 : }
6591 : }
6592 0 : r->rsprintf("</select>\r\n");
6593 :
6594 : /*---- node contents ----*/
6595 0 : r->rsprintf("<td class=\"vars\">\r\n");
6596 0 : r->rsprintf("<table>\r\n");
6597 0 : db_get_key(hDB, hKeyCurSubm, &key);
6598 0 : if (cur_node != -1)
6599 0 : r->rsprintf("<tr><td colspan=3 align=center><b>%s:%d</b>", key.name, cur_node);
6600 : else
6601 0 : r->rsprintf("<tr><td colspan=3 align=center><b>%s</b>", key.name);
6602 0 : r->rsprintf("<hr></td></tr>\r\n");
6603 :
6604 : char passwd[32];
6605 0 : passwd[0] = 0;
6606 0 : size = 32;
6607 0 : db_get_value(hDB, hKeyCurSubm, "Pwd", passwd, &size, TID_STRING, TRUE);
6608 :
6609 0 : fd = mscb_init(key.name, 0, passwd, FALSE);
6610 0 : if (fd < 0) {
6611 0 : if (fd == EMSCB_WRONG_PASSWORD)
6612 0 : r->rsprintf("<tr><td colspan=3><b>Invalid password</b></td>");
6613 : else
6614 0 : r->rsprintf("<tr><td colspan=3><b>Submaster does not respond</b></td>");
6615 0 : goto mscb_error;
6616 : }
6617 0 : mscb_set_eth_max_retry(fd, 3);
6618 0 : mscb_set_max_retry(1);
6619 :
6620 0 : status = mscb_ping(fd, cur_node, 0, 1);
6621 0 : if (status != MSCB_SUCCESS) {
6622 0 : r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6623 0 : goto mscb_error;
6624 : }
6625 0 : status = mscb_info(fd, (unsigned short) cur_node, &info);
6626 0 : if (status != MSCB_SUCCESS) {
6627 0 : r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6628 0 : goto mscb_error;
6629 : }
6630 : char tr16[17];
6631 0 : mstrlcpy(tr16, info.node_name, sizeof(tr16));
6632 0 : r->rsprintf("<tr><td class=\"v1\">Node name<td colspan=2 class=\"v2\">%s</tr>\n", tr16);
6633 0 : r->rsprintf("<tr><td class=\"v1\">GIT revision<td colspan=2 class=\"v2\">%d</tr>\n", info.revision);
6634 :
6635 0 : if (info.rtc[0] && info.rtc[0] != 0xFF) {
6636 0 : for (i=0 ; i<6 ; i++)
6637 0 : info.rtc[i] = (info.rtc[i] / 0x10) * 10 + info.rtc[i] % 0x10;
6638 0 : r->rsprintf("<tr><td class=\"v1\">Real Time Clock<td colspan=2 class=\"v2\">%02d-%02d-%02d %02d:%02d:%02d</td>\n",
6639 0 : info.rtc[0], info.rtc[1], info.rtc[2],
6640 0 : info.rtc[3], info.rtc[4], info.rtc[5]);
6641 : }
6642 :
6643 0 : status = mscb_uptime(fd, (unsigned short) cur_node, &uptime);
6644 0 : if (status == MSCB_SUCCESS)
6645 0 : r->rsprintf("<tr><td class=\"v1\">Uptime<td colspan=2 class=\"v2\">%dd %02dh %02dm %02ds</tr>\n",
6646 : uptime / (3600 * 24),
6647 0 : (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
6648 : (uptime % 60));
6649 :
6650 0 : r->rsprintf("<tr><td colspan=3><hr></td></tr>\r\n");
6651 :
6652 : /* check for hidden variables */
6653 0 : for (i=0 ; i < info.n_variables ; i++) {
6654 0 : mscb_info_variable(fd, cur_node, i, &info_var);
6655 0 : if (info_var.flags & MSCBF_HIDDEN)
6656 0 : break;
6657 : }
6658 0 : if (i < info.n_variables) {
6659 : char str[32];
6660 0 : strcpy(str, show_hidden ? " checked" : "");
6661 0 : r->rsprintf("<tr><td colspan=3><input type=checkbox%s name=\"hidden\" value=\"1\"", str);
6662 0 : r->rsprintf("onChange=\"window.location.search=?cmd=mscb&subm=%s&node=%d&hidden=1\">Display hidden variables<hr></td></tr>\r\n", cur_subm_name, cur_node);
6663 : }
6664 :
6665 : /* read variables in blocks of 100 bytes */
6666 0 : for (fi=0 ; fi < info.n_variables ; ) {
6667 0 : for (i=fi,size=0 ; i < info.n_variables && size < 100; i++) {
6668 0 : mscb_info_variable(fd, cur_node, i, &info_var);
6669 0 : size += info_var.width;
6670 : }
6671 :
6672 0 : size = sizeof(dbuf);
6673 0 : status = mscb_read_range(fd, cur_node, fi, i-1, dbuf, &size);
6674 0 : if (status != MSCB_SUCCESS) {
6675 0 : r->rsprintf("<tr><td colspan=3><b>Error reading data from node</b></td>");
6676 0 : goto mscb_error;
6677 : }
6678 0 : pd = dbuf;
6679 :
6680 0 : for (j=fi ; j<i ; j++) {
6681 0 : status = mscb_info_variable(fd, cur_node, j, &info_var);
6682 0 : if ((info_var.flags & MSCBF_HIDDEN) == 0 || show_hidden) {
6683 : char tr8[9];
6684 0 : mstrlcpy(tr8, info_var.name, sizeof(tr8));
6685 0 : r->rsprintf("<tr><td class=\"v1\">%s</td>\r\n", tr8);
6686 0 : r->rsprintf("<td class=\"v2\">\r\n");
6687 : char value[256];
6688 0 : print_mscb_var(value, evalue, unit, &info_var, pd);
6689 0 : r->rsprintf("<a href=\"#\" onClick=\"mscb_edit(%d,'%s')\">%s</a>",
6690 : j, evalue, value);
6691 0 : r->rsprintf("</td><td class=\"v3\">%s</td>", unit);
6692 0 : r->rsprintf("</tr>\r\n");
6693 : }
6694 0 : pd += info_var.width;
6695 : }
6696 :
6697 0 : fi = i;
6698 : }
6699 :
6700 0 : mscb_error:
6701 0 : r->rsprintf("</tr></table>\r\n");
6702 0 : r->rsprintf("</td></tr></table>\r\n");
6703 0 : r->rsprintf("</td></tr></table>\r\n");
6704 0 : r->rsprintf("</td></tr></table>\r\n");
6705 0 : r->rsprintf("</div></body></html>\r\n");
6706 : }
6707 :
6708 : #endif // HAVE_MSCB
6709 :
6710 : /*------------------------------------------------------------------*/
6711 :
6712 0 : void show_password_page(Return* r, const char* dec_path, const char *password)
6713 : {
6714 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6715 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6716 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6717 :
6718 0 : r->rsprintf("<html><head>\n");
6719 0 : r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6720 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6721 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6722 0 : r->rsprintf("<title>Enter password</title></head><body>\n\n");
6723 :
6724 0 : r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6725 :
6726 : /*---- page header ----*/
6727 0 : r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6728 :
6729 0 : r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6730 0 : if (password[0])
6731 0 : r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6732 :
6733 0 : r->rsprintf("<tr><th>Please enter password</tr>\n");
6734 0 : r->rsprintf("<tr><td align=center><input type=password name=pwd></tr>\n");
6735 0 : r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6736 :
6737 0 : r->rsprintf("</table>\n");
6738 :
6739 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
6740 0 : r->rsprintf("</form>\n");
6741 0 : r->rsprintf("</body></html>\r\n");
6742 0 : }
6743 :
6744 : /*------------------------------------------------------------------*/
6745 :
6746 0 : BOOL check_web_password(Return* r, HNDLE hDB, const char* dec_path, const char *password, const char *redir)
6747 : {
6748 : HNDLE hkey;
6749 : INT size;
6750 : char str[256];
6751 :
6752 : /* check for password */
6753 0 : db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
6754 0 : if (hkey) {
6755 0 : size = sizeof(str);
6756 0 : db_get_data(hDB, hkey, str, &size, TID_STRING);
6757 0 : if (strcmp(password, str) == 0)
6758 0 : return TRUE;
6759 :
6760 : /* show web password page */
6761 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6762 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6763 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6764 :
6765 0 : r->rsprintf("<html><head>\n");
6766 0 : r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6767 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6768 0 : r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6769 0 : r->rsprintf("<title>Enter password</title></head><body>\n\n");
6770 :
6771 0 : r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6772 :
6773 : /* define hidden fields for current experiment and destination */
6774 0 : if (redir[0])
6775 0 : r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", redir);
6776 :
6777 : /*---- page header ----*/
6778 0 : r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6779 :
6780 0 : r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6781 :
6782 0 : if (password[0])
6783 0 : r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6784 :
6785 : r->rsprintf
6786 0 : ("<tr><th>Please enter password to obtain write access</tr>\n");
6787 0 : r->rsprintf("<tr><td align=center><input type=password name=wpwd></tr>\n");
6788 0 : r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6789 :
6790 0 : r->rsprintf("</table>\n");
6791 :
6792 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
6793 0 : r->rsprintf("</form>\n");
6794 0 : r->rsprintf("</body></html>\r\n");
6795 :
6796 0 : return FALSE;
6797 : } else
6798 0 : return TRUE;
6799 : }
6800 :
6801 : /*------------------------------------------------------------------*/
6802 :
6803 0 : void show_odb_page(Param* pp, Return* r, const char* dec_path, int write_access)
6804 : {
6805 : int keyPresent, size, status, line, link_index;
6806 : char colspan;
6807 : char style[32];
6808 : HNDLE hDB, hkey, hkeyroot;
6809 : KEY key;
6810 : DWORD delta;
6811 :
6812 0 : cm_get_experiment_database(&hDB, NULL);
6813 :
6814 : //printf("path [%s]\n", dec_path);
6815 :
6816 0 : if (strcmp(dec_path, "root") == 0) {
6817 0 : dec_path = "";
6818 : }
6819 :
6820 : char xdecpath[256];
6821 0 : mstrlcpy(xdecpath, dec_path, sizeof(xdecpath));
6822 0 : if (strrchr(xdecpath, '/'))
6823 0 : mstrlcpy(xdecpath, strrchr(xdecpath, '/')+1, sizeof(xdecpath));
6824 0 : if (xdecpath[0] == 0)
6825 0 : mstrlcpy(xdecpath, "root", sizeof(xdecpath));
6826 0 : show_header(r, "MIDAS online database", "", xdecpath, 0);
6827 :
6828 : /* use javascript file */
6829 0 : r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6830 0 : r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6831 0 : r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
6832 0 : r->rsprintf("<script type=\"text/javascript\" src=\"controls.js\"></script>\n");
6833 :
6834 : /* find key via path */
6835 0 : status = db_find_key(hDB, 0, dec_path, &hkeyroot);
6836 0 : if (status != DB_SUCCESS) {
6837 0 : r->rsprintf("Error: cannot find key %s<P>\n", dec_path);
6838 0 : r->rsprintf("</body></html>\r\n");
6839 0 : return;
6840 : }
6841 :
6842 : char xdec_path[MAX_ODB_PATH];
6843 :
6844 : /* if key is not of type TID_KEY, cut off key name */
6845 0 : db_get_key(hDB, hkeyroot, &key);
6846 0 : if (key.type != TID_KEY) {
6847 0 : mstrlcpy(xdec_path, dec_path, sizeof(xdec_path));
6848 :
6849 : /* strip variable name from path */
6850 0 : char* p = xdec_path + strlen(xdec_path) - 1;
6851 0 : while (*p && *p != '/')
6852 0 : *p-- = 0;
6853 0 : if (*p == '/')
6854 0 : *p = 0;
6855 :
6856 0 : status = db_find_key(hDB, 0, xdec_path, &hkeyroot);
6857 0 : if (status != DB_SUCCESS) {
6858 0 : r->rsprintf("Error: cannot find key %s<P>\n", xdec_path);
6859 0 : r->rsprintf("</body></html>\r\n");
6860 0 : return;
6861 : }
6862 :
6863 0 : dec_path = xdec_path;
6864 : }
6865 :
6866 : //mstrlcpy(enc_path, dec_path, enc_path_size);
6867 : //urlEncode(enc_path, enc_path_size);
6868 :
6869 0 : std::string odbpath = db_get_path(hDB, hkeyroot);
6870 :
6871 : /*---- navigation bar ----*/
6872 :
6873 0 : colspan = 7;
6874 :
6875 0 : if (elog_mode) {
6876 0 : r->rsprintf("<table class=\"mtableheader\">\n");
6877 0 : r->rsprintf("<tr><td colspan=%d>\n", colspan);
6878 0 : r->rsprintf("<input type=button value=ELog onclick=\"self.location=\'?cmd=Alarms\';\">\n");
6879 0 : r->rsprintf("</td></tr></table>\n\n");
6880 : } else
6881 0 : show_navigation_bar(r, "ODB");
6882 :
6883 : /*---- begin ODB directory table ----*/
6884 :
6885 0 : r->rsprintf("<table class=\"mtable\" style=\"border-spacing:0px;\">\n");
6886 0 : r->rsprintf("<tr><th colspan=%d class=\"mtableheader\">Online Database Browser</tr>\n", colspan);
6887 : //buttons:
6888 0 : if(!elog_mode){
6889 0 : r->rsprintf("<tr><td colspan=%d>\n", colspan);
6890 0 : r->rsprintf("<input type=button value=Find onclick=\"self.location=\'?cmd=Find\';\">\n");
6891 0 : r->rsprintf("<input type=button value=Create onclick=\"dlgShow('dlgCreate')\">\n");
6892 0 : r->rsprintf("<input type=button value=Link onclick=\"dlgShow('dlgLink')\">\n");
6893 0 : r->rsprintf("<input type=button value=Delete onclick=\"dlgShow('dlgDelete')\">\n");
6894 0 : r->rsprintf("<input type=button value=\"Create Elog from this page\" onclick=\"self.location=\'?cmd=Create Elog from this page&odb_path=%s\';\">\n", urlEncode(odbpath.c_str()).c_str());
6895 0 : r->rsprintf("<input type=button value=\"Show open records\" onclick=\"self.location=\'?cmd=odb_sor&odb_path=%s\';\">\n", urlEncode(odbpath.c_str()).c_str());
6896 0 : r->rsprintf("<input type=button value=\"Show ODB clients\" onclick=\"self.location=\'?cmd=odb_scl\';\">\n");
6897 0 : r->rsprintf("</td></tr>\n");
6898 : }
6899 :
6900 : /*---- Build the Delete dialog------------------------------------*/
6901 :
6902 0 : std::string dd = "";
6903 :
6904 0 : dd += "<!-- Demo dialog -->\n";
6905 0 : dd += "<div id=\"dlgDelete\" class=\"dlgFrame\">\n";
6906 0 : dd += "<div class=\"dlgTitlebar\">Delete ODB entry</div>\n";
6907 0 : dd += "<div class=\"dlgPanel\">\n";
6908 0 : dd += "<div id=odbpath>";
6909 0 : dd += "\"";
6910 0 : dd += MJsonNode::Encode(odbpath.c_str());
6911 0 : dd += "\"";
6912 0 : dd += "</div>\n";
6913 0 : dd += "<div><br></div>\n";
6914 :
6915 0 : dd += "<table class=\"dialogTable\">\n";
6916 0 : dd += "<th colspan=2>Delete ODB entries:</th>\n";
6917 :
6918 0 : std::vector<std::string> delete_list;
6919 :
6920 0 : int count_delete = 0;
6921 :
6922 : /*---- ODB display -----------------------------------------------*/
6923 :
6924 : /* display root key */
6925 0 : r->rsprintf("<tr><td colspan=%d class='ODBpath'><b>", colspan);
6926 0 : r->rsprintf("<a href=\"?cmd=oldodb\">/</a> \n");
6927 :
6928 0 : std::string enc_root_path;
6929 :
6930 : /*---- display path ----*/
6931 : {
6932 0 : const char* p = dec_path;
6933 0 : while (*p) {
6934 0 : std::string pd;
6935 0 : while (*p && *p != '/')
6936 0 : pd += *p++;
6937 :
6938 0 : enc_root_path += urlEncode(pd.c_str());
6939 :
6940 0 : if (pd.length() > 0)
6941 0 : r->rsprintf("<a href=\"?cmd=oldodb&odb_path=%s\">%s</a>\n / ", enc_root_path.c_str(), pd.c_str());
6942 :
6943 0 : enc_root_path += "/";
6944 0 : if (*p == '/')
6945 0 : p++;
6946 0 : }
6947 : }
6948 :
6949 0 : r->rsprintf("</b></tr>\n");
6950 :
6951 : /* enumerate subkeys */
6952 0 : keyPresent = 0;
6953 0 : for(int scan=0; scan<2; scan++){
6954 0 : if(scan==1 && keyPresent==1) {
6955 0 : r->rsprintf("<tr class=\"titleRow\">\n");
6956 0 : r->rsprintf("<th class=\"ODBkey\">Key</th>\n");
6957 0 : r->rsprintf("<th class=\"ODBvalue\">Value ");
6958 0 : r->rsprintf("<script type=\"text/javascript\">\n");
6959 0 : r->rsprintf("function expand()\n");
6960 0 : r->rsprintf("{\n");
6961 0 : r->rsprintf(" var n = document.getElementsByName('ext');\n");
6962 0 : r->rsprintf(" for (i=0 ; i<n.length ; i++) {\n");
6963 0 : r->rsprintf(" if (n[i].style.display == 'none')\n");
6964 0 : r->rsprintf(" n[i].style.display = 'table-cell';\n");
6965 0 : r->rsprintf(" else\n");
6966 0 : r->rsprintf(" n[i].style.display = 'none';\n");
6967 0 : r->rsprintf(" }\n");
6968 0 : r->rsprintf(" if (document.getElementById('expp').expflag === true) {\n");
6969 0 : r->rsprintf(" document.getElementById('expp').expflag = false;\n");
6970 0 : r->rsprintf(" document.getElementById('expp').innerHTML = '⇥';\n");
6971 0 : r->rsprintf(" } else {\n");
6972 0 : r->rsprintf(" document.getElementById('expp').expflag = true;\n");
6973 0 : r->rsprintf(" document.getElementById('expp').innerHTML = '⇤';\n");
6974 0 : r->rsprintf(" }\n");
6975 0 : r->rsprintf("}\n");
6976 0 : r->rsprintf("</script>");
6977 0 : r->rsprintf("<div style=\"display:inline;float:right\"><a id=\"expp\"href=\"#\" onClick=\"expand();return false;\">⇥</div>");
6978 0 : r->rsprintf("</th>\n");
6979 0 : r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Type</th>\n");
6980 0 : r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">#Val</th>\n");
6981 0 : r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Size</th>\n");
6982 0 : r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Written</th>\n");
6983 0 : r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Mode</th>\n");
6984 0 : r->rsprintf("</tr>\n");
6985 : }
6986 0 : line = 0;
6987 0 : for (int i = 0;; i++) {
6988 0 : db_enum_link(hDB, hkeyroot, i, &hkey);
6989 0 : if (!hkey)
6990 0 : break;
6991 0 : db_get_link(hDB, hkey, &key);
6992 :
6993 0 : if (scan == 0) {
6994 0 : delete_list.push_back(key.name);
6995 : }
6996 :
6997 0 : if (line % 2 == 0)
6998 0 : mstrlcpy(style, "ODBtableEven", sizeof(style));
6999 : else
7000 0 : mstrlcpy(style, "ODBtableOdd", sizeof(style));
7001 :
7002 0 : std::string keyname = key.name;
7003 0 : std::string enc_keyname = urlEncode(key.name);
7004 :
7005 0 : std::string enc_full_path = enc_root_path + enc_keyname;
7006 :
7007 0 : std::string odb_path = dec_path;
7008 0 : if (odb_path.length() > 0 && odb_path[odb_path.length() - 1] != '/')
7009 0 : odb_path += "/";
7010 0 : odb_path += key.name;
7011 :
7012 : /* resolve links */
7013 0 : std::string enc_link_ref;
7014 : char link_name[MAX_ODB_PATH];
7015 0 : link_name[0] = 0;
7016 0 : status = DB_SUCCESS;
7017 0 : if (key.type == TID_LINK) {
7018 0 : size = sizeof(link_name);
7019 0 : db_get_link_data(hDB, hkey, link_name, &size, TID_LINK);
7020 :
7021 0 : status = db_find_key(hDB, 0, link_name, &hkey);
7022 :
7023 0 : if (status == DB_SUCCESS)
7024 0 : db_get_key(hDB, hkey, &key);
7025 :
7026 : //sprintf(link_ref, "?cmd=Set&odb_path=%s", full_path);
7027 0 : enc_link_ref = "?cmd=Set&odb_path=";
7028 0 : enc_link_ref += enc_full_path;
7029 :
7030 0 : if (status == DB_SUCCESS && link_name[0] == 0) {
7031 : // fake the case when an empty link somehow resolves
7032 0 : sprintf(link_name, "%s", "(empty)");
7033 : }
7034 : }
7035 :
7036 0 : std::string enc_ref;
7037 :
7038 0 : if (link_name[0]) {
7039 0 : if (enc_root_path.back() == '/' && link_name[0] == '/') {
7040 : //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name+1);
7041 0 : enc_ref = "";
7042 0 : enc_ref += "?cmd=Set&odb_path=";
7043 0 : enc_ref += enc_root_path;
7044 0 : enc_ref += urlEncode(link_name + 1);
7045 : } else {
7046 : //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name);
7047 0 : enc_ref = "";
7048 0 : enc_ref += "?cmd=Set&odb_path=";
7049 0 : enc_ref += enc_root_path;
7050 0 : enc_ref += urlEncode(link_name);
7051 : }
7052 : } else {
7053 : //sprintf(ref, "?cmd=Set&odb_path=%s", full_path);
7054 0 : enc_ref = "";
7055 0 : enc_ref += "?cmd=Set&odb_path=";
7056 0 : enc_ref += enc_full_path;
7057 : }
7058 :
7059 0 : if (status != DB_SUCCESS) {
7060 0 : if (scan == 1) {
7061 0 : r->rsprintf("<tr><td class=\"yellowLight\">");
7062 0 : r->rsprintf("%s <i>→ <a href=\"%s\">%s</a></i><td><b><div style=\"color:red\"><cannot resolve link></div></b></tr>\n", keyname.c_str(), enc_link_ref.c_str(), link_name[0]?link_name:"(empty)");
7063 : }
7064 : } else {
7065 :
7066 0 : if (key.type == TID_KEY && scan == 0) {
7067 : /* for keys, don't display data value */
7068 0 : r->rsprintf("<tr><td colspan=%d class=\"ODBdirectory\"><a href=\"?cmd=oldodb&odb_path=%s\">▶ %s</a>\n", colspan, enc_full_path.c_str(), keyname.c_str());
7069 0 : if (link_name[0])
7070 0 : r->rsprintf("<i>→ <a href=\"%s\">%s</a></i>", enc_link_ref.c_str(), link_name);
7071 0 : r->rsprintf("</tr>\n");
7072 0 : } else if(key.type != TID_KEY && scan == 1) {
7073 :
7074 0 : if (strchr(link_name, '['))
7075 0 : link_index = atoi(strchr(link_name, '[')+1);
7076 : else
7077 0 : link_index = -1;
7078 :
7079 : /* display single value */
7080 0 : if (key.num_values == 1 || link_index != -1) {
7081 : char data[TEXT_SIZE];
7082 0 : size = sizeof(data);
7083 0 : db_get_data(hDB, hkey, data, &size, key.type);
7084 :
7085 0 : std::string data_str;
7086 :
7087 0 : if (link_index != -1)
7088 0 : data_str = db_sprintf(data, key.item_size, link_index, key.type);
7089 : else
7090 0 : data_str = db_sprintf(data, key.item_size, 0, key.type);
7091 :
7092 0 : if (key.type == TID_STRING) {
7093 0 : if (size == sizeof(data)) {
7094 0 : data_str += "...(truncated)";
7095 : }
7096 : }
7097 :
7098 0 : std::string hex_str;
7099 :
7100 0 : if (key.type != TID_STRING) {
7101 0 : if (link_index != -1)
7102 0 : hex_str = db_sprintfh(data, key.item_size, link_index, key.type);
7103 : else
7104 0 : hex_str = db_sprintfh(data, key.item_size, 0, key.type);
7105 : }
7106 :
7107 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7108 0 : data_str = "(empty)";
7109 0 : hex_str = "";
7110 : }
7111 :
7112 0 : r->rsprintf("<tr>\n");
7113 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
7114 0 : if (link_name[0]) {
7115 0 : r->rsprintf("<td class=\"ODBkey\">\n");
7116 0 : r->rsprintf("%s <i>→ ", keyname.c_str());
7117 0 : r->rsprintf("<a href=\"%s\">%s</a></i>\n", enc_link_ref.c_str(), link_name);
7118 0 : r->rsprintf("<td class=\"%s\">\n", style);
7119 0 : if (!write_access)
7120 0 : r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7121 : else {
7122 0 : r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7123 0 : r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7124 : }
7125 : } else {
7126 0 : r->rsprintf("<td class=\"ODBkey\">\n");
7127 0 : r->rsprintf("%s<td class=\"%s\">", keyname.c_str(), style);
7128 0 : if (!write_access)
7129 0 : r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7130 : else {
7131 0 : r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7132 0 : r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7133 : }
7134 : }
7135 : } else {
7136 0 : if (strchr(data_str.c_str(), '\n')) {
7137 0 : if (link_name[0]) {
7138 0 : r->rsprintf("<td class=\"ODBkey\">");
7139 0 : r->rsprintf("%s <i>→ <a href=\"%s\">%s</a></i><td class=\"ODBvalue\">", keyname.c_str(), enc_link_ref.c_str(), link_name);
7140 : } else
7141 0 : r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7142 0 : r->rsprintf("\n<pre>");
7143 0 : strencode3(r, data_str.c_str());
7144 0 : r->rsprintf("</pre>");
7145 0 : if (strlen(data) > data_str.length())
7146 0 : r->rsprintf("<i>... (%d bytes total)<p>\n", (int)strlen(data));
7147 :
7148 0 : r->rsprintf("<a href=\"%s\">Edit</a>\n", enc_ref.c_str());
7149 : } else {
7150 0 : if (link_name[0]) {
7151 0 : r->rsprintf("<td class=\"ODBkey\">\n");
7152 0 : r->rsprintf("%s <i>→ <a href=\"%s\">%s</a></i><td class=\"%s\">", keyname.c_str(), enc_link_ref.c_str(), link_name, style);
7153 0 : if (!write_access)
7154 0 : strencode(r, data_str.c_str());
7155 : else {
7156 0 : r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7157 0 : r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7158 0 : strencode(r, data_str.c_str());
7159 0 : r->rsprintf("</a>\n");
7160 : }
7161 : } else {
7162 0 : r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7163 0 : if (!write_access) {
7164 0 : strencode(r, data_str.c_str());
7165 : } else {
7166 0 : r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7167 0 : r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7168 0 : strencode(r, data_str.c_str());
7169 0 : r->rsprintf("</a>\n");
7170 : }
7171 : }
7172 : }
7173 : }
7174 :
7175 : /* extended key information */
7176 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7177 0 : r->rsprintf("%s", rpc_tid_name(key.type));
7178 0 : r->rsprintf("</td>\n");
7179 :
7180 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7181 0 : r->rsprintf("%d", key.num_values);
7182 0 : r->rsprintf("</td>\n");
7183 :
7184 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7185 0 : r->rsprintf("%d", key.item_size);
7186 0 : r->rsprintf("</td>\n");
7187 :
7188 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7189 0 : db_get_key_time(hDB, hkey, &delta);
7190 0 : if (delta < 60)
7191 0 : r->rsprintf("%ds", delta);
7192 0 : else if (delta < 3600)
7193 0 : r->rsprintf("%1.0lfm", delta / 60.0);
7194 0 : else if (delta < 86400)
7195 0 : r->rsprintf("%1.0lfh", delta / 3600.0);
7196 0 : else if (delta < 86400 * 99)
7197 0 : r->rsprintf("%1.0lfd", delta / 86400.0);
7198 : else
7199 0 : r->rsprintf(">99d");
7200 0 : r->rsprintf("</td>\n");
7201 :
7202 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7203 0 : if (key.access_mode & MODE_READ)
7204 0 : r->rsprintf("R");
7205 0 : if (key.access_mode & MODE_WRITE)
7206 0 : r->rsprintf("W");
7207 0 : if (key.access_mode & MODE_DELETE)
7208 0 : r->rsprintf("D");
7209 0 : if (key.access_mode & MODE_EXCLUSIVE)
7210 0 : r->rsprintf("E");
7211 0 : r->rsprintf("</td>\n");
7212 :
7213 0 : line++;
7214 0 : r->rsprintf("</tr>\n");
7215 0 : } else { /* display array value */
7216 : /* check for exceeding length */
7217 0 : if (key.num_values > 1000 && !pp->isparam("all"))
7218 0 : r->rsprintf("<tr><td class=\"ODBkey\">%s<td class=\"%s\"><span style=\"font-style: italic\"><a href=\"?cmd=oldodb&odb_path=%s&all=1\">... %d values ...</a></span>\n", keyname.c_str(), style, enc_full_path.c_str(), key.num_values);
7219 : else {
7220 : /* display first value */
7221 0 : if (link_name[0])
7222 0 : r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s<br><i>→ <a href=\"%s\">%s</a></i>\n", key.num_values, keyname.c_str(), enc_link_ref.c_str(), link_name);
7223 : else
7224 0 : r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s\n", key.num_values, keyname.c_str());
7225 :
7226 0 : for (int j = 0; j < key.num_values; j++) {
7227 0 : if (line % 2 == 0)
7228 0 : mstrlcpy(style, "ODBtableEven", sizeof(style));
7229 : else
7230 0 : mstrlcpy(style, "ODBtableOdd", sizeof(style));
7231 :
7232 : char data[TEXT_SIZE];
7233 0 : size = sizeof(data);
7234 0 : db_get_data_index(hDB, hkey, data, &size, j, key.type);
7235 0 : std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
7236 :
7237 0 : std::string hex_str;
7238 0 : if (key.type == TID_STRING || key.type == TID_LINK) {
7239 0 : hex_str = "";
7240 : } else {
7241 0 : hex_str = db_sprintfh(data, key.item_size, 0, key.type);
7242 : }
7243 :
7244 0 : if (key.type == TID_STRING) {
7245 0 : if (size == sizeof(data)) {
7246 0 : data_str += "...(truncated)";
7247 : }
7248 : }
7249 :
7250 0 : if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7251 0 : data_str = "(empty)";
7252 0 : hex_str = "";
7253 : }
7254 :
7255 : //sprintf(ref, "?cmd=Set&odb_path=%s&index=%d", full_path, j);
7256 0 : enc_ref = "";
7257 0 : enc_ref += "?cmd=Set&odb_path=";
7258 0 : enc_ref += enc_full_path;
7259 0 : enc_ref += "&index=";
7260 0 : enc_ref += toString(j);
7261 :
7262 0 : std::string tmpstr;
7263 : //sprintf(str, "%s[%d]", odb_path, j);
7264 0 : tmpstr += odb_path;
7265 0 : tmpstr += "[";
7266 0 : tmpstr += toString(j);
7267 0 : tmpstr += "]";
7268 :
7269 0 : if (j > 0)
7270 0 : r->rsprintf("<tr>");
7271 :
7272 0 : r->rsprintf("<td class=\"%s\">[%d] ", style, j);
7273 0 : if (!write_access)
7274 0 : r->rsprintf("<a href=\"%s\">", enc_ref.c_str());
7275 : else {
7276 0 : r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), tmpstr.c_str());
7277 0 : r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", tmpstr.c_str());
7278 : }
7279 0 : if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
7280 0 : r->rsprintf("%s (%s)</a>\n", data_str.c_str(), hex_str.c_str());
7281 : else
7282 0 : r->rsprintf("%s</a>\n", data_str.c_str());
7283 :
7284 0 : if (j == 0) {
7285 : /* extended key information */
7286 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7287 0 : r->rsprintf("%s", rpc_tid_name(key.type));
7288 0 : r->rsprintf("</td>\n");
7289 :
7290 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7291 0 : r->rsprintf("%d", key.num_values);
7292 0 : r->rsprintf("</td>\n");
7293 :
7294 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7295 0 : r->rsprintf("%d", key.item_size);
7296 0 : r->rsprintf("</td>\n");
7297 :
7298 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7299 0 : db_get_key_time(hDB, hkey, &delta);
7300 0 : if (delta < 60)
7301 0 : r->rsprintf("%ds", delta);
7302 0 : else if (delta < 3600)
7303 0 : r->rsprintf("%1.0lfm", delta / 60.0);
7304 0 : else if (delta < 86400)
7305 0 : r->rsprintf("%1.0lfh", delta / 3600.0);
7306 0 : else if (delta < 86400 * 99)
7307 0 : r->rsprintf("%1.0lfh", delta / 86400.0);
7308 : else
7309 0 : r->rsprintf(">99d");
7310 0 : r->rsprintf("</td>\n");
7311 :
7312 0 : r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7313 0 : if (key.access_mode & MODE_READ)
7314 0 : r->rsprintf("R");
7315 0 : if (key.access_mode & MODE_WRITE)
7316 0 : r->rsprintf("W");
7317 0 : if (key.access_mode & MODE_DELETE)
7318 0 : r->rsprintf("D");
7319 0 : if (key.access_mode & MODE_EXCLUSIVE)
7320 0 : r->rsprintf("E");
7321 0 : r->rsprintf("</td>\n");
7322 : }
7323 0 : line++;
7324 0 : }
7325 :
7326 0 : r->rsprintf("</tr>\n");
7327 : }
7328 : }
7329 0 : } else if(key.type != TID_KEY){
7330 0 : keyPresent = 1; //flag that we've seen a key on the first pass, and should therefore write the Key / Value headline
7331 : }
7332 : }
7333 0 : }
7334 : }
7335 0 : r->rsprintf("</table>\n");
7336 0 : r->rsprintf("</div>\n"); // <div id="mmain">
7337 :
7338 : /*---- Build the Delete dialog------------------------------------*/
7339 :
7340 0 : std::sort(delete_list.begin(), delete_list.end());
7341 :
7342 0 : for (unsigned i=0; i<delete_list.size(); i++) {
7343 0 : std::string name = delete_list[i];
7344 :
7345 0 : dd += "<tr><td style=\"text-align:left;\" align=left><input align=left type=checkbox id=delete";
7346 0 : dd += toString(count_delete++);
7347 0 : dd += " value=\'";
7348 0 : dd += "\"";
7349 0 : dd += MJsonNode::Encode(name.c_str());
7350 0 : dd += "\"";
7351 0 : dd += "\'>";
7352 0 : dd += name;
7353 0 : dd += "</input></td></tr>\n";
7354 0 : }
7355 :
7356 0 : dd += "</table>\n";
7357 0 : dd += "<input type=button value=Delete onClick='mhttpd_delete_page_handle_delete(event);'>\n";
7358 0 : dd += "<input type=button value=Cancel onClick='mhttpd_delete_page_handle_cancel(event);'>\n";
7359 0 : dd += "</div>\n";
7360 0 : dd += "</div>\n";
7361 :
7362 0 : r->rsputs(dd.c_str());
7363 :
7364 : /*---- Build the Create dialog------------------------------------*/
7365 :
7366 0 : std::string cd = "";
7367 :
7368 0 : cd += "<!-- Demo dialog -->\n";
7369 0 : cd += "<div id=\"dlgCreate\" class=\"dlgFrame\">\n";
7370 0 : cd += "<div class=\"dlgTitlebar\">Create ODB entry</div>\n";
7371 0 : cd += "<div class=\"dlgPanel\">\n";
7372 0 : cd += "<br />\n";
7373 0 : cd += "<div id=odbpath>";
7374 0 : cd += "\"";
7375 0 : cd += MJsonNode::Encode(odbpath.c_str());
7376 0 : cd += "\"";
7377 0 : cd += "</div>\n";
7378 0 : cd += "<div><br></div>\n";
7379 :
7380 0 : cd += "<table class=\"dialogTable\">\n";
7381 0 : cd += "<th colspan=2>Create ODB entry:</th>\n";
7382 0 : cd += "<tr>";
7383 0 : cd += "<td>Type";
7384 0 : cd += "<td>";
7385 0 : cd += "<select type=text size=1 id=create_tid name=type>";
7386 0 : cd += "<option value=7>Integer (32-bit)";
7387 0 : cd += "<option value=9>Float (4 Bytes)";
7388 0 : cd += "<option value=12>String";
7389 0 : cd += "<option selected value=15>Subdirectory";
7390 0 : cd += "<option value=1>Byte";
7391 0 : cd += "<option value=2>Signed byte";
7392 0 : cd += "<option value=3>Character (8-bit)";
7393 0 : cd += "<option value=4>Word (16-bit)";
7394 0 : cd += "<option value=5>Short integer (16-bit)";
7395 0 : cd += "<option value=6>Double Word (32-bit)";
7396 0 : cd += "<option value=8>Boolean";
7397 0 : cd += "<option value=10>Double float (8 Bytes)";
7398 : //cd += "<option value=16>Symbolic link";
7399 0 : cd += "</select>";
7400 0 : cd += "</tr>\n";
7401 0 : cd += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=create_name name=value></tr>\n";
7402 0 : cd += "<tr><td>Array size<td><input type=text size=31 maxlength=31 id=create_array_length name=index value=1></tr>\n";
7403 0 : cd += "<tr><td>String length<td><input type=text size=31 maxlength=31 id=create_strlen name=strlen value=32></tr>\n";
7404 0 : cd += "</table>\n";
7405 0 : cd += "<input type=button value=Create onClick='mhttpd_create_page_handle_create(event);'>\n";
7406 0 : cd += "<input type=button value=Cancel onClick='mhttpd_create_page_handle_cancel(event);'>\n";
7407 0 : cd += "</div>\n";
7408 0 : cd += "</div>\n";
7409 :
7410 0 : r->rsputs(cd.c_str());
7411 :
7412 : /*---- Build the Link dialog------------------------------------*/
7413 :
7414 0 : std::string ld = "";
7415 :
7416 0 : ld += "<!-- Demo dialog -->\n";
7417 0 : ld += "<div id=\"dlgLink\" class=\"dlgFrame\">\n";
7418 0 : ld += "<div class=\"dlgTitlebar\">Create a link to an ODB entry</div>\n";
7419 0 : ld += "<div class=\"dlgPanel\">\n";
7420 0 : ld += "<br />\n";
7421 0 : ld += "<div id=link_odbpath>";
7422 0 : ld += "\"";
7423 0 : ld += MJsonNode::Encode(odbpath.c_str());
7424 0 : ld += "\"";
7425 0 : ld += "</div>\n";
7426 0 : ld += "<div><br></div>\n";
7427 :
7428 0 : ld += "<table class=\"dialogTable\">\n";
7429 0 : ld += "<th colspan=2>Create a link to an ODB entry:</th>\n";
7430 0 : ld += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=link_name name=value></tr>\n";
7431 0 : ld += "<tr><td>Link target<td><input type=text size=31 maxlength=256 id=link_target name=target></tr>\n";
7432 0 : ld += "</table>\n";
7433 0 : ld += "<input type=button value=Link onClick='mhttpd_link_page_handle_link(event);'>\n";
7434 0 : ld += "<input type=button value=Cancel onClick='mhttpd_link_page_handle_cancel(event);'>\n";
7435 0 : ld += "</div>\n";
7436 0 : ld += "</div>\n";
7437 :
7438 0 : r->rsputs(ld.c_str());
7439 0 : }
7440 :
7441 : /*------------------------------------------------------------------*/
7442 :
7443 0 : void show_set_page(Param* pp, Return* r,
7444 : const char *group,
7445 : int index, const char *value)
7446 : {
7447 : int status, size;
7448 : HNDLE hDB, hkey;
7449 : KEY key;
7450 : char data[TEXT_SIZE];
7451 :
7452 0 : std::string odb_path = pp->getparam("odb_path");
7453 :
7454 : //printf("show_set_page: odb_path [%s] group [%s] index %d value [%s]\n", odb_path.c_str(), group, index, value);
7455 :
7456 0 : cm_get_experiment_database(&hDB, NULL);
7457 :
7458 : /* show set page if no value is given */
7459 0 : if (!pp->isparam("value") && !*pp->getparam("text")) {
7460 0 : status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7461 0 : if (status != DB_SUCCESS) {
7462 0 : r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7463 0 : return;
7464 : }
7465 0 : db_get_link(hDB, hkey, &key);
7466 :
7467 0 : show_header(r, "Set value", "POST", "", 0);
7468 : //close header:
7469 0 : r->rsprintf("</table>");
7470 :
7471 : //main table:
7472 0 : r->rsprintf("<table class=\"dialogTable\">");
7473 :
7474 0 : if (index > 0)
7475 0 : r->rsprintf("<input type=hidden name=index value=\"%d\">\n", index);
7476 : else
7477 0 : index = 0;
7478 :
7479 0 : if (group[0])
7480 0 : r->rsprintf("<input type=hidden name=group value=\"%s\">\n", group);
7481 :
7482 0 : r->rsprintf("<input type=hidden name=odb_path value=\"%s\">\n", odb_path.c_str());
7483 :
7484 0 : std::string data_str1 = rpc_tid_name(key.type);
7485 0 : std::string str1;
7486 0 : if (key.num_values > 1) {
7487 0 : data_str1 += msprintf("[%d]", key.num_values);
7488 0 : str1 = msprintf("%s[%d]", odb_path.c_str(), index);
7489 : } else
7490 0 : str1 = odb_path.c_str();
7491 :
7492 0 : r->rsprintf("<tr><th colspan=2>Set new value - type = %s</tr>\n", data_str1.c_str());
7493 0 : r->rsprintf("<tr><td>%s<td>\n", str1.c_str());
7494 :
7495 : /* set current value as default */
7496 0 : size = sizeof(data);
7497 0 : db_get_link_data(hDB, hkey, data, &size, key.type);
7498 0 : std::string data_str = db_sprintf(data, key.item_size, index, key.type);
7499 :
7500 0 : if (equal_ustring(data_str.c_str(), "<NULL>"))
7501 0 : data_str = "";
7502 :
7503 0 : if (strchr(data_str.c_str(), '\n') != NULL) {
7504 0 : r->rsprintf("<textarea rows=20 cols=80 name=\"text\">\n");
7505 0 : strencode3(r, data);
7506 0 : r->rsprintf("</textarea>\n");
7507 : } else {
7508 0 : size = 20;
7509 0 : if ((int) data_str.length() > size)
7510 0 : size = data_str.length() + 3;
7511 0 : if (size > 80)
7512 0 : size = 80;
7513 :
7514 0 : r->rsprintf("<input type=\"text\" size=%d maxlength=256 name=\"value\" value=\"", size);
7515 0 : strencode(r, data_str.c_str());
7516 0 : r->rsprintf("\">\n");
7517 : }
7518 :
7519 0 : r->rsprintf("</tr>\n");
7520 :
7521 0 : r->rsprintf("<tr><td align=center colspan=2>");
7522 0 : r->rsprintf("<input type=submit name=cmd value=Set>");
7523 0 : r->rsprintf("<input type=submit name=cmd value=Cancel>");
7524 0 : r->rsprintf("</tr>");
7525 0 : r->rsprintf("</table>");
7526 :
7527 0 : r->rsprintf("<input type=hidden name=cmd value=Set>\n");
7528 :
7529 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
7530 0 : r->rsprintf("</form>\n");
7531 0 : r->rsprintf("</body></html>\r\n");
7532 0 : return;
7533 0 : } else {
7534 : /* set value */
7535 :
7536 0 : status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7537 0 : if (status != DB_SUCCESS) {
7538 0 : r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7539 0 : return;
7540 : }
7541 0 : db_get_link(hDB, hkey, &key);
7542 :
7543 0 : memset(data, 0, sizeof(data));
7544 :
7545 0 : if (pp->getparam("text") && *pp->getparam("text"))
7546 0 : mstrlcpy(data, pp->getparam("text"), sizeof(data));
7547 : else
7548 0 : db_sscanf(value, data, &size, 0, key.type);
7549 :
7550 0 : if (index < 0)
7551 0 : index = 0;
7552 :
7553 : /* extend data size for single string if necessary */
7554 0 : if ((key.type == TID_STRING || key.type == TID_LINK)
7555 0 : && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
7556 0 : key.item_size = strlen(data) + 1;
7557 :
7558 0 : if (key.item_size == 0)
7559 0 : key.item_size = rpc_tid_size(key.type);
7560 :
7561 0 : if (key.num_values > 1)
7562 0 : status = db_set_link_data_index(hDB, hkey, data, key.item_size, index, key.type);
7563 : else
7564 0 : status = db_set_link_data(hDB, hkey, data, key.item_size, 1, key.type);
7565 :
7566 0 : if (status == DB_NO_ACCESS)
7567 0 : r->rsprintf("<h2>Write access not allowed</h2>\n");
7568 :
7569 0 : redirect(r, "");
7570 :
7571 0 : return;
7572 : }
7573 0 : }
7574 :
7575 : /*------------------------------------------------------------------*/
7576 :
7577 0 : void show_find_page(Return* r, const char *value)
7578 : {
7579 : HNDLE hDB, hkey;
7580 :
7581 0 : cm_get_experiment_database(&hDB, NULL);
7582 :
7583 0 : if (value[0] == 0) {
7584 : /* without value, show find dialog */
7585 0 : show_header(r, "Find value", "GET", "", 0);
7586 :
7587 : //end header:
7588 0 : r->rsprintf("</table>");
7589 :
7590 : //find dialog:
7591 0 : r->rsprintf("<table class=\"dialogTable\">");
7592 :
7593 0 : r->rsprintf("<tr><th colspan=2>Find string in Online Database</tr>\n");
7594 0 : r->rsprintf("<tr><td>Enter substring (case insensitive)\n");
7595 :
7596 0 : r->rsprintf("<td><input type=\"text\" size=\"20\" maxlength=\"80\" name=\"value\">\n");
7597 0 : r->rsprintf("</tr>");
7598 :
7599 0 : r->rsprintf("<tr><td align=center colspan=2>");
7600 0 : r->rsprintf("<input type=submit name=cmd value=Find>");
7601 0 : r->rsprintf("<input type=submit name=cmd value=Cancel>");
7602 0 : r->rsprintf("</tr>");
7603 0 : r->rsprintf("</table>");
7604 :
7605 0 : r->rsprintf("<input type=hidden name=cmd value=Find>");
7606 :
7607 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
7608 0 : r->rsprintf("</form>\n");
7609 0 : r->rsprintf("</body></html>\r\n");
7610 : } else {
7611 0 : show_header(r, "Search results", "GET", "", 0);
7612 :
7613 0 : r->rsprintf("<table class=\"mtable\">\n");
7614 0 : r->rsprintf("<tr><th colspan=2 class=\"mtableheader\">");
7615 0 : r->rsprintf("Results of search for substring \"%s\"</tr>\n", value);
7616 0 : r->rsprintf("<tr><th class=\"titlerow\">Key<th>Value</tr>\n");
7617 :
7618 : /* start from root */
7619 0 : db_find_key(hDB, 0, "", &hkey);
7620 0 : assert(hkey);
7621 :
7622 : /* scan tree, call "search_callback" for each key */
7623 : search_data data;
7624 0 : data.r = r;
7625 0 : data.search_name = value;
7626 :
7627 0 : db_scan_tree(hDB, hkey, 0, search_callback, (void *)&data);
7628 :
7629 0 : r->rsprintf("</table>");
7630 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
7631 0 : r->rsprintf("</form>\n");
7632 0 : r->rsprintf("</body></html>\r\n");
7633 : }
7634 0 : }
7635 :
7636 : /*------------------------------------------------------------------*/
7637 :
7638 : #define LN10 2.302585094
7639 : #define LOG2 0.301029996
7640 : #define LOG5 0.698970005
7641 :
7642 0 : void haxis(gdImagePtr im, gdFont * font, int col, int gcol,
7643 : int x1, int y1, int width,
7644 : int minor, int major, int text, int label, int grid, double xmin, double xmax)
7645 : {
7646 : double dx, int_dx, frac_dx, x_act, label_dx, major_dx, x_screen, maxwidth;
7647 : int tick_base, major_base, label_base, n_sig1, n_sig2, xs;
7648 : char str[80];
7649 0 : double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7650 :
7651 0 : if (xmax <= xmin || width <= 0)
7652 0 : return;
7653 :
7654 : /* use 5 as min tick distance */
7655 0 : dx = (xmax - xmin) / (double) (width / 5);
7656 :
7657 0 : frac_dx = modf(log(dx) / LN10, &int_dx);
7658 0 : if (frac_dx < 0) {
7659 0 : frac_dx += 1;
7660 0 : int_dx -= 1;
7661 : }
7662 :
7663 0 : tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
7664 0 : major_base = label_base = tick_base + 1;
7665 :
7666 : /* rounding up of dx, label_dx */
7667 0 : dx = pow(10, int_dx) * base[tick_base];
7668 0 : major_dx = pow(10, int_dx) * base[major_base];
7669 0 : label_dx = major_dx;
7670 :
7671 : /* number of significant digits */
7672 0 : if (xmin == 0)
7673 0 : n_sig1 = 0;
7674 : else
7675 0 : n_sig1 = (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7676 :
7677 0 : if (xmax == 0)
7678 0 : n_sig2 = 0;
7679 : else
7680 0 : n_sig2 =
7681 0 : (int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7682 :
7683 0 : n_sig1 = MAX(n_sig1, n_sig2);
7684 0 : n_sig1 = MAX(n_sig1, 4);
7685 :
7686 : /* determination of maximal width of labels */
7687 0 : sprintf(str, "%1.*lG", n_sig1, floor(xmin / dx) * dx);
7688 0 : maxwidth = font->h / 2 * strlen(str);
7689 0 : sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx);
7690 0 : maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7691 0 : sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx + label_dx);
7692 0 : maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7693 :
7694 : /* increasing label_dx, if labels would overlap */
7695 0 : while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7696 0 : label_base++;
7697 0 : label_dx = pow(10, int_dx) * base[label_base];
7698 0 : if (label_base % 3 == 2 && major_base % 3 == 1) {
7699 0 : major_base++;
7700 0 : major_dx = pow(10, int_dx) * base[major_base];
7701 : }
7702 : }
7703 :
7704 0 : x_act = floor(xmin / dx) * dx;
7705 :
7706 0 : gdImageLine(im, x1, y1, x1 + width, y1, col);
7707 :
7708 : do {
7709 0 : x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
7710 0 : xs = (int) (x_screen + 0.5);
7711 :
7712 0 : if (x_screen > x1 + width + 0.001)
7713 0 : break;
7714 :
7715 0 : if (x_screen >= x1) {
7716 0 : if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
7717 0 : dx / major_dx / 10.0) {
7718 :
7719 0 : if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
7720 0 : dx / label_dx / 10.0) {
7721 : /* label tick mark */
7722 0 : gdImageLine(im, xs, y1, xs, y1 + text, col);
7723 :
7724 : /* grid line */
7725 0 : if (grid != 0 && xs > x1 && xs < x1 + width)
7726 0 : gdImageLine(im, xs, y1, xs, y1 + grid, col);
7727 :
7728 : /* label */
7729 0 : if (label != 0) {
7730 0 : sprintf(str, "%1.*lG", n_sig1, x_act);
7731 0 : gdImageString(im, font, (int) xs - font->w * strlen(str) / 2,
7732 : y1 + label, str, col);
7733 : }
7734 : } else {
7735 : /* major tick mark */
7736 0 : gdImageLine(im, xs, y1, xs, y1 + major, col);
7737 :
7738 : /* grid line */
7739 0 : if (grid != 0 && xs > x1 && xs < x1 + width)
7740 0 : gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7741 : }
7742 :
7743 : } else
7744 : /* minor tick mark */
7745 0 : gdImageLine(im, xs, y1, xs, y1 + minor, col);
7746 :
7747 : }
7748 :
7749 0 : x_act += dx;
7750 :
7751 : /* supress 1.23E-17 ... */
7752 0 : if (fabs(x_act) < dx / 100)
7753 0 : x_act = 0;
7754 :
7755 : } while (1);
7756 : }
7757 :
7758 : /*------------------------------------------------------------------*/
7759 :
7760 0 : void sec_to_label(char *result, int sec, int base, int force_date)
7761 : {
7762 : char mon[80];
7763 : time_t t_sec;
7764 :
7765 0 : t_sec = (time_t) sec;
7766 :
7767 : struct tm tms;
7768 0 : localtime_r(&t_sec, &tms);
7769 0 : strcpy(mon, mname[tms.tm_mon]);
7770 0 : mon[3] = 0;
7771 :
7772 0 : if (force_date) {
7773 0 : if (base < 600)
7774 0 : sprintf(result, "%02d %s %02d %02d:%02d:%02d",
7775 0 : tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min,
7776 : tms.tm_sec);
7777 0 : else if (base < 3600 * 24)
7778 0 : sprintf(result, "%02d %s %02d %02d:%02d",
7779 0 : tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7780 : else
7781 0 : sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7782 : } else {
7783 0 : if (base < 600)
7784 0 : sprintf(result, "%02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec);
7785 0 : else if (base < 3600 * 3)
7786 0 : sprintf(result, "%02d:%02d", tms.tm_hour, tms.tm_min);
7787 0 : else if (base < 3600 * 24)
7788 0 : sprintf(result, "%02d %s %02d %02d:%02d",
7789 0 : tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7790 : else
7791 0 : sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7792 : }
7793 0 : }
7794 :
7795 0 : void taxis(gdImagePtr im, gdFont * font, int col, int gcol,
7796 : int x1, int y1, int width, int xr,
7797 : int minor, int major, int text, int label, int grid, double xmin, double xmax)
7798 : {
7799 : int dx, x_act, label_dx, major_dx, x_screen, maxwidth;
7800 : int tick_base, major_base, label_base, xs, xl;
7801 : char str[80];
7802 0 : const int base[] = { 1, 5, 10, 60, 300, 600, 1800, 3600, 3600 * 6, 3600 * 12, 3600 * 24, 0 };
7803 : time_t ltime;
7804 : int force_date, d1, d2;
7805 : struct tm tms;
7806 :
7807 0 : if (xmax <= xmin || width <= 0)
7808 0 : return;
7809 :
7810 : /* force date display if xmax not today */
7811 0 : ltime = ss_time();
7812 0 : localtime_r(<ime, &tms);
7813 0 : d1 = tms.tm_mday;
7814 0 : ltime = (time_t) xmax;
7815 0 : localtime_r(<ime, &tms);
7816 0 : d2 = tms.tm_mday;
7817 0 : force_date = (d1 != d2);
7818 :
7819 : /* use 5 pixel as min tick distance */
7820 0 : dx = (int) ((xmax - xmin) / (double) (width / 5) + 0.5);
7821 :
7822 0 : for (tick_base = 0; base[tick_base]; tick_base++) {
7823 0 : if (base[tick_base] > dx)
7824 0 : break;
7825 : }
7826 0 : if (!base[tick_base])
7827 0 : tick_base--;
7828 0 : dx = base[tick_base];
7829 :
7830 0 : if (base[tick_base + 1])
7831 0 : major_base = tick_base + 1;
7832 : else
7833 0 : major_base = tick_base;
7834 0 : major_dx = base[major_base];
7835 :
7836 0 : if (base[major_base + 1])
7837 0 : label_base = major_base + 1;
7838 : else
7839 0 : label_base = major_base;
7840 0 : label_dx = base[label_base];
7841 :
7842 : do {
7843 0 : sec_to_label(str, (int) (xmin + 0.5), label_dx, force_date);
7844 0 : maxwidth = font->h / 2 * strlen(str);
7845 :
7846 : /* increasing label_dx, if labels would overlap */
7847 0 : if (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7848 0 : if (base[label_base + 1])
7849 0 : label_dx = base[++label_base];
7850 : else
7851 0 : label_dx += 3600 * 24;
7852 : } else
7853 0 : break;
7854 : } while (1);
7855 :
7856 0 : x_act =
7857 0 : (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
7858 :
7859 0 : gdImageLine(im, x1, y1, x1 + width, y1, col);
7860 :
7861 : do {
7862 0 : x_screen = (int) ((x_act - xmin) / (xmax - xmin) * width + x1 + 0.5);
7863 0 : xs = (int) (x_screen + 0.5);
7864 :
7865 0 : if (x_screen > x1 + width + 0.001)
7866 0 : break;
7867 :
7868 0 : if (x_screen >= x1) {
7869 0 : if ((x_act - ss_timezone()) % major_dx == 0) {
7870 0 : if ((x_act - ss_timezone()) % label_dx == 0) {
7871 : /* label tick mark */
7872 0 : gdImageLine(im, xs, y1, xs, y1 + text, col);
7873 :
7874 : /* grid line */
7875 0 : if (grid != 0 && xs > x1 && xs < x1 + width)
7876 0 : gdImageLine(im, xs, y1, xs, y1 + grid, col);
7877 :
7878 : /* label */
7879 0 : if (label != 0) {
7880 0 : sec_to_label(str, x_act, label_dx, force_date);
7881 :
7882 : /* if labels at edge, shift them in */
7883 0 : xl = (int) xs - font->w * strlen(str) / 2;
7884 0 : if (xl < 0)
7885 0 : xl = 0;
7886 0 : if (xl + font->w * (int) strlen(str) > xr)
7887 0 : xl = xr - font->w * strlen(str);
7888 0 : gdImageString(im, font, xl, y1 + label, str, col);
7889 : }
7890 : } else {
7891 : /* major tick mark */
7892 0 : gdImageLine(im, xs, y1, xs, y1 + major, col);
7893 :
7894 : /* grid line */
7895 0 : if (grid != 0 && xs > x1 && xs < x1 + width)
7896 0 : gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7897 : }
7898 :
7899 : } else
7900 : /* minor tick mark */
7901 0 : gdImageLine(im, xs, y1, xs, y1 + minor, col);
7902 :
7903 : }
7904 :
7905 0 : x_act += dx;
7906 :
7907 : /* supress 1.23E-17 ... */
7908 0 : if (fabs((double)x_act) < dx / 100)
7909 0 : x_act = 0;
7910 :
7911 : } while (1);
7912 : }
7913 :
7914 : /*------------------------------------------------------------------*/
7915 :
7916 0 : int vaxis(gdImagePtr im, gdFont * font, int col, int gcol,
7917 : int x1, int y1, int width,
7918 : int minor, int major, int text, int label, int grid, double ymin, double ymax,
7919 : BOOL logaxis)
7920 : {
7921 : double dy, int_dy, frac_dy, y_act, label_dy, major_dy, y_screen, y_next;
7922 : int tick_base, major_base, label_base, n_sig1, n_sig2, ys, max_width;
7923 : int last_label_y;
7924 : char str[80];
7925 0 : const double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7926 :
7927 0 : if (ymax <= ymin || width <= 0)
7928 0 : return 0;
7929 :
7930 : // data type "double" only has about 15 significant digits, if difference between ymax and ymin is less than 10 significant digits, bailout! Otherwise code below goes into infinite loop
7931 0 : if (fabs(ymax - ymin) <= 1e-10)
7932 0 : return 0;
7933 :
7934 0 : if (logaxis) {
7935 0 : dy = pow(10, floor(log(ymin) / LN10));
7936 0 : label_dy = dy;
7937 0 : major_dy = dy * 10;
7938 0 : n_sig1 = 4;
7939 : } else {
7940 0 : dy = (ymax - ymin) / (double) (width / 5);
7941 :
7942 0 : frac_dy = modf(log(dy) / LN10, &int_dy);
7943 0 : if (frac_dy < 0) {
7944 0 : frac_dy += 1;
7945 0 : int_dy -= 1;
7946 : }
7947 :
7948 0 : tick_base = frac_dy < LOG2 ? 1 : frac_dy < LOG5 ? 2 : 3;
7949 0 : major_base = label_base = tick_base + 1;
7950 :
7951 : /* rounding up of dy, label_dy */
7952 0 : dy = pow(10, int_dy) * base[tick_base];
7953 0 : major_dy = pow(10, int_dy) * base[major_base];
7954 0 : label_dy = major_dy;
7955 :
7956 : /* number of significant digits */
7957 0 : if (ymin == 0)
7958 0 : n_sig1 = 0;
7959 : else
7960 0 : n_sig1 =
7961 0 : (int) floor(log(fabs(ymin)) / LN10) -
7962 0 : (int) floor(log(fabs(label_dy)) / LN10) + 1;
7963 :
7964 0 : if (ymax == 0)
7965 0 : n_sig2 = 0;
7966 : else
7967 0 : n_sig2 =
7968 0 : (int) floor(log(fabs(ymax)) / LN10) -
7969 0 : (int) floor(log(fabs(label_dy)) / LN10) + 1;
7970 :
7971 0 : n_sig1 = MAX(n_sig1, n_sig2);
7972 0 : n_sig1 = MAX(n_sig1, 4);
7973 :
7974 : /* increasing label_dy, if labels would overlap */
7975 0 : while (label_dy / (ymax - ymin) * width < 1.5 * font->h) {
7976 0 : label_base++;
7977 0 : label_dy = pow(10, int_dy) * base[label_base];
7978 0 : if (label_base % 3 == 2 && major_base % 3 == 1) {
7979 0 : major_base++;
7980 0 : major_dy = pow(10, int_dy) * base[major_base];
7981 : }
7982 : }
7983 : }
7984 :
7985 0 : max_width = 0;
7986 0 : y_act = floor(ymin / dy) * dy;
7987 :
7988 0 : if (x1 != 0 || y1 != 0)
7989 0 : gdImageLine(im, x1, y1, x1, y1 - width, col);
7990 :
7991 0 : last_label_y = y1 + 2 * font->h;
7992 :
7993 : do {
7994 0 : if (logaxis)
7995 0 : y_screen = y1 - (log(y_act) - log(ymin)) / (log(ymax) - log(ymin)) * width;
7996 : else
7997 0 : y_screen = y1 - (y_act - ymin) / (ymax - ymin) * width;
7998 0 : ys = (int) (y_screen + 0.5);
7999 :
8000 0 : if (y_screen < y1 - width - 0.001)
8001 0 : break;
8002 :
8003 0 : if (y_screen <= y1 + 0.001) {
8004 0 : if (fabs(floor(y_act / major_dy + 0.5) - y_act / major_dy) <
8005 0 : dy / major_dy / 10.0) {
8006 0 : if (fabs(floor(y_act / label_dy + 0.5) - y_act / label_dy) <
8007 0 : dy / label_dy / 10.0) {
8008 0 : if (x1 != 0 || y1 != 0) {
8009 : /* label tick mark */
8010 0 : gdImageLine(im, x1, ys, x1 + text, ys, col);
8011 :
8012 : /* grid line */
8013 0 : if (grid != 0 && y_screen < y1 && y_screen > y1 - width) {
8014 0 : if (grid > 0)
8015 0 : gdImageLine(im, x1 + 1, ys, x1 + grid, ys, gcol);
8016 : else
8017 0 : gdImageLine(im, x1 - 1, ys, x1 + grid, ys, gcol);
8018 : }
8019 :
8020 : /* label */
8021 0 : if (label != 0) {
8022 0 : sprintf(str, "%1.*lG", n_sig1, y_act);
8023 0 : if (label < 0)
8024 0 : gdImageString(im, font, x1 + label - font->w * strlen(str),
8025 0 : ys - font->h / 2, str, col);
8026 : else
8027 0 : gdImageString(im, font, x1 + label, ys - font->h / 2, str, col);
8028 :
8029 0 : last_label_y = ys - font->h / 2;
8030 : }
8031 : } else {
8032 0 : sprintf(str, "%1.*lG", n_sig1, y_act);
8033 0 : max_width = MAX(max_width, (int) (font->w * strlen(str)));
8034 : }
8035 : } else {
8036 0 : if (x1 != 0 || y1 != 0) {
8037 : /* major tick mark */
8038 0 : gdImageLine(im, x1, ys, x1 + major, ys, col);
8039 :
8040 : /* grid line */
8041 0 : if (grid != 0 && y_screen < y1 && y_screen > y1 - width)
8042 0 : gdImageLine(im, x1, ys, x1 + grid, ys, col);
8043 : }
8044 : }
8045 0 : if (logaxis) {
8046 0 : dy *= 10;
8047 0 : major_dy *= 10;
8048 0 : label_dy *= 10;
8049 : }
8050 :
8051 : } else {
8052 0 : if (x1 != 0 || y1 != 0) {
8053 : /* minor tick mark */
8054 0 : gdImageLine(im, x1, ys, x1 + minor, ys, col);
8055 : }
8056 :
8057 : /* for logaxis, also put labes on minor tick marks */
8058 0 : if (logaxis) {
8059 0 : if (label != 0) {
8060 0 : if (x1 != 0 || y1 != 0) {
8061 : /* calculate position of next major label */
8062 0 : y_next = pow(10, floor(log(y_act) / LN10) + 1);
8063 0 : y_screen =
8064 0 : (int) (y1 -
8065 0 : (log(y_next) - log(ymin)) / (log(ymax) -
8066 0 : log(ymin)) * width + 0.5);
8067 :
8068 0 : if (ys + font->h / 2 < last_label_y
8069 0 : && ys - font->h / 2 > y_screen + font->h / 2) {
8070 0 : sprintf(str, "%1.*lG", n_sig1, y_act);
8071 0 : if (label < 0)
8072 0 : gdImageString(im, font, x1 + label - font->w * strlen(str),
8073 0 : ys - font->h / 2, str, col);
8074 : else
8075 0 : gdImageString(im, font, x1 + label, ys - font->h / 2, str,
8076 : col);
8077 : }
8078 :
8079 0 : last_label_y = ys - font->h / 2;
8080 : } else {
8081 0 : sprintf(str, "%1.*lG", n_sig1, y_act);
8082 0 : max_width = MAX(max_width, (int) (font->w * strlen(str)));
8083 : }
8084 : }
8085 : }
8086 : }
8087 : }
8088 :
8089 0 : y_act += dy;
8090 :
8091 : /* supress 1.23E-17 ... */
8092 0 : if (fabs(y_act) < dy / 100)
8093 0 : y_act = 0;
8094 :
8095 : } while (1);
8096 :
8097 0 : return max_width + abs(label);
8098 : }
8099 :
8100 : /*------------------------------------------------------------------*/
8101 :
8102 0 : int time_to_sec(const char *str)
8103 : {
8104 : double s;
8105 :
8106 0 : s = atof(str);
8107 0 : switch (str[strlen(str) - 1]) {
8108 0 : case 'm':
8109 : case 'M':
8110 0 : s *= 60;
8111 0 : break;
8112 0 : case 'h':
8113 : case 'H':
8114 0 : s *= 3600;
8115 0 : break;
8116 0 : case 'd':
8117 : case 'D':
8118 0 : s *= 3600 * 24;
8119 0 : break;
8120 : }
8121 :
8122 0 : return (int) s;
8123 : }
8124 :
8125 : /*------------------------------------------------------------------*/
8126 :
8127 0 : time_t string_to_time(const char *str)
8128 : {
8129 0 : time_t t = 0;
8130 0 : for (; *str != 0; str++) {
8131 0 : if (*str < '0')
8132 0 : break;
8133 0 : if (*str > '9')
8134 0 : break;
8135 0 : t *= 10;
8136 0 : t += *str - '0';
8137 : }
8138 0 : return t;
8139 : }
8140 :
8141 : /*------------------------------------------------------------------*/
8142 :
8143 0 : std::string time_to_string(time_t t)
8144 : {
8145 : char buf[256];
8146 0 : sprintf(buf, "%.0f", (double)t);
8147 0 : return buf;
8148 : }
8149 :
8150 : /*------------------------------------------------------------------*/
8151 :
8152 : static bool gDoSetupHistoryWatch = true;
8153 : static bool gDoReloadHistory = false;
8154 :
8155 0 : static void history_watch_callback(HNDLE hDB, HNDLE hKey, int index, void* info)
8156 : {
8157 : //printf("history_watch_callback %d %d %d\n", hDB, hKey, index);
8158 0 : gDoReloadHistory = true;
8159 0 : cm_msg(MINFO, "history_watch_callback", "History configuration may have changed, will reconnect");
8160 0 : }
8161 :
8162 : static MidasHistoryInterface* gMh = NULL;
8163 : static HNDLE gMhkey = 0;
8164 :
8165 : /*------------------------------------------------------------------*/
8166 :
8167 0 : static MidasHistoryInterface* get_history(bool reset = false)
8168 : {
8169 : int status;
8170 : HNDLE hDB;
8171 :
8172 : // history reconnect requested by watch callback?
8173 :
8174 0 : if (gDoReloadHistory) {
8175 0 : gDoReloadHistory = false;
8176 0 : reset = true;
8177 : }
8178 :
8179 : // disconnect from previous history
8180 :
8181 0 : if (reset && gMh) {
8182 0 : gMh->hs_disconnect();
8183 0 : delete gMh;
8184 0 : gMh = NULL;
8185 0 : gMhkey = 0;
8186 : }
8187 :
8188 0 : status = cm_get_experiment_database(&hDB, NULL);
8189 0 : assert(status == CM_SUCCESS);
8190 :
8191 : // setup a watch on history configuration
8192 :
8193 0 : if (gDoSetupHistoryWatch) {
8194 : HNDLE hKey;
8195 0 : gDoSetupHistoryWatch = false;
8196 :
8197 0 : status = db_find_key(hDB, 0, "/Logger/History", &hKey);
8198 0 : if (status == DB_SUCCESS)
8199 0 : status = db_watch(hDB, hKey, history_watch_callback, NULL);
8200 :
8201 0 : status = db_find_key(hDB, 0, "/History/LoggerHistoryChannel", &hKey);
8202 0 : if (status == DB_SUCCESS)
8203 0 : status = db_watch(hDB, hKey, history_watch_callback, NULL);
8204 : }
8205 :
8206 : // find out if ODB settings have changed and we need to connect to a different history channel
8207 :
8208 0 : HNDLE hKey = 0;
8209 0 : status = hs_find_reader_channel(hDB, &hKey, verbose);
8210 0 : if (status != HS_SUCCESS)
8211 0 : return gMh;
8212 :
8213 : //printf("mh %p, hKey %d, mhkey %d\n", mh, hKey, mhkey);
8214 :
8215 0 : if (gMh && hKey == gMhkey) // same channel as before
8216 0 : return gMh;
8217 :
8218 0 : if (gMh) {
8219 0 : delete gMh;
8220 0 : gMh = NULL;
8221 0 : gMhkey = 0;
8222 : }
8223 :
8224 0 : status = hs_get_history(hDB, hKey, HS_GET_READER|HS_GET_INACTIVE, verbose, &gMh);
8225 0 : if (status != HS_SUCCESS || gMh==NULL) {
8226 0 : cm_msg(MERROR, "get_history", "Cannot configure history, hs_get_history() status %d", status);
8227 0 : gMh = NULL;
8228 0 : return NULL;
8229 : }
8230 :
8231 0 : gMhkey = hKey;
8232 :
8233 : // cm_msg(MINFO, "get_history", "Reading history from channel \'%s\' type \'%s\'", mh->name, mh->type);
8234 :
8235 0 : return gMh;
8236 : }
8237 :
8238 : /*------------------------------------------------------------------*/
8239 :
8240 : #ifdef OS_WINNT
8241 : #undef DELETE
8242 : #endif
8243 :
8244 : #define ALLOC(t,n) (t*)calloc(sizeof(t),(n))
8245 : #define DELETE(x) if (x) { free(x); (x)=NULL; }
8246 : #define DELETEA(x, n) if (x) { for (int i=0; i<(n); i++) { free((x)[i]); (x)[i]=NULL; }; DELETE(x); }
8247 : #define STRDUP(x) strdup(x)
8248 :
8249 : struct HistoryData
8250 : {
8251 : int nvars;
8252 : int alloc_nvars;
8253 : char** event_names;
8254 : char** var_names;
8255 : int* var_index;
8256 : int* odb_index;
8257 : int* status;
8258 : int* num_entries;
8259 : time_t** t;
8260 : double** v;
8261 :
8262 : bool have_last_written;
8263 : time_t* last_written;
8264 :
8265 : time_t tstart;
8266 : time_t tend;
8267 : time_t scale;
8268 :
8269 0 : void Allocate(int xnvars) {
8270 0 : if (alloc_nvars > 0)
8271 0 : Free();
8272 0 : nvars = 0;
8273 0 : alloc_nvars = xnvars;
8274 0 : event_names = ALLOC(char*, alloc_nvars);
8275 0 : var_names = ALLOC(char*, alloc_nvars);
8276 0 : var_index = ALLOC(int, alloc_nvars);
8277 0 : odb_index = ALLOC(int, alloc_nvars);
8278 0 : status = ALLOC(int, alloc_nvars);
8279 0 : num_entries = ALLOC(int, alloc_nvars);
8280 0 : t = ALLOC(time_t*, alloc_nvars);
8281 0 : v = ALLOC(double*, alloc_nvars);
8282 :
8283 0 : have_last_written = false;
8284 0 : last_written = ALLOC(time_t, alloc_nvars);
8285 0 : }
8286 :
8287 0 : void Free() {
8288 0 : DELETEA(event_names, alloc_nvars);
8289 0 : DELETEA(var_names, alloc_nvars);
8290 0 : DELETE(var_index);
8291 0 : DELETE(odb_index);
8292 0 : DELETE(status);
8293 0 : DELETE(num_entries);
8294 0 : DELETEA(t, alloc_nvars);
8295 0 : DELETEA(v, alloc_nvars);
8296 0 : DELETE(last_written);
8297 0 : nvars = 0;
8298 0 : alloc_nvars = 0;
8299 0 : have_last_written = false;
8300 0 : }
8301 :
8302 0 : void Print() const {
8303 0 : printf("this %p, nvars %d. tstart %d, tend %d, scale %d\n", this, nvars, (int)tstart, (int)tend, (int)scale);
8304 0 : for (int i=0; i<nvars; i++) {
8305 0 : printf("var[%d]: [%s/%s][%d] %d entries, status %d", i, event_names[i], var_names[i], var_index[i], num_entries[i], status[i]);
8306 0 : if (status[i]==HS_SUCCESS && num_entries[i]>0 && t[i] && v[i])
8307 0 : printf(", t %d:%d, v %g:%g", (int)t[i][0], (int)t[i][num_entries[i]-1], v[i][0], v[i][num_entries[i]-1]);
8308 0 : printf(" last_written %d", (int)last_written[i]);
8309 0 : printf("\n");
8310 : }
8311 0 : }
8312 :
8313 0 : HistoryData() // ctor
8314 0 : {
8315 0 : nvars = 0;
8316 0 : alloc_nvars = 0;
8317 0 : have_last_written = false;
8318 0 : tstart = 0;
8319 0 : tend = 0;
8320 0 : scale = 0;
8321 0 : }
8322 :
8323 0 : ~HistoryData() // dtor
8324 : {
8325 0 : if (alloc_nvars > 0)
8326 0 : Free();
8327 0 : }
8328 : };
8329 :
8330 : #define READ_HISTORY_DATA 0x1
8331 : #define READ_HISTORY_RUNMARKER 0x2
8332 : #define READ_HISTORY_LAST_WRITTEN 0x4
8333 :
8334 : struct HistVar
8335 : {
8336 : std::string event_name;
8337 : std::string tag_name;
8338 : std::string formula;
8339 : std::string colour;
8340 : std::string label;
8341 : bool show_raw_value = false;
8342 : int order = -1;
8343 : double factor = 1.0;
8344 : double offset = 0;
8345 : double voffset = 0;
8346 : };
8347 :
8348 : struct HistPlot
8349 : {
8350 : std::string timescale = "1h";
8351 : double minimum = 0;
8352 : double maximum = 0;
8353 : bool zero_ylow = false;
8354 : bool log_axis = false;
8355 : bool show_run_markers = true;
8356 : bool show_values = true;
8357 : bool show_fill = true;
8358 : bool show_factor = false;
8359 : bool enable_factor = true;
8360 :
8361 : std::vector<HistVar> vars;
8362 : };
8363 :
8364 : static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel);
8365 :
8366 0 : int read_history(const HistPlot& hp, /*HNDLE hDB, const char *group, const char *panel,*/ int index, int flags, time_t tstart, time_t tend, time_t scale, HistoryData *data)
8367 : {
8368 : //HNDLE hkeypanel, hkeydvar, hkey;
8369 : //KEY key;
8370 : //char path[256];
8371 : //int n_vars;
8372 : int status;
8373 0 : int debug = 1;
8374 :
8375 : //mstrlcpy(path, group, sizeof(path));
8376 : //mstrlcat(path, "/", sizeof(path));
8377 : //mstrlcat(path, panel, sizeof(path));
8378 :
8379 : //printf("read_history, path %s, index %d, flags 0x%x, start %d, end %d, scale %d, data %p\n", path, index, flags, (int)tstart, (int)tend, (int)scale, data);
8380 :
8381 : /* connect to history */
8382 0 : MidasHistoryInterface* mh = get_history();
8383 0 : if (mh == NULL) {
8384 : //r->rsprintf(str, "History is not configured\n");
8385 0 : return HS_FILE_ERROR;
8386 : }
8387 :
8388 : #if 0
8389 : /* check panel name in ODB */
8390 : status = db_find_key(hDB, 0, "/History/Display", &hkey);
8391 : if (!hkey) {
8392 : cm_msg(MERROR, "read_history", "Cannot find \'/History/Display\' in ODB, status %d", status);
8393 : return HS_FILE_ERROR;
8394 : }
8395 :
8396 : /* check panel name in ODB */
8397 : status = db_find_key(hDB, hkey, path, &hkeypanel);
8398 : if (!hkeypanel) {
8399 : cm_msg(MERROR, "read_history", "Cannot find \'%s\' in ODB, status %d", path, status);
8400 : return HS_FILE_ERROR;
8401 : }
8402 :
8403 : status = db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8404 : if (!hkeydvar) {
8405 : cm_msg(MERROR, "read_history", "Cannot find \'%s/Variables\' in ODB, status %d", path, status);
8406 : return HS_FILE_ERROR;
8407 : }
8408 :
8409 : db_get_key(hDB, hkeydvar, &key);
8410 : n_vars = key.num_values;
8411 : #endif
8412 :
8413 0 : data->Allocate(hp.vars.size()+2);
8414 :
8415 0 : data->tstart = tstart;
8416 0 : data->tend = tend;
8417 0 : data->scale = scale;
8418 :
8419 0 : for (size_t i=0; i<hp.vars.size(); i++) {
8420 0 : if (index != -1 && (size_t)index != i)
8421 0 : continue;
8422 :
8423 : //char str[256];
8424 : //int size = sizeof(str);
8425 : //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8426 : //if (status != DB_SUCCESS) {
8427 : // cm_msg(MERROR, "read_history", "Cannot read tag %d in panel %s, status %d", i, path, status);
8428 : // continue;
8429 : //}
8430 :
8431 : /* split varname in event, variable and index: "event/tag[index]" */
8432 :
8433 : //char *p = strchr(str, ':');
8434 : //if (!p)
8435 : // p = strchr(str, '/');
8436 : //
8437 : //if (!p) {
8438 : // cm_msg(MERROR, "read_history", "Tag \"%s\" has wrong format in panel \"%s\"", str, path);
8439 : // continue;
8440 : //}
8441 :
8442 : //*p = 0;
8443 :
8444 0 : data->odb_index[data->nvars] = i;
8445 0 : data->event_names[data->nvars] = STRDUP(hp.vars[i].event_name.c_str());
8446 0 : data->var_names[data->nvars] = STRDUP(hp.vars[i].tag_name.c_str());
8447 0 : data->var_index[data->nvars] = 0;
8448 :
8449 0 : char *q = strchr(data->var_names[data->nvars], '[');
8450 0 : if (q) {
8451 0 : data->var_index[data->nvars] = atoi(q+1);
8452 0 : *q = 0;
8453 : }
8454 :
8455 0 : data->nvars++;
8456 : } // loop over variables
8457 :
8458 : /* write run markes if selected */
8459 0 : if (flags & READ_HISTORY_RUNMARKER) {
8460 :
8461 0 : data->event_names[data->nvars+0] = STRDUP("Run transitions");
8462 0 : data->event_names[data->nvars+1] = STRDUP("Run transitions");
8463 :
8464 0 : data->var_names[data->nvars+0] = STRDUP("State");
8465 0 : data->var_names[data->nvars+1] = STRDUP("Run number");
8466 :
8467 0 : data->var_index[data->nvars+0] = 0;
8468 0 : data->var_index[data->nvars+1] = 0;
8469 :
8470 0 : data->odb_index[data->nvars+0] = -1;
8471 0 : data->odb_index[data->nvars+1] = -2;
8472 :
8473 0 : data->nvars += 2;
8474 : }
8475 :
8476 0 : bool get_last_written = false;
8477 :
8478 0 : if (flags & READ_HISTORY_DATA) {
8479 0 : status = mh->hs_read(tstart, tend, scale,
8480 : data->nvars,
8481 0 : data->event_names,
8482 0 : data->var_names,
8483 0 : data->var_index,
8484 : data->num_entries,
8485 : data->t,
8486 : data->v,
8487 : data->status);
8488 :
8489 0 : if (debug) {
8490 0 : printf("read_history: nvars %d, hs_read() status %d\n", data->nvars, status);
8491 0 : for (int i=0; i<data->nvars; i++) {
8492 0 : printf("read_history: %d: event [%s], var [%s], index %d, odb index %d, status %d, num_entries %d\n", i, data->event_names[i], data->var_names[i], data->var_index[i], data->odb_index[i], data->status[i], data->num_entries[i]);
8493 : }
8494 : }
8495 :
8496 0 : if (status != HS_SUCCESS) {
8497 0 : cm_msg(MERROR, "read_history", "Complete history failure, hs_read() status %d, see messages", status);
8498 0 : return HS_FILE_ERROR;
8499 : }
8500 :
8501 0 : for (int i=0; i<data->nvars; i++) {
8502 0 : if (data->status[i] != HS_SUCCESS || data->num_entries[i] < 1) {
8503 0 : get_last_written = true;
8504 0 : break;
8505 : }
8506 : }
8507 : }
8508 :
8509 0 : if (flags & READ_HISTORY_LAST_WRITTEN)
8510 0 : get_last_written = true;
8511 :
8512 0 : if (get_last_written) {
8513 0 : data->have_last_written = true;
8514 :
8515 0 : status = mh->hs_get_last_written(
8516 : tstart,
8517 : data->nvars,
8518 0 : data->event_names,
8519 0 : data->var_names,
8520 0 : data->var_index,
8521 : data->last_written);
8522 :
8523 0 : if (status != HS_SUCCESS) {
8524 0 : data->have_last_written = false;
8525 : }
8526 : }
8527 :
8528 0 : return SUCCESS;
8529 : }
8530 :
8531 0 : int get_hist_last_written(MVOdb* odb, const char *group, const char *panel, time_t endtime, int index, int want_all, time_t *plastwritten)
8532 : {
8533 : //HNDLE hDB;
8534 : int status;
8535 :
8536 0 : time_t now = ss_time();
8537 :
8538 0 : if (endtime == 0)
8539 0 : endtime = now;
8540 :
8541 0 : HistoryData hsxxx;
8542 0 : HistoryData* hsdata = &hsxxx;
8543 :
8544 : //cm_get_experiment_database(&hDB, NULL);
8545 :
8546 0 : HistPlot hp;
8547 0 : LoadHistPlotFromOdb(odb, &hp, group, panel);
8548 :
8549 0 : double tstart = ss_millitime();
8550 :
8551 0 : int flags = READ_HISTORY_LAST_WRITTEN;
8552 :
8553 0 : status = read_history(hp, /*hDB, group, panel,*/ index, flags, endtime, endtime, 0, hsdata);
8554 :
8555 0 : if (status != HS_SUCCESS) {
8556 : //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8557 0 : return status;
8558 : }
8559 :
8560 0 : if (!hsdata->have_last_written) {
8561 : //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8562 0 : return HS_FILE_ERROR;
8563 : }
8564 :
8565 0 : int count = 0;
8566 0 : time_t tmin = endtime;
8567 0 : time_t tmax = 0;
8568 :
8569 0 : for (int k=0; k<hsdata->nvars; k++) {
8570 0 : int i = hsdata->odb_index[k];
8571 :
8572 0 : if (i<0)
8573 0 : continue;
8574 0 : if (index != -1 && index != i)
8575 0 : continue;
8576 :
8577 0 : time_t lw = hsdata->last_written[k];
8578 :
8579 0 : if (lw==0) // no last_written for this variable, skip it.
8580 0 : continue;
8581 :
8582 0 : if (lw > endtime)
8583 0 : lw = endtime; // just in case hs_get_last_written() returns dates in the "future" for this plot
8584 :
8585 0 : if (lw > tmax)
8586 0 : tmax = lw;
8587 :
8588 0 : if (lw < tmin)
8589 0 : tmin = lw;
8590 :
8591 0 : count++;
8592 :
8593 : //printf("odb index %d, last_written[%d] = %.0f, tmin %.0f, tmax %.0f, endtime %.0f\n", i, k, (double)lw, (double)tmin, (double)tmax, (double)endtime);
8594 : }
8595 :
8596 0 : if (count == 0) // all variables have no last_written
8597 0 : return HS_FILE_ERROR;
8598 :
8599 0 : if (want_all)
8600 0 : *plastwritten = tmin; // all variables have data
8601 : else
8602 0 : *plastwritten = tmax; // at least one variable has data
8603 :
8604 : //printf("tmin %.0f, tmax %.0f, endtime %.0f, last written %.0f\n", (double)tmin, (double)tmax, (double)endtime, (double)*plastwritten);
8605 :
8606 0 : double tend = ss_millitime();
8607 :
8608 : if (/* DISABLES CODE */ (0))
8609 : printf("get_hist_last_written: elapsed time %f ms\n", tend-tstart);
8610 :
8611 0 : return HS_SUCCESS;
8612 0 : }
8613 :
8614 0 : void generate_hist_graph(MVOdb* odb, Return* rr, const char *hgroup, const char *hpanel, char *buffer, int *buffer_size,
8615 : int width, int height,
8616 : time_t xendtime,
8617 : int scale,
8618 : int index,
8619 : int labels, const char *bgcolor, const char *fgcolor, const char *gridcolor)
8620 : {
8621 : HNDLE hDB;
8622 : //KEY key;
8623 : gdImagePtr im;
8624 : gdGifBuffer gb;
8625 : int i, j, k, l;
8626 : //int n_vars;
8627 : int size, status, r, g, b;
8628 : //int x_marker;
8629 : int length;
8630 : int white, grey, red;
8631 : //int black, ltgrey, green, blue;
8632 : int fgcol, bgcol, gridcol;
8633 : int curve_col[MAX_VARS];
8634 : int state_col[3];
8635 : char str[256], *p;
8636 : //INT var_index[MAX_VARS];
8637 : //char event_name[MAX_VARS][NAME_LENGTH];
8638 : //char tag_name[MAX_VARS][64];
8639 : //char var_name[MAX_VARS][NAME_LENGTH];
8640 : //char varname[64];
8641 : //char key_name[256];
8642 : //float factor[MAX_VARS], offset[MAX_VARS];
8643 : //BOOL logaxis, runmarker;
8644 : //double xmin, xrange;
8645 : double ymin, ymax;
8646 : double upper_limit[MAX_VARS], lower_limit[MAX_VARS];
8647 : //float minvalue = (float) -HUGE_VAL;
8648 : //float maxvalue = (float) +HUGE_VAL;
8649 : //int show_values = 0;
8650 : //int sort_vars = 0;
8651 : //int old_vars = 0;
8652 : time_t starttime, endtime;
8653 : int flags;
8654 :
8655 0 : time_t now = ss_time();
8656 :
8657 0 : if (xendtime == 0)
8658 0 : xendtime = now;
8659 :
8660 0 : HistPlot hp;
8661 0 : LoadHistPlotFromOdb(odb, &hp, hgroup, hpanel);
8662 :
8663 0 : std::vector<int> var_index; var_index.resize(hp.vars.size());
8664 :
8665 0 : for (size_t i=0; i<hp.vars.size(); i++) {
8666 0 : var_index[i] = 0;
8667 0 : const char *vp = strchr(hp.vars[i].tag_name.c_str(), '[');
8668 0 : if (vp) {
8669 0 : var_index[i] = atoi(vp + 1);
8670 : }
8671 : }
8672 :
8673 0 : int logaxis = hp.log_axis;
8674 0 : double minvalue = hp.minimum;
8675 0 : double maxvalue = hp.maximum;
8676 :
8677 0 : if ((minvalue == 0) && (maxvalue == 0)) {
8678 0 : minvalue = -HUGE_VAL;
8679 0 : maxvalue = +HUGE_VAL;
8680 : }
8681 :
8682 0 : std::vector<int> x[MAX_VARS];
8683 0 : std::vector<double> y[MAX_VARS];
8684 :
8685 0 : HistoryData hsxxx;
8686 0 : HistoryData* hsdata = &hsxxx;
8687 :
8688 0 : cm_get_experiment_database(&hDB, NULL);
8689 :
8690 : /* generate image */
8691 0 : im = gdImageCreate(width, height);
8692 :
8693 : /* allocate standard colors */
8694 0 : sscanf(bgcolor, "%02x%02x%02x", &r, &g, &b);
8695 0 : bgcol = gdImageColorAllocate(im, r, g, b);
8696 0 : sscanf(fgcolor, "%02x%02x%02x", &r, &g, &b);
8697 0 : fgcol = gdImageColorAllocate(im, r, g, b);
8698 0 : sscanf(gridcolor, "%02x%02x%02x", &r, &g, &b);
8699 0 : gridcol = gdImageColorAllocate(im, r, g, b);
8700 :
8701 0 : grey = gdImageColorAllocate(im, 192, 192, 192);
8702 : //ltgrey = gdImageColorAllocate(im, 208, 208, 208);
8703 0 : white = gdImageColorAllocate(im, 255, 255, 255);
8704 : //black = gdImageColorAllocate(im, 0, 0, 0);
8705 0 : red = gdImageColorAllocate(im, 255, 0, 0);
8706 : //green = gdImageColorAllocate(im, 0, 255, 0);
8707 : //blue = gdImageColorAllocate(im, 0, 0, 255);
8708 :
8709 0 : curve_col[0] = gdImageColorAllocate(im, 0, 0, 255);
8710 0 : curve_col[1] = gdImageColorAllocate(im, 0, 192, 0);
8711 0 : curve_col[2] = gdImageColorAllocate(im, 255, 0, 0);
8712 0 : curve_col[3] = gdImageColorAllocate(im, 0, 192, 192);
8713 0 : curve_col[4] = gdImageColorAllocate(im, 255, 0, 255);
8714 0 : curve_col[5] = gdImageColorAllocate(im, 192, 192, 0);
8715 0 : curve_col[6] = gdImageColorAllocate(im, 128, 128, 128);
8716 0 : curve_col[7] = gdImageColorAllocate(im, 128, 255, 128);
8717 0 : curve_col[8] = gdImageColorAllocate(im, 255, 128, 128);
8718 0 : curve_col[9] = gdImageColorAllocate(im, 128, 128, 255);
8719 0 : for (i=10; i<MAX_VARS; i++)
8720 0 : curve_col[i] = gdImageColorAllocate(im, 128, 128, 128);
8721 :
8722 0 : state_col[0] = gdImageColorAllocate(im, 255, 0, 0);
8723 0 : state_col[1] = gdImageColorAllocate(im, 255, 255, 0);
8724 0 : state_col[2] = gdImageColorAllocate(im, 0, 255, 0);
8725 :
8726 : /* Set transparent color. */
8727 0 : gdImageColorTransparent(im, grey);
8728 :
8729 : /* Title */
8730 0 : gdImageString(im, gdFontGiant, width / 2 - (strlen(hpanel) * gdFontGiant->w) / 2, 2, (char*)hpanel, fgcol);
8731 :
8732 : /* connect to history */
8733 0 : MidasHistoryInterface *mh = get_history();
8734 0 : if (mh == NULL) {
8735 0 : sprintf(str, "History is not configured, see messages");
8736 0 : gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8737 0 : goto error;
8738 : }
8739 :
8740 : ///* check panel name in ODB */
8741 : //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
8742 : //db_find_key(hDB, 0, str, &hkeypanel);
8743 : //if (!hkeypanel) {
8744 : // sprintf(str, "Cannot find /History/Display/%s/%s in ODB", hgroup, hpanel);
8745 : // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8746 : // goto error;
8747 : //}
8748 :
8749 : //db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8750 : //if (!hkeydvar) {
8751 : // sprintf(str, "Cannot find /History/Display/%s/%s/Variables in ODB", hgroup, hpanel);
8752 : // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8753 : // goto error;
8754 : //}
8755 :
8756 : //db_get_key(hDB, hkeydvar, &key);
8757 : //n_vars = key.num_values;
8758 :
8759 0 : if (hp.vars.empty()) {
8760 0 : sprintf(str, "No variables in panel %s/%s", hgroup, hpanel);
8761 0 : gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8762 0 : goto error;
8763 : }
8764 :
8765 0 : if (hp.vars.size() > MAX_VARS) {
8766 0 : sprintf(str, "Too many variables in panel %s/%s", hgroup, hpanel);
8767 0 : gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8768 0 : goto error;
8769 : }
8770 :
8771 0 : ymin = ymax = 0;
8772 : //logaxis = runmarker = 0;
8773 :
8774 0 : for (i = 0; i < (int)hp.vars.size(); i++) {
8775 0 : if (index != -1 && index != i)
8776 0 : continue;
8777 :
8778 : //size = sizeof(str);
8779 : //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8780 : //if (status != DB_SUCCESS) {
8781 : // sprintf(str, "Cannot read tag %d in panel %s/%s, status %d", i, hgroup, hpanel, status);
8782 : // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8783 : // goto error;
8784 : //}
8785 : //
8786 : //mstrlcpy(tag_name[i], str, sizeof(tag_name[0]));
8787 :
8788 : ///* split varname in event, variable and index */
8789 : //char *tp = strchr(tag_name[i], ':');
8790 : //if (tp) {
8791 : // mstrlcpy(event_name[i], tag_name[i], sizeof(event_name[0]));
8792 : // char *ep = strchr(event_name[i], ':');
8793 : // if (ep)
8794 : // *ep = 0;
8795 : // mstrlcpy(var_name[i], tp+1, sizeof(var_name[0]));
8796 : // var_index[i] = 0;
8797 : // char *vp = strchr(var_name[i], '[');
8798 : // if (vp) {
8799 : // var_index[i] = atoi(vp + 1);
8800 : // *vp = 0;
8801 : // }
8802 : //} else {
8803 : // sprintf(str, "Tag \"%s\" has wrong format in panel \"%s/%s\"", tag_name[i], hgroup, hpanel);
8804 : // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8805 : // goto error;
8806 : //}
8807 : //
8808 : //db_find_key(hDB, hkeypanel, "Colour", &hkey);
8809 : //if (hkey) {
8810 : // size = sizeof(str);
8811 : // status = db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
8812 : // if (status == DB_SUCCESS) {
8813 : // if (str[0] == '#') {
8814 : // char sss[3];
8815 : // int r, g, b;
8816 : //
8817 : // sss[0] = str[1];
8818 : // sss[1] = str[2];
8819 : // sss[2] = 0;
8820 : // r = strtoul(sss, NULL, 16);
8821 : // sss[0] = str[3];
8822 : // sss[1] = str[4];
8823 : // sss[2] = 0;
8824 : // g = strtoul(sss, NULL, 16);
8825 : // sss[0] = str[5];
8826 : // sss[1] = str[6];
8827 : // sss[2] = 0;
8828 : // b = strtoul(sss, NULL, 16);
8829 : //
8830 : // curve_col[i] = gdImageColorAllocate(im, r, g, b);
8831 : // }
8832 : // }
8833 : //}
8834 :
8835 0 : if (hp.vars[i].colour[0] == '#') {
8836 0 : const char* str = hp.vars[i].colour.c_str();
8837 : char sss[3];
8838 : int r, g, b;
8839 :
8840 0 : sss[0] = str[1];
8841 0 : sss[1] = str[2];
8842 0 : sss[2] = 0;
8843 0 : r = strtoul(sss, NULL, 16);
8844 0 : sss[0] = str[3];
8845 0 : sss[1] = str[4];
8846 0 : sss[2] = 0;
8847 0 : g = strtoul(sss, NULL, 16);
8848 0 : sss[0] = str[5];
8849 0 : sss[1] = str[6];
8850 0 : sss[2] = 0;
8851 0 : b = strtoul(sss, NULL, 16);
8852 :
8853 0 : curve_col[i] = gdImageColorAllocate(im, r, g, b);
8854 : }
8855 :
8856 : /* get timescale */
8857 0 : if (scale == 0) {
8858 : //std::string ts = "1h";
8859 : //status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8860 : //if (status != DB_SUCCESS) {
8861 : // /* delete old integer key */
8862 : // db_find_key(hDB, hkeypanel, "Timescale", &hkey);
8863 : // if (hkey)
8864 : // db_delete_key(hDB, hkey, FALSE);
8865 : //
8866 : // ts = "1h";
8867 : // status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8868 : //}
8869 :
8870 0 : scale = time_to_sec(hp.timescale.c_str());
8871 : }
8872 :
8873 : //for (j = 0; j < MAX_VARS; j++) {
8874 : // factor[j] = 1;
8875 : // offset[j] = 0;
8876 : //}
8877 :
8878 : ///* get factors */
8879 : //size = sizeof(float) * n_vars;
8880 : //db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
8881 :
8882 : ///* get offsets */
8883 : //size = sizeof(float) * n_vars;
8884 : //db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
8885 :
8886 : ///* get axis type */
8887 : //size = sizeof(logaxis);
8888 : //logaxis = 0;
8889 : //db_get_value(hDB, hkeypanel, "Log axis", &logaxis, &size, TID_BOOL, TRUE);
8890 :
8891 : ///* get show_values type */
8892 : //size = sizeof(show_values);
8893 : //show_values = 0;
8894 : //db_get_value(hDB, hkeypanel, "Show values", &show_values, &size, TID_BOOL, TRUE);
8895 :
8896 : ///* get sort_vars type */
8897 : //size = sizeof(sort_vars);
8898 : //sort_vars = 0;
8899 : //db_get_value(hDB, hkeypanel, "Sort vars", &sort_vars, &size, TID_BOOL, TRUE);
8900 :
8901 : ///* get old_vars type */
8902 : //size = sizeof(old_vars);
8903 : //old_vars = 0;
8904 : //db_get_value(hDB, hkeypanel, "Show old vars", &old_vars, &size, TID_BOOL, TRUE);
8905 :
8906 : ///* get min value */
8907 : //size = sizeof(minvalue);
8908 : //minvalue = (float) -HUGE_VAL;
8909 : //db_get_value(hDB, hkeypanel, "Minimum", &minvalue, &size, TID_FLOAT, TRUE);
8910 :
8911 : ///* get max value */
8912 : //size = sizeof(maxvalue);
8913 : //maxvalue = (float) +HUGE_VAL;
8914 : //db_get_value(hDB, hkeypanel, "Maximum", &maxvalue, &size, TID_FLOAT, TRUE);
8915 :
8916 : //if ((minvalue == 0) && (maxvalue == 0)) {
8917 : // minvalue = (float) -HUGE_VAL;
8918 : // maxvalue = (float) +HUGE_VAL;
8919 : //}
8920 :
8921 : ///* get runmarker flag */
8922 : //size = sizeof(runmarker);
8923 : //runmarker = 1;
8924 : //db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
8925 :
8926 : /* make ODB path from tag name */
8927 0 : std::string odbpath;
8928 0 : HNDLE hkeyeq = 0;
8929 : HNDLE hkeyroot;
8930 0 : db_find_key(hDB, 0, "/Equipment", &hkeyroot);
8931 0 : if (hkeyroot) {
8932 0 : for (j = 0;; j++) {
8933 : HNDLE hkeyeq;
8934 0 : db_enum_key(hDB, hkeyroot, j, &hkeyeq);
8935 :
8936 0 : if (!hkeyeq)
8937 0 : break;
8938 :
8939 : KEY key;
8940 0 : db_get_key(hDB, hkeyeq, &key);
8941 0 : if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
8942 : /* check if variable is individual key under variables/ */
8943 0 : sprintf(str, "Variables/%s", hp.vars[i].tag_name.c_str());
8944 : HNDLE hkey;
8945 0 : db_find_key(hDB, hkeyeq, str, &hkey);
8946 0 : if (hkey) {
8947 : //sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[i], var_name[i]);
8948 0 : odbpath = "";
8949 0 : odbpath += "/Equipment/";
8950 0 : odbpath += hp.vars[i].event_name;
8951 0 : odbpath += "/Variables/";
8952 0 : odbpath += hp.vars[i].tag_name;
8953 0 : break;
8954 : }
8955 :
8956 : /* check if variable is in setttins/names array */
8957 : HNDLE hkeynames;
8958 0 : db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
8959 0 : if (hkeynames) {
8960 : /* extract variable name and Variables/<key> */
8961 0 : mstrlcpy(str, hp.vars[i].tag_name.c_str(), sizeof(str));
8962 0 : p = str + strlen(str) - 1;
8963 0 : while (p > str && *p != ' ')
8964 0 : p--;
8965 0 : std::string key_name = p + 1;
8966 0 : *p = 0;
8967 :
8968 0 : std::string varname = str;
8969 :
8970 : /* find key in single name array */
8971 0 : db_get_key(hDB, hkeynames, &key);
8972 0 : for (k = 0; k < key.num_values; k++) {
8973 0 : size = sizeof(str);
8974 0 : db_get_data_index(hDB, hkeynames, str, &size, k, TID_STRING);
8975 0 : if (equal_ustring(str, varname.c_str())) {
8976 : //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, k);
8977 0 : odbpath = "";
8978 0 : odbpath += "/Equipment/";
8979 0 : odbpath += hp.vars[i].event_name;
8980 0 : odbpath += "/Variables/";
8981 0 : odbpath += key_name;
8982 0 : odbpath += "[";
8983 0 : odbpath += toString(k);
8984 0 : odbpath += "]";
8985 0 : break;
8986 : }
8987 : }
8988 0 : } else {
8989 : /* go through /variables/<name> entries */
8990 : HNDLE hkeyvars;
8991 0 : db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
8992 0 : if (hkeyvars) {
8993 0 : for (k = 0;; k++) {
8994 0 : db_enum_key(hDB, hkeyvars, k, &hkey);
8995 :
8996 0 : if (!hkey)
8997 0 : break;
8998 :
8999 : /* find "settins/names <key>" for this key */
9000 0 : db_get_key(hDB, hkey, &key);
9001 :
9002 : /* find key in key_name array */
9003 0 : std::string key_name = key.name;
9004 :
9005 0 : std::string path;
9006 : //sprintf(str, "Settings/Names %s", key_name);
9007 0 : path += "Settings/Names ";
9008 0 : path += key_name;
9009 :
9010 : HNDLE hkeynames;
9011 0 : db_find_key(hDB, hkeyeq, path.c_str(), &hkeynames);
9012 0 : if (hkeynames) {
9013 0 : db_get_key(hDB, hkeynames, &key);
9014 0 : for (l = 0; l < key.num_values; l++) {
9015 0 : size = sizeof(str);
9016 0 : db_get_data_index(hDB, hkeynames, str, &size, l, TID_STRING);
9017 0 : if (equal_ustring(str, hp.vars[i].tag_name.c_str())) {
9018 : //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, l);
9019 0 : odbpath = "";
9020 0 : odbpath += "/Equipment/";
9021 0 : odbpath += hp.vars[i].event_name;
9022 0 : odbpath += "/Variables/";
9023 0 : odbpath += key_name;
9024 0 : odbpath += "[";
9025 0 : odbpath += toString(l);
9026 0 : odbpath += "]";
9027 0 : break;
9028 : }
9029 : }
9030 : }
9031 0 : }
9032 : }
9033 : }
9034 :
9035 0 : break;
9036 : }
9037 0 : }
9038 :
9039 0 : if (!hkeyeq) {
9040 0 : db_find_key(hDB, 0, "/History/Links", &hkeyroot);
9041 0 : if (hkeyroot) {
9042 0 : for (j = 0;; j++) {
9043 : HNDLE hkey;
9044 0 : db_enum_link(hDB, hkeyroot, j, &hkey);
9045 :
9046 0 : if (!hkey)
9047 0 : break;
9048 :
9049 : KEY key;
9050 0 : db_get_key(hDB, hkey, &key);
9051 0 : if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
9052 0 : db_enum_key(hDB, hkeyroot, j, &hkey);
9053 0 : db_find_key(hDB, hkey, hp.vars[i].tag_name.c_str(), &hkey);
9054 0 : if (hkey) {
9055 0 : db_get_key(hDB, hkey, &key);
9056 0 : odbpath = db_get_path(hDB, hkey);
9057 0 : if (key.num_values > 1) {
9058 0 : odbpath += "[";
9059 0 : odbpath += toString(var_index[i]);
9060 0 : odbpath += "]";
9061 : }
9062 0 : break;
9063 : }
9064 : }
9065 0 : }
9066 : }
9067 : }
9068 : }
9069 :
9070 : /* search alarm limits */
9071 0 : upper_limit[i] = lower_limit[i] = -12345;
9072 0 : db_find_key(hDB, 0, "Alarms/Alarms", &hkeyroot);
9073 0 : if (odbpath.length() > 0 && hkeyroot) {
9074 0 : for (j = 0;; j++) {
9075 : HNDLE hkey;
9076 0 : db_enum_key(hDB, hkeyroot, j, &hkey);
9077 :
9078 0 : if (!hkey)
9079 0 : break;
9080 :
9081 0 : size = sizeof(str);
9082 0 : db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
9083 :
9084 0 : if (strstr(str, odbpath.c_str())) {
9085 0 : if (strchr(str, '<')) {
9086 0 : p = strchr(str, '<') + 1;
9087 0 : if (*p == '=')
9088 0 : p++;
9089 0 : if (hp.enable_factor) {
9090 0 : lower_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9091 : } else {
9092 0 : lower_limit[i] = atof(p);
9093 : }
9094 : }
9095 0 : if (strchr(str, '>')) {
9096 0 : p = strchr(str, '>') + 1;
9097 0 : if (*p == '=')
9098 0 : p++;
9099 0 : if (hp.enable_factor) {
9100 0 : upper_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9101 : } else {
9102 0 : upper_limit[i] = atof(p);
9103 : }
9104 : }
9105 : }
9106 0 : }
9107 : }
9108 0 : } // loop over variables
9109 :
9110 : //starttime = now - scale + toffset;
9111 : //endtime = now + toffset;
9112 :
9113 0 : starttime = xendtime - scale;
9114 0 : endtime = xendtime;
9115 :
9116 : //printf("now %d, scale %d, xendtime %d, starttime %d, endtime %d\n", now, scale, xendtime, starttime, endtime);
9117 :
9118 0 : flags = READ_HISTORY_DATA;
9119 0 : if (hp.show_run_markers)
9120 0 : flags |= READ_HISTORY_RUNMARKER;
9121 :
9122 0 : status = read_history(hp, /*hDB, hgroup, hpanel,*/ index, flags, starttime, endtime, scale/1000+1, hsdata);
9123 :
9124 0 : if (status != HS_SUCCESS) {
9125 0 : sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
9126 0 : gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
9127 0 : goto error;
9128 : }
9129 :
9130 : DWORD n_point[MAX_VARS];
9131 : char var_status[MAX_VARS][256];
9132 :
9133 0 : for (int k=0; k<hsdata->nvars; k++) {
9134 0 : int i = hsdata->odb_index[k];
9135 :
9136 0 : if (i<0)
9137 0 : continue;
9138 :
9139 0 : if (index != -1 && index != i)
9140 0 : continue;
9141 :
9142 0 : n_point[i] = 0;
9143 :
9144 0 : var_status[i][0] = 0;
9145 0 : if (hsdata->status[k] == HS_UNDEFINED_VAR) {
9146 0 : sprintf(var_status[i], "not found in history");
9147 0 : continue;
9148 0 : } else if (hsdata->status[k] != HS_SUCCESS) {
9149 0 : sprintf(var_status[i], "hs_read() error %d, see messages", hsdata->status[k]);
9150 0 : continue;
9151 : }
9152 :
9153 0 : int n_vp = 0;
9154 0 : for (int j=0; j<hsdata->num_entries[k]; j++) {
9155 0 : int xx = (int)(hsdata->t[k][j]);
9156 0 : double yy = hsdata->v[k][j];
9157 :
9158 : /* skip NaNs */
9159 0 : if (ss_isnan(yy))
9160 0 : continue;
9161 :
9162 : /* skip INFs */
9163 0 : if (!ss_isfin(yy))
9164 0 : continue;
9165 :
9166 : /* avoid overflow */
9167 0 : if (yy > 1E30)
9168 0 : yy = 1E30f;
9169 :
9170 : /* apply factor and offset */
9171 0 : if (hp.enable_factor) {
9172 0 : yy = hp.vars[i].factor * (yy - hp.vars[i].voffset) + hp.vars[i].offset;
9173 : }
9174 :
9175 : /* calculate ymin and ymax */
9176 0 : if ((i == 0 || index != -1) && n_vp == 0)
9177 0 : ymin = ymax = yy;
9178 : else {
9179 0 : if (yy > ymax)
9180 0 : ymax = yy;
9181 0 : if (yy < ymin)
9182 0 : ymin = yy;
9183 : }
9184 :
9185 : /* increment number of valid points */
9186 :
9187 0 : x[i].push_back(xx);
9188 0 : y[i].push_back(yy);
9189 :
9190 0 : n_vp++;
9191 :
9192 : } // loop over data
9193 :
9194 0 : n_point[i] = n_vp;
9195 :
9196 0 : assert(x[i].size() == y[i].size());
9197 : }
9198 :
9199 : //int flag;
9200 : int xmaxm;
9201 : int row;
9202 : int xold;
9203 : int yold;
9204 : int aoffset;
9205 : double yb1, yb2, yf1, yf2;
9206 : int xs, ys;
9207 : int x1, x2;
9208 : int y1, y2;
9209 : int xs_old;
9210 : double ybase;
9211 :
9212 : gdPoint poly[3];
9213 :
9214 0 : if (ymin < minvalue)
9215 0 : ymin = minvalue;
9216 :
9217 0 : if (ymax > maxvalue)
9218 0 : ymax = maxvalue;
9219 :
9220 : /* check if ylow = 0 */
9221 0 : if (index == -1) {
9222 : //flag = 0;
9223 : //size = sizeof(flag);
9224 : //db_get_value(hDB, hkeypanel, "Zero ylow", &flag, &size, TID_BOOL, TRUE);
9225 0 : if (hp.zero_ylow && ymin > 0)
9226 0 : ymin = 0;
9227 : }
9228 :
9229 : /* if min and max too close together, switch to linear axis */
9230 0 : if (logaxis && ymin > 0 && ymax > 0) {
9231 0 : yb1 = pow(10, floor(log(ymin) / LN10));
9232 0 : yf1 = floor(ymin / yb1);
9233 0 : yb2 = pow(10, floor(log(ymax) / LN10));
9234 0 : yf2 = floor(ymax / yb2);
9235 :
9236 0 : if (yb1 == yb2 && yf1 == yf2)
9237 0 : logaxis = 0;
9238 : else {
9239 : /* round down and up ymin and ymax */
9240 0 : ybase = pow(10, floor(log(ymin) / LN10));
9241 0 : ymin = (floor(ymin / ybase) * ybase);
9242 0 : ybase = pow(10, floor(log(ymax) / LN10));
9243 0 : ymax = ((floor(ymax / ybase) + 1) * ybase);
9244 : }
9245 : }
9246 :
9247 : /* avoid negative limits for log axis */
9248 0 : if (logaxis) {
9249 0 : if (ymax <= 0)
9250 0 : ymax = 1;
9251 0 : if (ymin <= 0)
9252 0 : ymin = 1E-12f;
9253 : }
9254 :
9255 : /* increase limits by 5% */
9256 0 : if (ymin == 0 && ymax == 0) {
9257 0 : ymin = -1;
9258 0 : ymax = 1;
9259 : } else {
9260 0 : if (!logaxis) {
9261 0 : ymax += (ymax - ymin) / 20.f;
9262 :
9263 0 : if (ymin != 0)
9264 0 : ymin -= (ymax - ymin) / 20.f;
9265 : }
9266 : }
9267 :
9268 : /* avoid ymin == ymax */
9269 0 : if (ymax == ymin) {
9270 0 : if (logaxis) {
9271 0 : ymax *= 2;
9272 0 : ymin /= 2;
9273 : } else {
9274 0 : ymax += 10;
9275 0 : ymin -= 10;
9276 : }
9277 : }
9278 :
9279 : /* calculate X limits */
9280 : //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9281 : //xmax = (double) (toffset / 3600.0);
9282 : //xrange = xmax - xmin;
9283 : //xrange = scale/3600.0;
9284 :
9285 : /* caluclate required space for Y-axis */
9286 0 : aoffset = vaxis(im, gdFontSmall, fgcol, gridcol, 0, 0, height, -3, -5, -7, -8, 0, ymin, ymax, logaxis);
9287 0 : aoffset += 2;
9288 :
9289 0 : x1 = aoffset;
9290 0 : y1 = height - 20;
9291 0 : x2 = width - 20;
9292 0 : y2 = 20;
9293 :
9294 0 : gdImageFilledRectangle(im, x1, y2, x2, y1, bgcol);
9295 :
9296 : /* draw axis frame */
9297 0 : taxis(im, gdFontSmall, fgcol, gridcol, x1, y1, x2 - x1, width, 3, 5, 9, 10, 0, (double)starttime, (double)endtime);
9298 :
9299 0 : vaxis(im, gdFontSmall, fgcol, gridcol, x1, y1, y1 - y2, -3, -5, -7, -8, x2 - x1, ymin, ymax, logaxis);
9300 0 : gdImageLine(im, x1, y2, x2, y2, fgcol);
9301 0 : gdImageLine(im, x2, y2, x2, y1, fgcol);
9302 :
9303 0 : xs = ys = xold = yold = 0;
9304 :
9305 : /* old code for run markers, new code is below */
9306 :
9307 : /* write run markes if selected */
9308 : if (/* DISABLES CODE */ (0) && hp.show_run_markers) {
9309 :
9310 : const char* event_names[] = {
9311 : "Run transitions",
9312 : "Run transitions",
9313 : 0 };
9314 :
9315 : const char* tag_names[] = {
9316 : "State",
9317 : "Run number",
9318 : 0 };
9319 :
9320 : const int tag_indexes[] = {
9321 : 0,
9322 : 0,
9323 : 0 };
9324 :
9325 : int num_entries[3];
9326 : time_t *tbuf[3];
9327 : double *dbuf[3];
9328 : int st[3];
9329 :
9330 : num_entries[0] = 0;
9331 : num_entries[1] = 0;
9332 :
9333 : status = mh->hs_read(starttime - scale, endtime, 0,
9334 : 2, event_names, tag_names, tag_indexes,
9335 : num_entries, tbuf, dbuf, st);
9336 :
9337 : //printf("read run info: status %d, entries %d %d\n", status, num_entries[0], num_entries[1]);
9338 :
9339 : int n_marker = num_entries[0];
9340 :
9341 : if (status == HS_SUCCESS && n_marker > 0 && n_marker < 100) {
9342 : xs_old = -1;
9343 : xmaxm = x1;
9344 : for (j = 0; j < (int) n_marker; j++) {
9345 : int col;
9346 :
9347 : // explicit algebra manipulation to clarify computations:
9348 :
9349 : //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9350 : //xrange = scale/3600.0;
9351 : //time_t starttime = now - scale + toffset;
9352 :
9353 : //x_marker = (int)(tbuf[1][j] - now);
9354 : //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9355 : //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9356 : //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9357 : //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9358 : xs = (int) ((tbuf[1][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9359 :
9360 : if (xs < x1)
9361 : continue;
9362 : if (xs >= x2)
9363 : continue;
9364 :
9365 : double run_number = dbuf[1][j];
9366 :
9367 : if (xs <= xs_old)
9368 : xs = xs_old + 1;
9369 : xs_old = xs;
9370 :
9371 : if (dbuf[0][j] == 1)
9372 : col = state_col[0];
9373 : else if (dbuf[0][j] == 2)
9374 : col = state_col[1];
9375 : else if (dbuf[0][j] == 3)
9376 : col = state_col[2];
9377 : else
9378 : col = state_col[0];
9379 :
9380 : gdImageDashedLine(im, xs, y1, xs, y2, col);
9381 :
9382 : sprintf(str, "%.0f", run_number);
9383 :
9384 : if (dbuf[0][j] == STATE_RUNNING) {
9385 : if (xs > xmaxm) {
9386 : gdImageStringUp(im, gdFontSmall, xs + 0, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9387 : xmaxm = xs - 2 + gdFontSmall->h;
9388 : }
9389 : } else if (dbuf[0][j] == STATE_STOPPED) {
9390 : if (xs + 2 - gdFontSmall->h > xmaxm) {
9391 : gdImageStringUp(im, gdFontSmall, xs + 2 - gdFontSmall->h, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9392 : xmaxm = xs - 1;
9393 : }
9394 : }
9395 : }
9396 : }
9397 :
9398 : if (num_entries[0]) {
9399 : free(tbuf[0]);
9400 : free(dbuf[0]);
9401 : tbuf[0] = NULL;
9402 : dbuf[0] = NULL;
9403 : }
9404 :
9405 : if (num_entries[1]) {
9406 : free(tbuf[1]);
9407 : free(dbuf[1]);
9408 : tbuf[1] = NULL;
9409 : dbuf[1] = NULL;
9410 : }
9411 : }
9412 :
9413 : /* write run markes if selected */
9414 0 : if (hp.show_run_markers) {
9415 :
9416 0 : int index_state = -1;
9417 0 : int index_run_number = -1;
9418 :
9419 0 : for (int k=0; k<hsdata->nvars; k++) {
9420 0 : if (hsdata->odb_index[k] == -1)
9421 0 : index_state = k;
9422 :
9423 0 : if (hsdata->odb_index[k] == -2)
9424 0 : index_run_number = k;
9425 : }
9426 :
9427 0 : bool ok = true;
9428 :
9429 0 : if (ok)
9430 0 : ok = (index_state >= 0) && (index_run_number >= 0);
9431 :
9432 0 : if (ok)
9433 0 : ok = (hsdata->status[index_state] == HS_SUCCESS);
9434 :
9435 0 : if (ok)
9436 0 : ok = (hsdata->status[index_run_number] == HS_SUCCESS);
9437 :
9438 : if (/* DISABLES CODE */ (0) && ok)
9439 : printf("read run info: indexes: %d, %d, status: %d, %d, entries: %d, %d\n", index_state, index_run_number, hsdata->status[index_state], hsdata->status[index_run_number], hsdata->num_entries[index_state], hsdata->num_entries[index_run_number]);
9440 :
9441 0 : if (ok)
9442 0 : ok = (hsdata->num_entries[index_state] == hsdata->num_entries[index_run_number]);
9443 :
9444 0 : int n_marker = hsdata->num_entries[index_state];
9445 :
9446 0 : if (ok && n_marker > 0 && n_marker < 100) {
9447 0 : xs_old = -1;
9448 0 : xmaxm = x1;
9449 0 : for (j = 0; j < (int) n_marker; j++) {
9450 : int col;
9451 :
9452 : // explicit algebra manipulation to clarify computations:
9453 :
9454 : //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9455 : //xrange = scale/3600.0;
9456 : //time_t starttime = now - scale + toffset;
9457 :
9458 : //x_marker = (int)(tbuf[1][j] - now);
9459 : //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9460 : //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9461 : //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9462 : //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9463 0 : xs = (int) ((hsdata->t[index_state][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9464 :
9465 0 : if (xs < x1)
9466 0 : continue;
9467 0 : if (xs >= x2)
9468 0 : continue;
9469 :
9470 0 : double run_number = hsdata->v[index_run_number][j];
9471 :
9472 0 : if (xs <= xs_old)
9473 0 : xs = xs_old + 1;
9474 0 : xs_old = xs;
9475 :
9476 0 : int state = (int)hsdata->v[index_state][j];
9477 :
9478 0 : if (state == 1)
9479 0 : col = state_col[0];
9480 0 : else if (state == 2)
9481 0 : col = state_col[1];
9482 0 : else if (state == 3)
9483 0 : col = state_col[2];
9484 : else
9485 0 : col = state_col[0];
9486 :
9487 0 : gdImageDashedLine(im, xs, y1, xs, y2, col);
9488 :
9489 0 : sprintf(str, "%.0f", run_number);
9490 :
9491 0 : if (state == STATE_RUNNING) {
9492 0 : if (xs > xmaxm) {
9493 0 : gdImageStringUp(im, gdFontSmall, xs + 0, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9494 0 : xmaxm = xs - 2 + gdFontSmall->h;
9495 : }
9496 0 : } else if (state == STATE_STOPPED) {
9497 0 : if (xs + 2 - gdFontSmall->h > xmaxm) {
9498 0 : gdImageStringUp(im, gdFontSmall, xs + 2 - gdFontSmall->h, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9499 0 : xmaxm = xs - 1;
9500 : }
9501 : }
9502 : }
9503 : }
9504 : }
9505 :
9506 0 : for (i = 0; i < (int)hp.vars.size(); i++) {
9507 0 : if (index != -1 && index != i)
9508 0 : continue;
9509 :
9510 : /* draw alarm limits */
9511 0 : if (lower_limit[i] != -12345) {
9512 0 : if (logaxis) {
9513 0 : if (lower_limit[i] <= 0)
9514 0 : ys = y1;
9515 : else
9516 0 : ys = (int) (y1 - (log(lower_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9517 : } else {
9518 0 : ys = (int) (y1 - (lower_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9519 : }
9520 :
9521 0 : if (xs < 0)
9522 0 : xs = 0;
9523 0 : if (xs >= width)
9524 0 : xs = width-1;
9525 0 : if (ys < 0)
9526 0 : ys = 0;
9527 0 : if (ys >= height)
9528 0 : ys = height-1;
9529 :
9530 0 : if (ys > y2 && ys < y1) {
9531 0 : gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
9532 :
9533 0 : poly[0].x = x1;
9534 0 : poly[0].y = ys;
9535 0 : poly[1].x = x1 + 5;
9536 0 : poly[1].y = ys;
9537 0 : poly[2].x = x1;
9538 0 : poly[2].y = ys - 5;
9539 :
9540 0 : gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9541 : }
9542 : }
9543 0 : if (upper_limit[i] != -12345) {
9544 0 : if (logaxis) {
9545 0 : if (upper_limit[i] <= 0)
9546 0 : ys = y1;
9547 : else
9548 0 : ys = (int) (y1 - (log(upper_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9549 : } else {
9550 0 : ys = (int) (y1 - (upper_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9551 : }
9552 :
9553 0 : if (xs < 0)
9554 0 : xs = 0;
9555 0 : if (xs >= width)
9556 0 : xs = width-1;
9557 0 : if (ys < 0)
9558 0 : ys = 0;
9559 0 : if (ys >= height)
9560 0 : ys = height-1;
9561 :
9562 0 : if (ys > y2 && ys < y1) {
9563 0 : gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
9564 :
9565 0 : poly[0].x = x1;
9566 0 : poly[0].y = ys;
9567 0 : poly[1].x = x1 + 5;
9568 0 : poly[1].y = ys;
9569 0 : poly[2].x = x1;
9570 0 : poly[2].y = ys + 5;
9571 :
9572 0 : gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9573 : }
9574 : }
9575 :
9576 0 : for (j = 0; j < (int) n_point[i]; j++) {
9577 : //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9578 : //xrange = scale/3600.0;
9579 : //xs = (int) (((x[i][j]-now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9580 : //xs = (int) (((x[i][j] - now + scale - toffset) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9581 : //xs = (int) (((x[i][j] - starttime) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9582 0 : xs = (int) (((x[i][j] - starttime)/1.0) / (1.0*scale) * (x2 - x1) + x1 + 0.5);
9583 :
9584 0 : if (logaxis) {
9585 0 : if (y[i][j] <= 0)
9586 0 : ys = y1;
9587 : else
9588 0 : ys = (int) (y1 - (log(y[i][j]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9589 : } else {
9590 0 : ys = (int) (y1 - (y[i][j] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9591 : }
9592 :
9593 0 : if (xs < 0)
9594 0 : xs = 0;
9595 0 : if (xs >= width)
9596 0 : xs = width-1;
9597 0 : if (ys < 0)
9598 0 : ys = 0;
9599 0 : if (ys >= height)
9600 0 : ys = height-1;
9601 :
9602 0 : if (j > 0)
9603 0 : gdImageLine(im, xold, yold, xs, ys, curve_col[i]);
9604 0 : xold = xs;
9605 0 : yold = ys;
9606 : }
9607 :
9608 0 : if (n_point[i] > 0) {
9609 0 : poly[0].x = xs;
9610 0 : poly[0].y = ys;
9611 0 : poly[1].x = xs + 12;
9612 0 : poly[1].y = ys - 6;
9613 0 : poly[2].x = xs + 12;
9614 0 : poly[2].y = ys + 6;
9615 :
9616 0 : gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9617 : }
9618 : }
9619 :
9620 0 : if (labels) {
9621 0 : for (i = 0; i < (int)hp.vars.size(); i++) {
9622 0 : if (index != -1 && index != i)
9623 0 : continue;
9624 :
9625 : //str[0] = 0;
9626 : //status = db_find_key(hDB, hkeypanel, "Label", &hkeydvar);
9627 : //if (status == DB_SUCCESS) {
9628 : // size = sizeof(str);
9629 : // status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
9630 : //}
9631 :
9632 0 : std::string str = hp.vars[i].label.c_str();
9633 :
9634 0 : if (str.empty()) {
9635 0 : if (hp.enable_factor) {
9636 0 : str = hp.vars[i].tag_name;
9637 :
9638 0 : if (hp.vars[i].voffset > 0)
9639 0 : str += msprintf(" - %G", hp.vars[i].voffset);
9640 0 : else if (hp.vars[i].voffset < 0)
9641 0 : str += msprintf(" + %G", -hp.vars[i].voffset);
9642 :
9643 0 : if (hp.vars[i].factor != 1) {
9644 0 : if (hp.vars[i].voffset == 0)
9645 0 : str += msprintf(" * %+G", hp.vars[i].factor);
9646 : else {
9647 0 : str = msprintf("(%s) * %+G", str.c_str(), hp.vars[i].factor);
9648 : }
9649 : }
9650 :
9651 0 : if (hp.vars[i].offset > 0)
9652 0 : str += msprintf(" + %G", hp.vars[i].offset);
9653 0 : else if (hp.vars[i].offset < 0)
9654 0 : str += msprintf(" - %G", -hp.vars[i].offset);
9655 :
9656 : } else {
9657 0 : str = hp.vars[i].tag_name;
9658 : }
9659 : }
9660 :
9661 0 : int k=0;
9662 0 : for (int j=0; j<hsdata->nvars; j++)
9663 0 : if (hsdata->odb_index[j] == i) {
9664 0 : k = j;
9665 0 : break;
9666 : }
9667 :
9668 : if (/* DISABLES CODE */ (0)) {
9669 : printf("graph %d: odb index %d, n_point %d, num_entries %d, have_last_written %d %d, status %d, var_status [%s]\n", i, k, n_point[i], hsdata->num_entries[k], hsdata->have_last_written, (int)hsdata->last_written[k], hsdata->status[k], var_status[i]);
9670 : }
9671 :
9672 0 : if (hp.show_values) {
9673 : char xstr[256];
9674 0 : if (n_point[i] > 0) {
9675 0 : sprintf(xstr," = %g", y[i][n_point[i]-1]);
9676 0 : } else if (hsdata->num_entries[k] > 0) {
9677 0 : sprintf(xstr," = all data is NaN or INF");
9678 0 : } else if (hsdata->have_last_written) {
9679 0 : if (hsdata->last_written[k]) {
9680 : char ctimebuf[32];
9681 0 : ctime_r(&hsdata->last_written[k], ctimebuf);
9682 0 : sprintf(xstr," = last data %s", ctimebuf);
9683 : // kill trailing '\n'
9684 0 : char*s = strchr(xstr, '\n');
9685 0 : if (s) *s=0;
9686 : // clear the unnecessary error status report
9687 0 : if (hsdata->status[k] == HS_UNDEFINED_VAR)
9688 0 : var_status[i][0] = 0;
9689 : } else {
9690 0 : sprintf(xstr," = no data ever");
9691 : }
9692 : } else {
9693 0 : sprintf(xstr," = no data");
9694 : }
9695 0 : str += xstr;
9696 : }
9697 :
9698 0 : if (strlen(var_status[i]) > 1) {
9699 0 : str += msprintf(" (%s)", var_status[i]);
9700 : }
9701 :
9702 0 : row = index == -1 ? i : 0;
9703 :
9704 0 : gdImageFilledRectangle(im,
9705 : x1 + 10,
9706 0 : y2 + 10 + row * (gdFontMediumBold->h + 10),
9707 0 : x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9708 0 : y2 + 10 + row * (gdFontMediumBold->h + 10) +
9709 0 : gdFontMediumBold->h + 2 + 2, white);
9710 0 : gdImageRectangle(im, x1 + 10, y2 + 10 + row * (gdFontMediumBold->h + 10),
9711 0 : x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9712 0 : y2 + 10 + row * (gdFontMediumBold->h + 10) +
9713 0 : gdFontMediumBold->h + 2 + 2, curve_col[i]);
9714 :
9715 0 : gdImageString(im, gdFontMediumBold,
9716 0 : x1 + 10 + 5, y2 + 10 + 2 + row * (gdFontMediumBold->h + 10),
9717 : (char*)str.c_str(),
9718 : curve_col[i]);
9719 0 : }
9720 : }
9721 :
9722 0 : gdImageRectangle(im, x1, y2, x2, y1, fgcol);
9723 :
9724 0 : error:
9725 :
9726 : /* generate GIF */
9727 0 : gdImageInterlace(im, 1);
9728 0 : gdImageGif(im, &gb);
9729 0 : gdImageDestroy(im);
9730 0 : length = gb.size;
9731 :
9732 0 : if (buffer == NULL) {
9733 0 : rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
9734 0 : rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
9735 :
9736 0 : rr->rsprintf("Content-Type: image/gif\r\n");
9737 0 : rr->rsprintf("Content-Length: %d\r\n", length);
9738 0 : rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
9739 0 : rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
9740 :
9741 0 : rr->rmemcpy(gb.data, length);
9742 : } else {
9743 0 : if (length > *buffer_size) {
9744 0 : printf("return buffer too small\n");
9745 0 : return;
9746 : }
9747 :
9748 0 : memcpy(buffer, gb.data, length);
9749 0 : *buffer_size = length;
9750 : }
9751 0 : }
9752 :
9753 : /*------------------------------------------------------------------*/
9754 :
9755 0 : time_t mktime_with_dst(const struct tm* ptms)
9756 : {
9757 : // this silly stuff is required to correctly handle daylight savings time (Summer time/Winter time)
9758 : // when we fill "struct tm" from user input, we cannot know if daylight savings time is in effect
9759 : // and we do not know how to initialize the value of tms.tm_isdst.
9760 : // This can cause the output of mktime() to be off by one hour.
9761 : // (Rules for daylight savings time are set by national and local govt and in some locations, changes yearly)
9762 : // (There are no locations with 2 hour or half-hour daylight savings that I know of)
9763 : // (Yes, "man mktime" talks about using "tms.tm_isdst = -1")
9764 : //
9765 : // We assume the user is using local time and we convert in two steps:
9766 : //
9767 : // first we convert "struct tm" to "time_t" using mktime() with unknown tm_isdst
9768 : // second we convert "time_t" back to "struct tm" using localtime_r()
9769 : // this fills "tm_isdst" with correct value from the system time zone database
9770 : // then we reset all the time fields (except for sub-minute fields not affected by daylight savings)
9771 : // and call mktime() again, now with the correct value of "tm_isdst".
9772 : // K.O. 2013-09-14
9773 :
9774 0 : struct tm tms = *ptms;
9775 : struct tm tms2;
9776 0 : time_t t1 = ss_mktime(&tms);
9777 0 : localtime_r(&t1, &tms2);
9778 0 : tms2.tm_year = ptms->tm_year;
9779 0 : tms2.tm_mon = ptms->tm_mon;
9780 0 : tms2.tm_mday = ptms->tm_mday;
9781 0 : tms2.tm_hour = ptms->tm_hour;
9782 0 : tms2.tm_min = ptms->tm_min;
9783 0 : time_t t2 = ss_mktime(&tms2);
9784 : //printf("t1 %.0f, t2 %.0f, diff %d\n", (double)t1, (double)t2, (int)(t1-t2));
9785 0 : return t2;
9786 : }
9787 :
9788 : /*------------------------------------------------------------------*/
9789 :
9790 0 : static std::string add_param_to_url(const char* name, const char* value)
9791 : {
9792 0 : std::string s;
9793 0 : s += name; // FIXME: should be URI-encoded
9794 0 : s += "=";
9795 0 : s += value; // FIXME: should be URI-encoded
9796 0 : return s;
9797 0 : }
9798 :
9799 : /*------------------------------------------------------------------*/
9800 :
9801 0 : void show_query_page(Param* p, Return* r)
9802 : {
9803 : int i;
9804 : HNDLE hDB;
9805 :
9806 0 : if (p->getparam("m1") && *p->getparam("m1")) {
9807 : struct tm tms;
9808 0 : memset(&tms, 0, sizeof(struct tm));
9809 :
9810 0 : tms.tm_year = atoi(p->getparam("y1")) % 100;
9811 :
9812 0 : std::string m1 = p->getparam("m1");
9813 0 : for (i = 0; i < 12; i++)
9814 0 : if (equal_ustring(m1.c_str(), mname[i]))
9815 0 : break;
9816 0 : if (i == 12)
9817 0 : i = 0;
9818 :
9819 0 : tms.tm_mon = i;
9820 0 : tms.tm_mday = atoi(p->getparam("d1"));
9821 0 : tms.tm_hour = atoi(p->getparam("h1"));
9822 :
9823 0 : if (tms.tm_year < 90)
9824 0 : tms.tm_year += 100;
9825 :
9826 0 : time_t ltime_start = mktime_with_dst(&tms);
9827 :
9828 0 : memset(&tms, 0, sizeof(struct tm));
9829 0 : tms.tm_year = atoi(p->getparam("y2")) % 100;
9830 :
9831 0 : std::string m2 = p->getparam("m2");
9832 0 : for (i = 0; i < 12; i++)
9833 0 : if (equal_ustring(m2.c_str(), mname[i]))
9834 0 : break;
9835 0 : if (i == 12)
9836 0 : i = 0;
9837 :
9838 0 : tms.tm_mon = i;
9839 0 : tms.tm_mday = atoi(p->getparam("d2"));
9840 0 : tms.tm_hour = atoi(p->getparam("h2"));
9841 :
9842 0 : if (tms.tm_year < 90)
9843 0 : tms.tm_year += 100;
9844 :
9845 0 : time_t ltime_end = mktime_with_dst(&tms);
9846 :
9847 0 : if (ltime_end == ltime_start)
9848 0 : ltime_end += 3600 * 24;
9849 :
9850 0 : std::string redir;
9851 0 : redir += "?cmd=oldhistory&";
9852 0 : redir += add_param_to_url("group", p->getparam("group"));
9853 0 : redir += "&";
9854 0 : redir += add_param_to_url("panel", p->getparam("panel"));
9855 0 : redir += "&";
9856 0 : redir += add_param_to_url("scale", toString((int)(ltime_end - ltime_start)).c_str());
9857 0 : redir += "&";
9858 0 : redir += add_param_to_url("time", time_to_string(ltime_end).c_str());
9859 0 : if (p->isparam("hindex")) {
9860 0 : redir += "&";
9861 0 : redir += add_param_to_url("index", p->getparam("hindex"));
9862 : }
9863 0 : redirect(r, redir.c_str());
9864 0 : return;
9865 0 : }
9866 :
9867 0 : cm_get_experiment_database(&hDB, NULL);
9868 0 : show_header(r, "History", "GET", "", 0);
9869 :
9870 : /* set the times */
9871 :
9872 0 : time_t now = time(NULL);
9873 :
9874 0 : time_t starttime = now - 3600 * 24;
9875 0 : time_t endtime = now;
9876 0 : bool full_day = true;
9877 :
9878 0 : if (p->isparam("htime")) {
9879 0 : endtime = string_to_time(p->getparam("htime"));
9880 :
9881 0 : if (p->isparam("hscale")) {
9882 0 : starttime = endtime - atoi(p->getparam("hscale"));
9883 0 : full_day = false;
9884 : } else {
9885 0 : starttime = endtime - 3600 * 24;
9886 0 : full_day = false;
9887 : }
9888 : }
9889 :
9890 : /* menu buttons */
9891 0 : r->rsprintf("<tr><td colspan=2>\n");
9892 0 : r->rsprintf("<input type=hidden name=cmd value=OldHistory>\n");
9893 0 : r->rsprintf("<input type=submit name=hcmd value=Query>\n");
9894 0 : r->rsprintf("<input type=submit name=hcmd value=Cancel>\n");
9895 0 : if (p->isparam("group"))
9896 0 : r->rsprintf("<input type=hidden name=group value=\"%s\">\n", p->getparam("group"));
9897 0 : if (p->isparam("panel"))
9898 0 : r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", p->getparam("panel"));
9899 0 : if (p->isparam("htime"))
9900 0 : r->rsprintf("<input type=hidden name=htime value=\"%s\">\n", p->getparam("htime"));
9901 0 : if (p->isparam("hscale"))
9902 0 : r->rsprintf("<input type=hidden name=hscale value=\"%s\">\n", p->getparam("hscale"));
9903 0 : if (p->isparam("hindex"))
9904 0 : r->rsprintf("<input type=hidden name=hindex value=\"%s\">\n", p->getparam("hindex"));
9905 0 : r->rsprintf("</tr>\n\n");
9906 0 : r->rsprintf("</table>"); //end header
9907 :
9908 0 : r->rsprintf("<table class=\"dialogTable\">"); //main table
9909 :
9910 : struct tm tms;
9911 0 : localtime_r(&starttime, &tms);
9912 0 : tms.tm_year += 1900;
9913 :
9914 0 : r->rsprintf("<tr><td nowrap>Start date:</td>");
9915 :
9916 0 : r->rsprintf("<td>Month: <select name=\"m1\">\n");
9917 0 : r->rsprintf("<option value=\"\">\n");
9918 0 : for (i = 0; i < 12; i++)
9919 0 : if (i == tms.tm_mon)
9920 0 : r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9921 : else
9922 0 : r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9923 0 : r->rsprintf("</select>\n");
9924 :
9925 0 : r->rsprintf(" Day: <select name=\"d1\">");
9926 0 : r->rsprintf("<option selected value=\"\">\n");
9927 0 : for (i = 0; i < 31; i++)
9928 0 : if (i + 1 == tms.tm_mday)
9929 0 : r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9930 : else
9931 0 : r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9932 0 : r->rsprintf("</select>\n");
9933 :
9934 0 : int start_hour = tms.tm_hour;
9935 0 : if (full_day)
9936 0 : start_hour = 0;
9937 :
9938 0 : r->rsprintf(" Hour: <input type=\"text\" size=5 maxlength=5 name=\"h1\" value=\"%d\">", start_hour);
9939 :
9940 0 : r->rsprintf(" Year: <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">", tms.tm_year);
9941 0 : r->rsprintf("</td></tr>\n");
9942 :
9943 0 : r->rsprintf("<tr><td nowrap>End date:</td>");
9944 :
9945 0 : localtime_r(&endtime, &tms);
9946 0 : tms.tm_year += 1900;
9947 :
9948 0 : r->rsprintf("<td>Month: <select name=\"m2\">\n");
9949 0 : r->rsprintf("<option value=\"\">\n");
9950 0 : for (i = 0; i < 12; i++)
9951 0 : if (i == tms.tm_mon)
9952 0 : r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9953 : else
9954 0 : r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9955 0 : r->rsprintf("</select>\n");
9956 :
9957 0 : r->rsprintf(" Day: <select name=\"d2\">");
9958 0 : r->rsprintf("<option selected value=\"\">\n");
9959 0 : for (i = 0; i < 31; i++)
9960 0 : if (i + 1 == tms.tm_mday)
9961 0 : r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9962 : else
9963 0 : r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9964 0 : r->rsprintf("</select>\n");
9965 :
9966 0 : int end_hour = tms.tm_hour;
9967 0 : if (full_day)
9968 0 : end_hour = 24;
9969 :
9970 0 : r->rsprintf(" Hour: <input type=\"text\" size=5 maxlength=5 name=\"h2\" value=\"%d\">", end_hour);
9971 :
9972 0 : r->rsprintf(" Year: <input type=\"text\" size=5 maxlength=5 name=\"y2\" value=\"%d\">", tms.tm_year);
9973 0 : r->rsprintf("</td></tr>\n");
9974 :
9975 0 : r->rsprintf("</table>\n");
9976 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
9977 0 : r->rsprintf("</form>\n");
9978 0 : r->rsprintf("</body></html>\r\n");
9979 : }
9980 :
9981 : /*------------------------------------------------------------------*/
9982 : /* history plot code starts here */
9983 : /*------------------------------------------------------------------*/
9984 :
9985 0 : static int cmp_names(const void *a, const void *b)
9986 : {
9987 : int i;
9988 0 : const char*sa = (const char*)a;
9989 0 : const char*sb = (const char*)b;
9990 :
9991 0 : int debug = 0;
9992 :
9993 : // Cannot use strcmp() because it does not know how to compare numerical values, e.g.
9994 : // it thinks "111" is smaller than "9"
9995 : //return strcmp(sa, sb);
9996 :
9997 0 : if (debug)
9998 0 : printf("compare [%s] and [%s]\n", sa, sb);
9999 :
10000 0 : for (i=0; ; i++) {
10001 0 : if (sa[i]==0 && sb[i]==0)
10002 0 : return 0; // both strings have the same length and the same characters
10003 :
10004 : //printf("index %d, char [%c] [%c], isdigit %d %d\n", i, sa[i], sb[i], isdigit(sa[i]), isdigit(sb[i]));
10005 :
10006 0 : if (isdigit(sa[i]) && isdigit(sb[i])) {
10007 0 : int va = atoi(sa+i);
10008 0 : int vb = atoi(sb+i);
10009 :
10010 0 : if (debug)
10011 0 : printf("index %d, values %d %d\n", i, va, vb);
10012 :
10013 0 : if (va < vb)
10014 0 : return -1;
10015 0 : else if (va > vb)
10016 0 : return 1;
10017 :
10018 : // values are equal, skip the the end of the digits, compare any trailing text
10019 0 : continue;
10020 0 : }
10021 :
10022 0 : if (sa[i]==sb[i]) {
10023 0 : continue;
10024 : }
10025 :
10026 0 : if (debug)
10027 0 : printf("index %d, char [%c] [%c]\n", i, sa[i], sb[i]);
10028 :
10029 0 : if (sa[i] == 0) // string sa is shorter
10030 0 : return -1;
10031 0 : else if (sb[i] == 0) // string sb is shorter
10032 0 : return 1;
10033 :
10034 0 : if (sa[i]<sb[i])
10035 0 : return -1;
10036 : else
10037 0 : return 1;
10038 0 : }
10039 :
10040 : // NOT REACHED
10041 : }
10042 :
10043 0 : const bool cmp_events(const std::string& a, const std::string& b)
10044 : {
10045 0 : return cmp_names(a.c_str(), b.c_str()) < 0;
10046 : }
10047 :
10048 0 : const bool cmp_events1(const std::string& a, const std::string& b)
10049 : {
10050 0 : return a < b;
10051 : }
10052 :
10053 0 : const bool cmp_tags(const TAG& a, const TAG& b)
10054 : {
10055 0 : return cmp_names(a.name, b.name) < 0;
10056 : }
10057 :
10058 : #if 0
10059 : static int cmp_tags(const void *a, const void *b)
10060 : {
10061 : const TAG*sa = (const TAG*)a;
10062 : const TAG*sb = (const TAG*)b;
10063 : return cmp_names(sa->name, sb->name);
10064 : }
10065 :
10066 : static void sort_tags(int ntags, TAG* tags)
10067 : {
10068 : qsort(tags, ntags, sizeof(TAG), cmp_tags);
10069 : }
10070 : #endif
10071 :
10072 0 : int xdb_get_data_index(HNDLE hDB, const char* str, void *value, int size, int index, int tid)
10073 : {
10074 : HNDLE hKey;
10075 0 : int status = db_find_key(hDB, 0, str, &hKey);
10076 0 : if (status != DB_SUCCESS)
10077 0 : return status;
10078 :
10079 : KEY key;
10080 0 : db_get_key(hDB, hKey, &key);
10081 0 : if (index >= key.num_values)
10082 0 : return DB_OUT_OF_RANGE;
10083 :
10084 0 : status = db_get_data_index(hDB, hKey, value, &size, index, tid);
10085 0 : return status;
10086 : }
10087 :
10088 0 : static int xdb_find_key(HNDLE hDB, HNDLE dir, const char* str, HNDLE* hKey, int tid, int size)
10089 : {
10090 0 : int status = db_find_key(hDB, dir, str, hKey);
10091 0 : if (status == DB_SUCCESS)
10092 0 : return status;
10093 :
10094 0 : db_create_key(hDB, dir, str, tid);
10095 0 : status = db_find_key(hDB, dir, str, hKey);
10096 0 : if (status != DB_SUCCESS || !*hKey) {
10097 0 : cm_msg(MERROR, "xdb_find_key", "Invalid ODB path \"%s\"", str);
10098 0 : str = "bad_xdb_find_key";
10099 0 : db_create_key(hDB, dir, str, tid);
10100 0 : db_find_key(hDB, dir, str, hKey);
10101 : }
10102 0 : assert(*hKey);
10103 :
10104 0 : if (tid == TID_STRING) {
10105 0 : db_set_data_index(hDB, *hKey, "", size, 0, TID_STRING);
10106 : }
10107 :
10108 0 : return status;
10109 : }
10110 :
10111 0 : static bool cmp_vars(const HistVar &a, const HistVar &b)
10112 : {
10113 0 : return a.order < b.order;
10114 : }
10115 :
10116 0 : static void PrintHistPlot(const HistPlot& hp)
10117 : {
10118 0 : printf("hist plot: %d variables\n", (int)hp.vars.size());
10119 0 : printf("timescale: %s, minimum: %f, maximum: %f, zero_ylow: %d, log_axis: %d, show_run_markers: %d, show_values: %d, show_fill: %d, show_factor %d, enable_factor: %d\n", hp.timescale.c_str(), hp.minimum, hp.maximum, hp.zero_ylow, hp.log_axis, hp.show_run_markers, hp.show_values, hp.show_fill, hp.show_factor, hp.enable_factor);
10120 :
10121 0 : for (size_t i=0; i<hp.vars.size(); i++) {
10122 0 : printf("var[%d] event [%s][%s] formula [%s], colour [%s] label [%s] show_raw_value %d factor %f offset %f voffset %f order %d\n", (int)i, hp.vars[i].event_name.c_str(), hp.vars[i].tag_name.c_str(), hp.vars[i].formula.c_str(), hp.vars[i].colour.c_str(), hp.vars[i].label.c_str(), hp.vars[i].show_raw_value, hp.vars[i].factor, hp.vars[i].offset , hp.vars[i].voffset, hp.vars[i].order);
10123 : }
10124 0 : }
10125 :
10126 0 : static std::string NextHistPlotColour(const HistPlot& hp)
10127 : {
10128 0 : const char* const colour[] =
10129 : {
10130 : "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
10131 : "#A0C0D0", "#D0A060", "#C04010", "#807060",
10132 : "#F0C000", "#2090A0", "#D040D0", "#90B000",
10133 : "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
10134 : NULL };
10135 :
10136 0 : for (int i=0; colour[i]; i++) {
10137 0 : bool in_use = false;
10138 :
10139 0 : for (size_t j=0; j<hp.vars.size(); j++)
10140 0 : if (hp.vars[j].colour == colour[i]) {
10141 0 : in_use = true;
10142 0 : break;
10143 : }
10144 :
10145 0 : if (!in_use)
10146 0 : return colour[i];
10147 : }
10148 :
10149 0 : return "#808080";
10150 : }
10151 :
10152 0 : static int NextHistPlotOrder(const HistPlot& hp)
10153 : {
10154 0 : int order = 0;
10155 0 : for (size_t i=0; i<hp.vars.size(); i++)
10156 0 : if (hp.vars[i].order > order)
10157 0 : order = hp.vars[i].order;
10158 0 : return order + 10;
10159 : }
10160 :
10161 0 : static void SplitEventAndTagNames(std::string var_name, std::string& event_name, std::string& tag_name) {
10162 0 : event_name = "";
10163 0 : tag_name = "";
10164 :
10165 0 : std::vector<size_t> colons;
10166 :
10167 0 : for (size_t i = 0; i < var_name.size(); i++) {
10168 0 : if (var_name[i] == ':') {
10169 0 : colons.push_back(i);
10170 : }
10171 : }
10172 :
10173 0 : if (colons.size() == 0) {
10174 : // No colons - leave the tag name empty
10175 0 : event_name = var_name;
10176 : } else {
10177 : size_t split_pos;
10178 0 : size_t slash_pos = var_name.find("/");
10179 0 : bool uses_per_variable_naming = (slash_pos != std::string::npos);
10180 :
10181 0 : if (uses_per_variable_naming && colons.size() % 2 == 1) {
10182 0 : size_t middle_colon_pos = colons[colons.size() / 2];
10183 0 : std::string slash_to_mid = var_name.substr(slash_pos + 1, middle_colon_pos - slash_pos - 1);
10184 0 : std::string mid_to_end = var_name.substr(middle_colon_pos + 1);
10185 :
10186 0 : if (slash_to_mid == mid_to_end) {
10187 : // Special case - we have a string of the form Beamlime/GS2:FC1:GS2:FC1.
10188 : // Logger has already warned people that having colons in the equipment/event
10189 : // names is a bad idea, so we only need to worry about them in the tag name.
10190 0 : split_pos = middle_colon_pos;
10191 : } else {
10192 : // We have a string of the form Beamlime/Demand:GS2:FC1. Split at the first colon.
10193 0 : split_pos = colons[0];
10194 : }
10195 0 : } else {
10196 : // Normal case - split at the fist colon.
10197 0 : split_pos = colons[0];
10198 : }
10199 :
10200 0 : event_name = var_name.substr(0, split_pos);
10201 0 : tag_name = var_name.substr(split_pos + 1);
10202 : }
10203 0 : }
10204 :
10205 0 : static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel)
10206 : {
10207 0 : std::string path = "History/Display/";
10208 0 : path += group;
10209 0 : path += "/";
10210 0 : path += panel;
10211 :
10212 0 : MVOdb* o = odb->Chdir(path.c_str());
10213 0 : if (!o) {
10214 0 : return;
10215 : }
10216 :
10217 0 : o->RS("Timescale", &hp->timescale);
10218 0 : o->RD("Minimum", &hp->minimum);
10219 0 : o->RD("Maximum", &hp->maximum);
10220 0 : o->RB("Zero ylow", &hp->zero_ylow);
10221 0 : o->RB("Log axis", &hp->log_axis);
10222 0 : o->RB("Zero ylow", &hp->zero_ylow);
10223 0 : o->RB("Show run markers", &hp->show_run_markers);
10224 0 : o->RB("Show values", &hp->show_values);
10225 0 : o->RB("Show fill", &hp->show_fill);
10226 0 : o->RB("Show factor", &hp->show_factor);
10227 : //o->RB("Enable factor and offset", &hp->enable_factor);
10228 :
10229 0 : std::vector<std::string> hist_vars;
10230 0 : std::vector<std::string> hist_formula;
10231 0 : std::vector<std::string> hist_colour;
10232 0 : std::vector<std::string> hist_label;
10233 0 : std::vector<bool> hist_show_raw_value;
10234 0 : std::vector<double> hist_factor;
10235 0 : std::vector<double> hist_offset;
10236 0 : std::vector<double> hist_voffset;
10237 :
10238 0 : o->RSA("Variables", &hist_vars);
10239 0 : o->RSA("Formula", &hist_formula);
10240 0 : o->RSA("Colour", &hist_colour);
10241 0 : o->RSA("Label", &hist_label);
10242 0 : o->RBA("Show raw value", &hist_show_raw_value);
10243 0 : o->RDA("Factor", &hist_factor);
10244 0 : o->RDA("Offset", &hist_offset);
10245 0 : o->RDA("VOffset", &hist_voffset);
10246 :
10247 : // fix broken plots with "factor" all zero. for reasons
10248 : // unknown the new history code has corrupted many
10249 : // history plot definitions like this. K.O.
10250 : {
10251 0 : bool all_zero = true;
10252 0 : for (size_t i=0; i<hist_factor.size(); i++) {
10253 0 : if (hist_factor[i] != 0)
10254 0 : all_zero = false;
10255 : }
10256 0 : if (all_zero) {
10257 0 : for (size_t i=0; i<hist_factor.size(); i++) {
10258 0 : hist_factor[i] = 1.0;
10259 : }
10260 : }
10261 : }
10262 :
10263 0 : size_t num = std::max(hist_vars.size(), hist_formula.size());
10264 0 : num = std::max(num, hist_colour.size());
10265 0 : num = std::max(num, hist_label.size());
10266 0 : num = std::max(num, hist_show_raw_value.size());
10267 0 : num = std::max(num, hist_factor.size());
10268 0 : num = std::max(num, hist_offset.size());
10269 0 : num = std::max(num, hist_voffset.size());
10270 :
10271 0 : hist_vars.resize(num);
10272 0 : hist_formula.resize(num);
10273 0 : hist_colour.resize(num);
10274 0 : hist_label.resize(num);
10275 0 : hist_show_raw_value.resize(num);
10276 0 : hist_factor.resize(num, 1.0);
10277 0 : hist_offset.resize(num, 0.0);
10278 0 : hist_voffset.resize(num, 0.0);
10279 :
10280 0 : for (size_t i=0; i<num; i++) {
10281 0 : HistVar v;
10282 :
10283 0 : SplitEventAndTagNames(hist_vars[i], v.event_name, v.tag_name);
10284 :
10285 0 : v.formula = hist_formula[i];
10286 0 : v.colour = hist_colour[i];
10287 0 : v.label = hist_label[i];
10288 0 : v.show_raw_value = hist_show_raw_value[i];
10289 0 : v.factor = hist_factor[i];
10290 0 : v.offset = hist_offset[i];
10291 0 : v.voffset = hist_voffset[i];
10292 0 : v.order = NextHistPlotOrder(*hp);
10293 :
10294 : // one-time migration of factor and offset to formula
10295 0 : if (hp->enable_factor && v.formula.empty()) {
10296 0 : if (v.factor!=1 || v.offset!=0 || v.voffset!=0) {
10297 0 : v.formula = msprintf("%g%+g*(x%+g)", v.offset, v.factor, -v.voffset);
10298 : }
10299 : }
10300 :
10301 0 : hp->vars.push_back(v);
10302 0 : }
10303 :
10304 : // printf("Load from ODB %s: ", path.c_str());
10305 : // PrintHistPlot(*hp);
10306 :
10307 0 : delete o;
10308 0 : }
10309 :
10310 0 : static void LoadHistPlotFromParam(HistPlot* hp, Param* p)
10311 : {
10312 0 : hp->timescale = p->getparam("timescale");
10313 0 : hp->minimum = strtod(p->getparam("minimum"), NULL);
10314 0 : hp->maximum = strtod(p->getparam("maximum"), NULL);
10315 0 : hp->zero_ylow = *p->getparam("zero_ylow");
10316 0 : hp->log_axis = *p->getparam("log_axis");
10317 0 : hp->show_run_markers = *p->getparam("run_markers");
10318 0 : hp->show_values = *p->getparam("show_values");
10319 0 : hp->show_fill = *p->getparam("show_fill");
10320 0 : hp->show_factor = *p->getparam("show_factor");
10321 : //hp->enable_factor = *p->getparam("enable_factor");
10322 :
10323 0 : for (int index=0; ; index++) {
10324 : char str[256];
10325 0 : sprintf(str, "event%d", index);
10326 :
10327 : //printf("param event %d: [%s] [%s] [%d]\n", index, str, p->getparam(str), *p->getparam(str));
10328 :
10329 0 : if (!p->isparam(str))
10330 0 : break;
10331 :
10332 0 : if (*p->getparam(str) == '/') // "/empty"
10333 0 : continue;
10334 :
10335 0 : HistVar v;
10336 :
10337 0 : v.event_name = p->xgetparam(str);
10338 :
10339 0 : sprintf(str, "var%d", index);
10340 0 : v.tag_name = p->xgetparam(str);
10341 :
10342 0 : sprintf(str, "form%d", index);
10343 0 : v.formula = p->xgetparam(str);
10344 :
10345 0 : sprintf(str, "col%d", index);
10346 0 : v.colour = p->xgetparam(str);
10347 :
10348 0 : sprintf(str, "lab%d", index);
10349 0 : v.label = p->xgetparam(str);
10350 :
10351 0 : sprintf(str, "raw%d", index);
10352 0 : v.show_raw_value = atoi(p->xgetparam(str).c_str());
10353 :
10354 0 : sprintf(str, "factor%d", index);
10355 0 : if (p->isparam(str)) {
10356 0 : v.factor = atof(p->xgetparam(str).c_str());
10357 : } else {
10358 0 : v.factor = 1.0;
10359 : }
10360 :
10361 0 : sprintf(str, "offset%d", index);
10362 0 : v.offset = atof(p->xgetparam(str).c_str());
10363 :
10364 0 : sprintf(str, "voffset%d", index);
10365 0 : v.voffset = atof(p->xgetparam(str).c_str());
10366 :
10367 0 : sprintf(str, "ord%d", index);
10368 0 : if (p->isparam(str)) {
10369 0 : v.order = atoi(p->xgetparam(str).c_str());
10370 : } else {
10371 0 : v.order = NextHistPlotOrder(*hp);
10372 : }
10373 :
10374 0 : hp->vars.push_back(v);
10375 0 : }
10376 :
10377 : /* correctly number newly added variables */
10378 0 : for (size_t index=0; index<hp->vars.size(); index++) {
10379 0 : if (hp->vars[index].order < 0)
10380 0 : hp->vars[index].order = NextHistPlotOrder(*hp);
10381 : }
10382 :
10383 : // printf("Load from param:\n");
10384 : // PrintHistPlot(*hp);
10385 0 : }
10386 :
10387 0 : static void AddHistPlotSelectedParam(HistPlot& hp, Param* p)
10388 : {
10389 0 : int seln = atoi(p->getparam("seln"));
10390 0 : for (int i=0; i<seln; i++) {
10391 : char str[256];
10392 0 : sprintf(str, "sel%d", i);
10393 :
10394 0 : std::string par = p->getparam(str);
10395 0 : if (par.length() < 1)
10396 0 : continue;
10397 :
10398 0 : std::string event_name, tag_name;
10399 0 : SplitEventAndTagNames(par, event_name, tag_name);
10400 :
10401 0 : if (tag_name == "")
10402 0 : continue;
10403 :
10404 0 : HistVar v;
10405 :
10406 0 : v.event_name = event_name;
10407 0 : v.tag_name = tag_name;
10408 0 : v.colour = NextHistPlotColour(hp);
10409 0 : v.order = NextHistPlotOrder(hp);
10410 :
10411 0 : hp.vars.push_back(v);
10412 0 : }
10413 0 : }
10414 :
10415 0 : static void SaveHistPlotToOdb(MVOdb* odb, const HistPlot& hp, const char* group, const char* panel)
10416 : {
10417 0 : if (strlen(group) < 1) {
10418 0 : cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid group name", group, panel);
10419 0 : return;
10420 : }
10421 :
10422 0 : if (strlen(panel) < 1) {
10423 0 : cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid panel name", group, panel);
10424 0 : return;
10425 : }
10426 :
10427 0 : std::string path = "History/Display/";
10428 0 : path += group;
10429 0 : path += "/";
10430 0 : path += panel;
10431 :
10432 : // printf("Save to ODB %s: ", path.c_str());
10433 : // PrintHistPlot(hp);
10434 :
10435 0 : MVOdb* o = odb->Chdir(path.c_str(), true);
10436 :
10437 0 : o->WS("Timescale", hp.timescale.c_str());
10438 0 : o->WD("Minimum", hp.minimum);
10439 0 : o->WD("Maximum", hp.maximum);
10440 0 : o->WB("Zero ylow", hp.zero_ylow);
10441 0 : o->WB("Log axis", hp.log_axis);
10442 0 : o->WB("Show run markers", hp.show_run_markers);
10443 0 : o->WB("Show values", hp.show_values);
10444 0 : o->WB("Show fill", hp.show_fill);
10445 0 : o->WB("Show factor and offset", hp.show_factor);
10446 : //o->WB("Enable factor and offset", hp.enable_factor);
10447 :
10448 0 : std::vector<std::string> hist_vars;
10449 0 : std::vector<std::string> hist_formula;
10450 0 : std::vector<std::string> hist_colour;
10451 0 : std::vector<std::string> hist_label;
10452 0 : std::vector<bool> hist_show_raw_value;
10453 0 : std::vector<double> hist_factor;
10454 0 : std::vector<double> hist_offset;
10455 0 : std::vector<double> hist_voffset;
10456 :
10457 0 : for (size_t i=0; i<hp.vars.size(); i++) {
10458 0 : hist_vars.push_back(hp.vars[i].event_name + ":" + hp.vars[i].tag_name);
10459 0 : hist_formula.push_back(hp.vars[i].formula);
10460 0 : hist_colour.push_back(hp.vars[i].colour);
10461 0 : hist_label.push_back(hp.vars[i].label);
10462 0 : hist_show_raw_value.push_back(hp.vars[i].show_raw_value);
10463 0 : hist_factor.push_back(hp.vars[i].factor);
10464 0 : hist_offset.push_back(hp.vars[i].offset);
10465 0 : hist_voffset.push_back(hp.vars[i].voffset);
10466 : }
10467 :
10468 0 : if (hp.vars.size() > 0) {
10469 0 : o->WSA("Variables", hist_vars, 64);
10470 0 : o->WSA("Formula", hist_formula, 64);
10471 0 : o->WSA("Colour", hist_colour, NAME_LENGTH);
10472 0 : o->WSA("Label", hist_label, NAME_LENGTH);
10473 0 : o->WBA("Show raw value", hist_show_raw_value);
10474 0 : o->WDA("Factor", hist_factor);
10475 0 : o->WDA("Offset", hist_offset);
10476 0 : o->WDA("VOffset", hist_voffset);
10477 : } else {
10478 0 : o->Delete("Variables");
10479 0 : o->Delete("Formula");
10480 0 : o->Delete("Colour");
10481 0 : o->Delete("Label");
10482 0 : o->Delete("Show raw value");
10483 0 : o->Delete("Factor");
10484 0 : o->Delete("Offset");
10485 0 : o->Delete("VOffset");
10486 : }
10487 :
10488 0 : delete o;
10489 0 : }
10490 :
10491 0 : static void DeleteHistPlotDeleted(HistPlot& hp)
10492 : {
10493 : /* delete variables according to "hist_order" */
10494 :
10495 : while (1) {
10496 0 : bool something_deleted = false;
10497 0 : for (unsigned i=0; i<hp.vars.size(); i++) {
10498 0 : if (hp.vars[i].order <= 0) {
10499 0 : hp.vars.erase(hp.vars.begin() + i);
10500 0 : something_deleted = true;
10501 : }
10502 : }
10503 0 : if (!something_deleted)
10504 0 : break;
10505 0 : }
10506 0 : }
10507 :
10508 0 : static void SortHistPlotVars(HistPlot& hp)
10509 : {
10510 : /* sort variables according to "hist_order" */
10511 :
10512 0 : bool need_sort = false;
10513 0 : for (size_t i=1; i<hp.vars.size(); i++) {
10514 0 : if (hp.vars[i-1].order >= hp.vars[i].order) {
10515 0 : need_sort = true;
10516 : }
10517 : }
10518 :
10519 0 : if (need_sort) {
10520 : /* sort variables by order */
10521 0 : std::sort(hp.vars.begin(), hp.vars.end(), cmp_vars);
10522 :
10523 : /* renumber the variables according to the new sorted order */
10524 0 : for (size_t index=0; index<hp.vars.size(); index++)
10525 0 : hp.vars[index].order = (index+1)*10;
10526 : }
10527 0 : }
10528 :
10529 0 : void show_hist_config_page(MVOdb* odb, Param* p, Return* r, const char *hgroup, const char *hpanel)
10530 : {
10531 : int status;
10532 0 : int max_display_events = 20;
10533 0 : int max_display_tags = 200;
10534 : char str[256], hcmd[256];
10535 :
10536 0 : odb->RI("History/MaxDisplayEvents", &max_display_events, true);
10537 0 : odb->RI("History/MaxDisplayTags", &max_display_tags, true);
10538 :
10539 0 : mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
10540 :
10541 0 : if (equal_ustring(hcmd, "Clear history cache")) {
10542 : //printf("clear history cache!\n");
10543 0 : strcpy(hcmd, "Refresh");
10544 0 : MidasHistoryInterface *mh = get_history();
10545 0 : if (mh)
10546 0 : mh->hs_clear_cache();
10547 : }
10548 :
10549 : //printf("cmd [%s]\n", cmd);
10550 : //printf("cmdx [%s]\n", p->getparam("cmdx"));
10551 :
10552 0 : HistPlot hp;
10553 :
10554 0 : if (equal_ustring(hcmd, "refresh") || equal_ustring(hcmd, "save")) {
10555 0 : LoadHistPlotFromParam(&hp, p);
10556 0 : DeleteHistPlotDeleted(hp);
10557 : } else {
10558 0 : LoadHistPlotFromOdb(odb, &hp, hgroup, hpanel);
10559 : }
10560 :
10561 0 : SortHistPlotVars(hp);
10562 :
10563 0 : if (strlen(p->getparam("seln")) > 0)
10564 0 : AddHistPlotSelectedParam(hp, p);
10565 :
10566 : //hp->Print();
10567 :
10568 0 : if (hcmd[0] && equal_ustring(hcmd, "save")) {
10569 0 : SaveHistPlotToOdb(odb, hp, hgroup, hpanel);
10570 :
10571 0 : if (p->getparam("redir") && *p->getparam("redir"))
10572 0 : redirect(r, p->getparam("redir"));
10573 : else {
10574 0 : sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
10575 0 : redirect(r, str);
10576 : }
10577 0 : return;
10578 : }
10579 :
10580 0 : show_header(r, "History Config", "GET", "", 0);
10581 0 : r->rsprintf("</table>"); //close header table
10582 :
10583 0 : r->rsprintf("<table class=\"mtable\">"); //open main table
10584 :
10585 0 : r->rsprintf("<tr><th colspan=11 class=\"subStatusTitle\">History Panel \"%s\" / \"%s\"</th></tr>\n", hgroup, hpanel);
10586 :
10587 : /* menu buttons */
10588 0 : r->rsprintf("<tr><td colspan=11>\n");
10589 :
10590 0 : r->rsprintf("<input type=button value=Refresh ");
10591 0 : r->rsprintf("onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">\n");
10592 :
10593 0 : r->rsprintf("<input type=button value=Save ");
10594 0 : r->rsprintf("onclick=\"document.form1.hcmd.value='Save';document.form1.submit()\">\n");
10595 :
10596 : {
10597 0 : r->rsprintf("<input type=button value=Cancel ");
10598 0 : std::string url = "?cmd=oldhistory&group=";
10599 0 : url += hgroup;
10600 0 : url += "&panel=";
10601 0 : url += hpanel;
10602 0 : url += "&hcmd=Cancel";
10603 0 : if (p->getparam("redir")) {
10604 0 : url += "&redir=";
10605 0 : url += urlEncode(p->getparam("redir"));
10606 : }
10607 0 : r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10608 0 : }
10609 : {
10610 0 : r->rsprintf("<input type=button value=\"Edit in ODB\"");
10611 0 : std::string url = "?cmd=odb&odb_path=";
10612 0 : url += "/History/Display/";
10613 0 : url += urlEncode(hgroup);
10614 0 : url += "/";
10615 0 : url += urlEncode(hpanel);
10616 0 : r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10617 0 : }
10618 : {
10619 0 : r->rsprintf("<input type=button value=\"Edit in new editor\"");
10620 0 : std::string url = "?cmd=hs_edit";
10621 0 : url += "&group=";
10622 0 : url += urlEncode(hgroup);
10623 0 : url += "&panel=";
10624 0 : url += urlEncode(hpanel);
10625 0 : if (p->getparam("redir")) {
10626 0 : url += "&redir=";
10627 0 : url += urlEncode(p->getparam("redir"));
10628 : }
10629 0 : r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10630 0 : }
10631 0 : r->rsprintf("<input type=button value=\"Clear history cache\"");
10632 0 : r->rsprintf("onclick=\"document.form1.hcmd.value='Clear history cache';document.form1.submit()\">\n");
10633 0 : r->rsprintf("<input type=button value=\"Delete panel\"");
10634 0 : r->rsprintf("onclick=\"window.location.search='?cmd=oldhistory&group=%s&panel=%s&hcmd=Delete%%20panel'\">\n", hgroup, hpanel);
10635 0 : r->rsprintf("</td></tr>\n");
10636 :
10637 0 : r->rsprintf("<tr><td colspan=11>\n");
10638 :
10639 : /* sort_vars */
10640 0 : int sort_vars = *p->getparam("sort_vars");
10641 0 : r->rsprintf("<input type=checkbox %s name=sort_vars value=1 onclick=\"this.form.submit();\">Sort variable names", sort_vars?"checked":"");
10642 :
10643 : /* old_vars */
10644 0 : int old_vars = *p->getparam("old_vars");
10645 0 : r->rsprintf(" <input type=checkbox %s name=old_vars value=1 onclick=\"this.form.submit();\">Show deleted and renamed variables", old_vars?"checked":"");
10646 :
10647 0 : if (hp.show_factor)
10648 0 : r->rsprintf(" <input type=checkbox checked name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10649 : else
10650 0 : r->rsprintf(" <input type=checkbox name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10651 0 : r->rsprintf("Show factor and offset\n");
10652 :
10653 : /* hidden command for refresh */
10654 0 : r->rsprintf("<input type=hidden name=cmd value=Oldhistory>\n");
10655 0 : r->rsprintf("<input type=hidden name=hcmd value=Refresh>\n");
10656 0 : r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", hpanel);
10657 0 : r->rsprintf("<input type=hidden name=group value=\"%s\">\n", hgroup);
10658 :
10659 0 : if (p->getparam("redir") && *p->getparam("redir"))
10660 0 : r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", p->getparam("redir"));
10661 :
10662 0 : r->rsprintf("</td></tr>\n");
10663 :
10664 0 : r->rsprintf("<tr><td colspan=4 style='text-align:right'>Time scale (in units 'm', 'h', 'd'):</td>\n");
10665 0 : r->rsprintf("<td colspan=3><input type=text size=12 name=timescale value=%s></td><td colspan=4></td></tr>\n", hp.timescale.c_str());
10666 :
10667 0 : r->rsprintf("<tr><td colspan=4 style='text-align:right'>Minimum (set to '-inf' for autoscale):</td>\n");
10668 0 : r->rsprintf("<td colspan=3><input type=text size=12 name=minimum value=%f></td><td colspan=4></td></tr>\n", hp.minimum);
10669 :
10670 0 : r->rsprintf("<tr><td colspan=4 style='text-align:right'>Maximum (set to 'inf' for autoscale):</td>\n");
10671 0 : r->rsprintf("<td colspan=3><input type=text size=12 name=maximum value=%f></td><td colspan=4></td></tr>\n", hp.maximum);
10672 :
10673 0 : r->rsprintf("<tr><td colspan=11>");
10674 :
10675 0 : if (hp.zero_ylow)
10676 0 : r->rsprintf("<input type=checkbox checked name=zero_ylow value=1>");
10677 : else
10678 0 : r->rsprintf("<input type=checkbox name=zero_ylow value=1>");
10679 0 : r->rsprintf("Zero Y; axis\n");
10680 :
10681 0 : if (hp.log_axis)
10682 0 : r->rsprintf("<input type=checkbox checked name=log_axis value=1>");
10683 : else
10684 0 : r->rsprintf("<input type=checkbox name=log_axis value=1>");
10685 0 : r->rsprintf("Logarithmic Y axis\n");
10686 :
10687 0 : if (hp.show_run_markers)
10688 0 : r->rsprintf(" <input type=checkbox checked name=run_markers value=1>");
10689 : else
10690 0 : r->rsprintf(" <input type=checkbox name=run_markers value=1>");
10691 0 : r->rsprintf("Show run markers\n");
10692 :
10693 0 : if (hp.show_values)
10694 0 : r->rsprintf(" <input type=checkbox checked name=show_values value=1>");
10695 : else
10696 0 : r->rsprintf(" <input type=checkbox name=show_values value=1>");
10697 0 : r->rsprintf("Show values of variables\n");
10698 :
10699 0 : if (hp.show_fill)
10700 0 : r->rsprintf(" <input type=checkbox checked name=show_fill value=1>");
10701 : else
10702 0 : r->rsprintf(" <input type=checkbox name=show_fill value=1>");
10703 0 : r->rsprintf("Show graph fill\n");
10704 :
10705 0 : r->rsprintf("</td></tr>\n");
10706 :
10707 : /*---- events and variables ----*/
10708 :
10709 : /* get display event name */
10710 :
10711 0 : MidasHistoryInterface* mh = get_history();
10712 0 : if (mh == NULL) {
10713 0 : r->rsprintf(str, "History is not configured\n");
10714 0 : return;
10715 : }
10716 :
10717 0 : time_t t = time(NULL);
10718 :
10719 0 : if (old_vars)
10720 0 : t = 0;
10721 :
10722 0 : std::vector<std::string> events;
10723 :
10724 0 : if (!old_vars)
10725 0 : hs_read_event_list(&events);
10726 :
10727 0 : if (events.size() == 0)
10728 0 : mh->hs_get_events(t, &events);
10729 :
10730 : #if 0
10731 : for (unsigned i=0; i<events.size(); i++)
10732 : printf("event %d: \"%s\"\n", i, events[i].c_str());
10733 : #endif
10734 :
10735 : // has to be sorted or equipment name code below would not work
10736 : //std::sort(events.begin(), events.end(), cmp_events);
10737 0 : std::sort(events.begin(), events.end(), cmp_events1);
10738 :
10739 0 : if (strlen(p->getparam("cmdx")) > 0) {
10740 0 : r->rsprintf("<tr><th colspan=8 class=\"subStatusTitle\">List of available history variables</th></tr>\n");
10741 0 : r->rsprintf("<tr><th colspan=1>Sel<th colspan=1>Equipment<th colspan=1>Event<th colspan=1>Variable</tr>\n");
10742 :
10743 0 : std::string cmdx = p->xgetparam("cmdx");
10744 0 : std::string xeqname;
10745 :
10746 0 : int i=0;
10747 0 : for (unsigned e=0; e<events.size(); e++) {
10748 0 : std::string eqname;
10749 0 : eqname = events[e].substr(0, events[e].find("/"));
10750 :
10751 0 : if (eqname.length() < 1)
10752 0 : eqname = events[e];
10753 :
10754 0 : bool once = false;
10755 0 : if (eqname != xeqname)
10756 0 : once = true;
10757 :
10758 0 : std::string qcmd = "Expand " + eqname;
10759 :
10760 : //printf("param [%s] is [%s]\n", qcmd.c_str(), p->getparam(qcmd.c_str()));
10761 :
10762 0 : bool collapsed = true;
10763 :
10764 0 : if (cmdx == qcmd)
10765 0 : collapsed = false;
10766 :
10767 0 : if (strlen(p->getparam(qcmd.c_str())) > 0)
10768 0 : collapsed = false;
10769 :
10770 0 : if (collapsed) {
10771 0 : if (eqname == xeqname)
10772 0 : continue;
10773 :
10774 0 : r->rsprintf("<tr align=left>\n");
10775 0 : r->rsprintf("<td></td>\n");
10776 0 : r->rsprintf("<td>%s</td>\n", eqname.c_str());
10777 0 : r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", qcmd.c_str());
10778 0 : r->rsprintf("<td>%s</td>\n", "");
10779 0 : r->rsprintf("</tr>\n");
10780 0 : xeqname = eqname;
10781 0 : continue;
10782 : }
10783 :
10784 0 : if (once)
10785 0 : r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", qcmd.c_str(), 1);
10786 :
10787 0 : std::string rcmd = "Expand " + events[e];
10788 :
10789 : //printf("param [%s] is [%s]\n", rcmd.c_str(), p->getparam(rcmd.c_str()));
10790 :
10791 0 : collapsed = true;
10792 :
10793 0 : if (cmdx == rcmd)
10794 0 : collapsed = false;
10795 :
10796 0 : if (strlen(p->getparam(rcmd.c_str())) > 0)
10797 0 : collapsed = false;
10798 :
10799 0 : if (collapsed) {
10800 0 : r->rsprintf("<tr align=left>\n");
10801 0 : r->rsprintf("<td></td>\n");
10802 0 : r->rsprintf("<td>%s</td>\n", eqname.c_str());
10803 0 : r->rsprintf("<td>%s</td>\n", events[e].c_str());
10804 0 : r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", rcmd.c_str());
10805 0 : r->rsprintf("</tr>\n");
10806 0 : continue;
10807 : }
10808 :
10809 0 : r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", rcmd.c_str(), 1);
10810 :
10811 0 : xeqname = eqname;
10812 :
10813 0 : std::vector<TAG> tags;
10814 :
10815 0 : status = mh->hs_get_tags(events[e].c_str(), t, &tags);
10816 :
10817 0 : if (status == HS_SUCCESS && tags.size() > 0) {
10818 :
10819 0 : if (sort_vars)
10820 0 : std::sort(tags.begin(), tags.end(), cmp_tags);
10821 :
10822 0 : for (unsigned v=0; v<tags.size(); v++) {
10823 :
10824 0 : for (unsigned j=0; j<tags[v].n_data; j++) {
10825 : char tagname[256];
10826 :
10827 0 : if (tags[v].n_data == 1)
10828 0 : sprintf(tagname, "%s", tags[v].name);
10829 : else
10830 0 : sprintf(tagname, "%s[%d]", tags[v].name, j);
10831 :
10832 0 : bool checked = false;
10833 : #if 0
10834 : for (int index=0; index<MAX_VARS; index++) {
10835 : if (equal_ustring(vars[index].event_name, events[e].c_str()) && equal_ustring(vars[index].var_name, tagname)) {
10836 : checked = true;
10837 : break;
10838 : }
10839 : }
10840 : #endif
10841 :
10842 0 : r->rsprintf("<tr align=left>\n");
10843 0 : r->rsprintf("<td><input type=checkbox %s name=\"sel%d\" value=\"%s:%s\"></td>\n", checked?"checked":"", i++, events[e].c_str(), tagname);
10844 0 : r->rsprintf("<td>%s</td>\n", eqname.c_str());
10845 0 : r->rsprintf("<td>%s</td>\n", events[e].c_str());
10846 0 : r->rsprintf("<td>%s</td>\n", tagname);
10847 0 : r->rsprintf("</tr>\n");
10848 : }
10849 : }
10850 : }
10851 0 : }
10852 :
10853 0 : r->rsprintf("<tr>\n");
10854 0 : r->rsprintf("<td></td>\n");
10855 0 : r->rsprintf("<td>\n");
10856 0 : r->rsprintf("<input type=hidden name=seln value=%d>\n", i);
10857 0 : r->rsprintf("<input type=submit value=\"Add Selected\">\n");
10858 0 : r->rsprintf("</td>\n");
10859 0 : r->rsprintf("</tr>\n");
10860 0 : }
10861 :
10862 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>New history: displayed_value = formula(history_value)</td></tr>\n");
10863 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>Old history: displayed_value = offset + factor*(history_value - voffset)</td></tr>\n");
10864 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>Formula format: \"3*x+4\", \"10*Math.sin(x)\", etc. all javascript math functions can be used</td></tr>\n");
10865 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>To display the raw history value instead of computed formula or offset value, check the \"raw\" checkbox</td></tr>\n");
10866 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>To reorder entries: enter new ordering in the \"order\" column and press \"refresh\"</td></tr>\n");
10867 0 : r->rsprintf("<tr><td colspan=11 style='text-align:left'>To delete entries: enter \"-1\" or leave blank the \"order\" column and press \"refresh\"</td></tr>\n");
10868 :
10869 0 : r->rsprintf("<tr>\n");
10870 0 : r->rsprintf("<th>Col<th>Event<th>Variable<th>Formula<th>Colour<th>Label<th>Raw<th>Order");
10871 0 : if (hp.show_factor) {
10872 0 : r->rsprintf("<th>Factor<th>Offset<th>VOffset");
10873 : }
10874 0 : r->rsprintf("</tr>\n");
10875 :
10876 : //print_vars(vars);
10877 :
10878 0 : size_t nvars = hp.vars.size();
10879 0 : for (size_t index = 0; index <= nvars; index++) {
10880 :
10881 0 : r->rsprintf("<tr>");
10882 :
10883 0 : if (index < nvars) {
10884 0 : if (hp.vars[index].colour.empty())
10885 0 : hp.vars[index].colour = NextHistPlotColour(hp);
10886 0 : r->rsprintf("<td style=\"background-color:%s\"> <td>\n", hp.vars[index].colour.c_str());
10887 : } else {
10888 0 : r->rsprintf("<td> <td>\n");
10889 : }
10890 :
10891 : /* event and variable selection */
10892 :
10893 0 : r->rsprintf("<select name=\"event%d\" size=1 onChange=\"document.form1.submit()\">\n", (int)index);
10894 :
10895 : /* enumerate events */
10896 :
10897 : /* empty option */
10898 0 : r->rsprintf("<option value=\"/empty\"><empty>\n");
10899 :
10900 0 : if (index==nvars) { // last "empty" entry
10901 0 : for (unsigned e=0; e<events.size(); e++) {
10902 0 : const char *p = events[e].c_str();
10903 0 : r->rsprintf("<option value=\"%s\">%s\n", p, p);
10904 : }
10905 0 : } else if ((int)events.size() > max_display_events) { // too many events
10906 0 : r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].event_name.c_str(), hp.vars[index].event_name.c_str());
10907 0 : r->rsprintf("<option>(%d events omitted)\n", (int)events.size());
10908 : } else { // show all events
10909 0 : bool found = false;
10910 0 : for (unsigned e=0; e<events.size(); e++) {
10911 0 : const char *s = "";
10912 0 : const char *p = events[e].c_str();
10913 0 : if (equal_ustring(hp.vars[index].event_name.c_str(), p)) {
10914 0 : s = "selected";
10915 0 : found = true;
10916 : }
10917 0 : r->rsprintf("<option %s value=\"%s\">%s\n", s, p, p);
10918 : }
10919 0 : if (!found) {
10920 0 : const char *p = hp.vars[index].event_name.c_str();
10921 0 : r->rsprintf("<option selected value=\"%s\">%s\n", p, p);
10922 : }
10923 : }
10924 :
10925 0 : r->rsprintf("</select></td>\n");
10926 :
10927 : //if (hp.vars[index].order <= 0)
10928 : // hp.vars[index].order = (index+1)*10;
10929 :
10930 0 : if (index < nvars) {
10931 0 : bool found_tag = false;
10932 0 : std::string selected_tag = hp.vars[index].tag_name;
10933 :
10934 0 : r->rsprintf("<td><select name=\"var%d\">\n", (int)index);
10935 :
10936 0 : std::vector<TAG> tags;
10937 :
10938 0 : status = mh->hs_get_tags(hp.vars[index].event_name.c_str(), t, &tags);
10939 :
10940 0 : if (status == HS_SUCCESS && tags.size() > 0) {
10941 :
10942 : if (/* DISABLES CODE */ (0)) {
10943 : printf("Compare %d\n", cmp_names("AAA", "BBB"));
10944 : printf("Compare %d\n", cmp_names("BBB", "AAA"));
10945 : printf("Compare %d\n", cmp_names("AAA", "AAA"));
10946 : printf("Compare %d\n", cmp_names("A", "AAA"));
10947 : printf("Compare %d\n", cmp_names("A111", "A1"));
10948 : printf("Compare %d\n", cmp_names("A111", "A2"));
10949 : printf("Compare %d\n", cmp_names("A111", "A222"));
10950 : printf("Compare %d\n", cmp_names("A111a", "A111b"));
10951 : }
10952 :
10953 0 : if (sort_vars)
10954 0 : std::sort(tags.begin(), tags.end(), cmp_tags);
10955 :
10956 : if (/* DISABLES CODE */ (0)) {
10957 : printf("Event [%s] %d tags\n", hp.vars[index].event_name.c_str(), (int)tags.size());
10958 :
10959 : for (unsigned v=0; v<tags.size(); v++) {
10960 : printf("tag[%d] [%s]\n", v, tags[v].name);
10961 : }
10962 : }
10963 :
10964 0 : unsigned count_tags = 0;
10965 0 : for (unsigned v=0; v<tags.size(); v++)
10966 0 : count_tags += tags[v].n_data;
10967 :
10968 : //printf("output %d option tags\n", count_tags);
10969 :
10970 0 : if ((int)count_tags < max_display_tags) {
10971 0 : for (unsigned v=0; v<tags.size(); v++) {
10972 :
10973 0 : for (unsigned j=0; j<tags[v].n_data; j++) {
10974 0 : std::string tagname;
10975 :
10976 0 : if (tags[v].n_data == 1)
10977 0 : tagname = tags[v].name;
10978 : else {
10979 : char buf[256];
10980 0 : sprintf(buf, "[%d]", j);
10981 0 : tagname = std::string(tags[v].name) + buf;
10982 : }
10983 :
10984 0 : if (equal_ustring(selected_tag.c_str(), tagname.c_str())) {
10985 0 : r->rsprintf("<option selected value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10986 0 : found_tag = true;
10987 : }
10988 : else
10989 0 : r->rsprintf("<option value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10990 :
10991 : //printf("%d [%s] [%s] [%s][%s] %d\n", (int)index, vars[index].event_name, tagname, vars[index].var_name, selected_var, found_var);
10992 0 : }
10993 : }
10994 : }
10995 : }
10996 :
10997 0 : if (!found_tag)
10998 0 : if (hp.vars[index].tag_name.length() > 0)
10999 0 : r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].tag_name.c_str(), hp.vars[index].tag_name.c_str());
11000 :
11001 0 : r->rsprintf("</select></td>\n");
11002 0 : r->rsprintf("<td><input type=text size=15 maxlength=256 name=\"form%d\" value=%s></td>\n", (int)index, hp.vars[index].formula.c_str());
11003 0 : r->rsprintf("<td><input type=text size=8 maxlength=10 name=\"col%d\" value=%s></td>\n", (int)index, hp.vars[index].colour.c_str());
11004 0 : r->rsprintf("<td><input type=text size=8 maxlength=%d name=\"lab%d\" value=\"%s\"></td>\n", NAME_LENGTH, (int)index, hp.vars[index].label.c_str());
11005 0 : if (hp.vars[index].show_raw_value)
11006 0 : r->rsprintf("<td><input type=checkbox checked name=\"raw%d\" value=1></td>", (int)index);
11007 : else
11008 0 : r->rsprintf("<td><input type=checkbox name=\"raw%d\" value=1></td>", (int)index);
11009 0 : r->rsprintf("<td><input type=text size=3 maxlength=32 name=\"ord%d\" value=\"%d\"></td>\n", (int)index, hp.vars[index].order);
11010 0 : if (hp.show_factor) {
11011 0 : r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"factor%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].factor);
11012 0 : r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"offset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].offset);
11013 0 : r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"voffset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].voffset);
11014 : } else {
11015 0 : r->rsprintf("<input type=hidden name=\"factor%d\" value=\"%f\">\n", (int)index, hp.vars[index].factor);
11016 0 : r->rsprintf("<input type=hidden name=\"offset%d\" value=\"%f\">\n", (int)index, hp.vars[index].offset);
11017 0 : r->rsprintf("<input type=hidden name=\"voffset%d\" value=\"%f\">\n", (int)index, hp.vars[index].voffset);
11018 : }
11019 0 : } else {
11020 0 : r->rsprintf("<td colspan=2><input type=submit name=cmdx value=\"List all variables\"></td>\n");
11021 : }
11022 :
11023 0 : r->rsprintf("</tr>\n");
11024 : }
11025 :
11026 0 : r->rsprintf("</table>\n");
11027 : //r->rsprintf("</form>\n");
11028 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
11029 0 : r->rsprintf("</form>\n");
11030 0 : r->rsprintf("</body></html>\r\n");
11031 0 : }
11032 :
11033 : /*------------------------------------------------------------------*/
11034 :
11035 0 : void export_hist(MVOdb* odb, Return* r, const char *group, const char *panel, time_t endtime, int scale, int index, int labels)
11036 : {
11037 : //HNDLE hDB, hkey, hkeypanel;
11038 : //int size;
11039 : int status;
11040 : //char str[256];
11041 :
11042 0 : int debug = 0;
11043 :
11044 0 : ss_tzset(); // required for localtime_r()
11045 :
11046 : #if 0
11047 : cm_get_experiment_database(&hDB, NULL);
11048 :
11049 : /* check panel name in ODB */
11050 : sprintf(str, "/History/Display/%s/%s", group, panel);
11051 : db_find_key(hDB, 0, str, &hkeypanel);
11052 : if (!hkeypanel) {
11053 : sprintf(str, "Cannot find /History/Display/%s/%s in ODB\n", group, panel);
11054 : show_error(r, str);
11055 : return;
11056 : }
11057 :
11058 : /* get runmarker flag */
11059 : BOOL runmarker = 1;
11060 : size = sizeof(runmarker);
11061 : db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
11062 :
11063 : if (scale == 0) {
11064 : /* get timescale */
11065 : std::string ts = "1h";
11066 : status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11067 : if (status != DB_SUCCESS) {
11068 : /* delete old integer key */
11069 : db_find_key(hDB, hkeypanel, "Timescale", &hkey);
11070 : if (hkey)
11071 : db_delete_key(hDB, hkey, FALSE);
11072 :
11073 : ts = "1h";
11074 : status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11075 : }
11076 :
11077 : scale = time_to_sec(ts.c_str());
11078 : }
11079 : #endif
11080 :
11081 0 : time_t now = ss_time();
11082 :
11083 0 : if (endtime == 0)
11084 0 : endtime = now;
11085 :
11086 0 : HistoryData hsxxx;
11087 0 : HistoryData* hsdata = &hsxxx;
11088 :
11089 0 : HistPlot hp;
11090 0 : LoadHistPlotFromOdb(odb, &hp, group, panel);
11091 :
11092 0 : time_t starttime = endtime - scale;
11093 :
11094 : //printf("start %.0f, end %.0f, scale %.0f\n", (double)starttime, (double)endtime, (double)scale);
11095 :
11096 0 : status = read_history(hp, /*hDB, group, panel,*/ index, hp.show_run_markers, starttime, endtime, 0, hsdata);
11097 0 : if (status != HS_SUCCESS) {
11098 : char str[256];
11099 0 : sprintf(str, "History error, status %d\n", status);
11100 0 : show_error(r, str);
11101 0 : return;
11102 : }
11103 :
11104 0 : if (debug)
11105 0 : hsdata->Print();
11106 :
11107 0 : int *i_var = (int *)malloc(sizeof(int)*hsdata->nvars);
11108 :
11109 0 : assert(i_var != NULL);
11110 :
11111 0 : for (int i = 0; i < hsdata->nvars; i++)
11112 0 : i_var[i] = -1;
11113 :
11114 0 : time_t t = 0;
11115 :
11116 : /* find first time where all variables are available */
11117 0 : for (int i = 0; i < hsdata->nvars; i++)
11118 0 : if (hsdata->odb_index[i] >= 0)
11119 0 : if (hsdata->num_entries[i] > 0)
11120 0 : if ((t == 0) || (hsdata->t[i][0] > t))
11121 0 : t = hsdata->t[i][0];
11122 :
11123 0 : if (t == 0 && hsdata->nvars > 1) {
11124 0 : show_error(r, "No history available for choosen period");
11125 0 : free(i_var);
11126 0 : return;
11127 : }
11128 :
11129 0 : int run_index = -1;
11130 0 : int state_index = -1;
11131 0 : int n_run_number = 0;
11132 0 : time_t* t_run_number = NULL;
11133 0 : if (hp.show_run_markers)
11134 0 : for (int i = 0; i < hsdata->nvars; i++) {
11135 0 : if (hsdata->odb_index[i] == -2) {
11136 0 : n_run_number = hsdata->num_entries[i];
11137 0 : t_run_number = hsdata->t[i];
11138 0 : run_index = i;
11139 0 : } else if (hsdata->odb_index[i] == -1) {
11140 0 : state_index = i;
11141 : }
11142 : }
11143 :
11144 : //printf("runmarker %d, state %d, run %d\n", runmarker, state_index, run_index);
11145 :
11146 : /* header */
11147 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
11148 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
11149 0 : r->rsprintf("Accept-Ranges: bytes\r\n");
11150 0 : r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
11151 0 : r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
11152 0 : r->rsprintf("Content-Type: text/plain\r\n");
11153 0 : r->rsprintf("Content-disposition: attachment; filename=\"export.csv\"\r\n");
11154 0 : r->rsprintf("\r\n");
11155 :
11156 : /* output header line with variable names */
11157 0 : if (hp.show_run_markers && t_run_number)
11158 0 : r->rsprintf("Time, Timestamp, Run, Run State, ");
11159 : else
11160 0 : r->rsprintf("Time, Timestamp, ");
11161 :
11162 0 : for (int i = 0, first = 1; i < hsdata->nvars; i++) {
11163 0 : if (hsdata->odb_index[i] < 0)
11164 0 : continue;
11165 0 : if (hsdata->num_entries[i] <= 0)
11166 0 : continue;
11167 0 : if (!first)
11168 0 : r->rsprintf(", ");
11169 0 : first = 0;
11170 0 : r->rsprintf("%s", hsdata->var_names[i]);
11171 : }
11172 0 : r->rsprintf("\n");
11173 :
11174 0 : int i_run = 0;
11175 :
11176 : do {
11177 :
11178 0 : if (debug)
11179 0 : printf("hsdata %p, t %d, irun %d\n", hsdata, (int)t, i_run);
11180 :
11181 : /* find run number/state which is valid for t */
11182 0 : if (hp.show_run_markers && t_run_number)
11183 0 : while (i_run < n_run_number-1 && t_run_number[i_run+1] <= t)
11184 0 : i_run++;
11185 :
11186 : //printf("irun %d\n", i_run);
11187 :
11188 : /* find index for all variables which is valid for t */
11189 0 : for (int i = 0; i < hsdata->nvars; i++)
11190 0 : while (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i] - 1 && hsdata->t[i][i_var[i]+1] <= t)
11191 0 : i_var[i]++;
11192 :
11193 : /* finish if last point for all variables reached */
11194 0 : bool done = true;
11195 0 : for (int i = 0 ; i < hsdata->nvars ; i++)
11196 0 : if (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i]) {
11197 0 : done = false;
11198 0 : break;
11199 : }
11200 :
11201 0 : if (debug) {
11202 0 : printf("step to time %d: ", (int)t);
11203 0 : for (int i = 0; i < hsdata->nvars; i++) {
11204 0 : printf(" [%d] %d, ", hsdata->num_entries[i], i_var[i]);
11205 : }
11206 0 : printf(" done: %d\n", done);
11207 : }
11208 :
11209 0 : if (done)
11210 0 : break;
11211 :
11212 : struct tm tms;
11213 0 : localtime_r(&t, &tms);
11214 :
11215 : char fmt[256];
11216 : //strcpy(fmt, "%c");
11217 0 : strcpy(fmt, "%Y.%m.%d %H:%M:%S");
11218 : char str[256];
11219 0 : strftime(str, sizeof(str), fmt, &tms);
11220 :
11221 0 : if (t_run_number && run_index>=0 && state_index>=0) {
11222 0 : if (t_run_number[i_run] <= t)
11223 0 : r->rsprintf("%s, %d, %.0f, %.0f, ", str, (int)t, hsdata->v[run_index][i_run], hsdata->v[state_index][i_run]);
11224 : else
11225 0 : r->rsprintf("%s, %d, N/A, N/A, ", str, (int)t);
11226 : } else
11227 0 : r->rsprintf("%s, %d, ", str, (int)t);
11228 :
11229 0 : if (debug) {
11230 0 : for (int i= 0 ; i < hsdata->nvars ; i++)
11231 0 : printf(" %d (%g)", i_var[i], hsdata->v[i][i_var[i]]);
11232 0 : printf("\n");
11233 : }
11234 :
11235 0 : for (int i=0, first=1 ; i<hsdata->nvars ; i++) {
11236 0 : if (i_var[i] < 0)
11237 0 : continue;
11238 0 : if (hsdata->odb_index[i] < 0)
11239 0 : continue;
11240 0 : if (!first)
11241 0 : r->rsprintf(", ");
11242 0 : first = 0;
11243 : //r->rsprintf("(%d %g)", i_var[i], hsdata->v[i][i_var[i]]);
11244 0 : r->rsprintf("%g", hsdata->v[i][i_var[i]]);
11245 : }
11246 0 : r->rsprintf("\n");
11247 :
11248 : /* find next t as smallest delta t */
11249 0 : int dt = -1;
11250 0 : for (int i = 0 ; i < hsdata->nvars ; i++)
11251 0 : if (i_var[i]>=0 && hsdata->odb_index[i]>=0 && hsdata->num_entries[i]>0 && i_var[i]<hsdata->num_entries[i]-1) {
11252 0 : int xdt = hsdata->t[i][i_var[i]+1] - t;
11253 0 : if (debug)
11254 0 : printf("var %d, i_var %d->%d, t %d->%d, dt %d\n", i, i_var[i], i_var[i]+1, (int)hsdata->t[i][i_var[i]], (int)hsdata->t[i][i_var[i]+1], xdt);
11255 0 : if (dt <= 0 || xdt < dt)
11256 0 : dt = xdt;
11257 : }
11258 :
11259 0 : if (debug)
11260 0 : printf("dt %d\n", dt);
11261 :
11262 0 : if (dt <= 0)
11263 0 : break;
11264 :
11265 0 : t += dt;
11266 :
11267 0 : } while (1);
11268 :
11269 0 : free(i_var);
11270 0 : }
11271 :
11272 : /*------------------------------------------------------------------*/
11273 :
11274 0 : void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
11275 : {
11276 : HNDLE hDB, hkey, hikeyp, hkeyp, hkeybutton;
11277 : KEY key, ikey;
11278 : int i, j, k, scale, index, width, size, status, labels;
11279 : char hgroup[256], hpanel[256], hcmd[256];
11280 0 : const char def_button[][NAME_LENGTH] = { "10m", "1h", "3h", "12h", "24h", "3d", "7d" };
11281 :
11282 0 : cm_get_experiment_database(&hDB, NULL);
11283 :
11284 0 : hcmd[0] = hgroup[0] = hpanel[0] = 0;
11285 :
11286 0 : if (p->getparam("group") && *p->getparam("group"))
11287 0 : mstrlcpy(hgroup, p->getparam("group"), sizeof(hgroup));
11288 0 : if (p->getparam("panel") && *p->getparam("panel"))
11289 0 : mstrlcpy(hpanel, p->getparam("panel"), sizeof(hpanel));
11290 0 : if (p->getparam("hcmd") && *p->getparam("hcmd"))
11291 0 : mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
11292 :
11293 0 : if (equal_ustring(hcmd, "Reset")) {
11294 0 : std::string redir;
11295 : //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11296 0 : redir += "?cmd=oldhistory&group=";
11297 0 : redir += hgroup;
11298 0 : redir += "&panel=";
11299 0 : redir += hpanel;
11300 0 : redirect(r, redir.c_str());
11301 0 : return;
11302 0 : }
11303 :
11304 0 : if (equal_ustring(hcmd, "Query")) {
11305 0 : show_query_page(p, r);
11306 0 : return;
11307 : }
11308 :
11309 0 : if (equal_ustring(hcmd, "Cancel")) {
11310 : //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11311 0 : if (p->getparam("redir") && *p->getparam("redir"))
11312 0 : redirect(r, p->getparam("redir"));
11313 : else {
11314 0 : std::string redir;
11315 0 : redir += "?cmd=oldhistory&group=";
11316 0 : redir += hgroup;
11317 0 : redir += "&panel=";
11318 0 : redir += hpanel;
11319 0 : redirect(r, redir.c_str());
11320 0 : }
11321 0 : return;
11322 : }
11323 :
11324 0 : if (equal_ustring(hcmd, "Config") ||
11325 0 : equal_ustring(hcmd, "Save")
11326 0 : || equal_ustring(hcmd, "Clear history cache")
11327 0 : || equal_ustring(hcmd, "Refresh")) {
11328 :
11329 0 : show_hist_config_page(odb, p, r, hgroup, hpanel);
11330 0 : return;
11331 : }
11332 :
11333 0 : if (equal_ustring(hcmd, "New")) {
11334 0 : show_header(r, "History", "GET", "", 0);
11335 :
11336 0 : r->rsprintf("<table class=\"dialogTable\">");
11337 0 : r->rsprintf("<tr><th class=\"subStatusTitle\" colspan=2>New History Item</th><tr>");
11338 0 : r->rsprintf("<tr><td align=center colspan=2>\n");
11339 0 : r->rsprintf("Select group: ");
11340 0 : r->rsprintf("<select id=\"group\" name=\"group\">\n");
11341 :
11342 : /* list existing groups */
11343 0 : db_find_key(hDB, 0, "/History/Display", &hkey);
11344 0 : i = 0;
11345 0 : if (hkey) {
11346 0 : for (i = 0;; i++) {
11347 0 : db_enum_link(hDB, hkey, i, &hkeyp);
11348 :
11349 0 : if (!hkeyp)
11350 0 : break;
11351 :
11352 0 : db_get_key(hDB, hkeyp, &key);
11353 0 : if (equal_ustring(hgroup, key.name))
11354 0 : r->rsprintf("<option selected>%s</option>\n", key.name);
11355 : else
11356 0 : r->rsprintf("<option>%s</option>\n", key.name);
11357 : }
11358 : }
11359 0 : if (!hkey || i == 0)
11360 0 : r->rsprintf("<option>Default</option>\n");
11361 0 : r->rsprintf("</select><p>\n");
11362 :
11363 0 : r->rsprintf("Or enter new group name: ");
11364 0 : r->rsprintf("<input type=text size=15 maxlength=31 id=new_group name=new_group>\n");
11365 :
11366 0 : r->rsprintf("<tr><td align=center colspan=2>\n");
11367 0 : r->rsprintf("<br>Panel name: ");
11368 0 : r->rsprintf("<input type=text size=15 maxlength=31 id=panel name=panel><br><br>\n");
11369 0 : r->rsprintf("</td></tr>\n");
11370 :
11371 0 : r->rsprintf("<tr><td align=center colspan=2>");
11372 0 : std::string str = "?cmd=oldhistory&hcmd=createnew";
11373 0 : str += "&new_group='+document.getElementById('new_group').value+'";
11374 0 : str += "&group='+document.getElementById('group').value+'";
11375 0 : str += "&panel='+document.getElementById('panel').value+'";
11376 0 : r->rsprintf("<input type=button value=Submit onclick=\"window.location.search='%s'\">\n", str.c_str());
11377 0 : r->rsprintf("</td></tr>\n");
11378 :
11379 0 : r->rsprintf("</table>\r\n");
11380 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
11381 0 : r->rsprintf("</form>\n");
11382 0 : r->rsprintf("</body></html>\r\n");
11383 0 : return;
11384 0 : }
11385 :
11386 0 : if (equal_ustring(hcmd, "Delete Panel")) {
11387 0 : std::string path;
11388 : //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11389 0 : path += "/History/Display/";
11390 0 : path += hgroup;
11391 0 : path += "/";
11392 0 : path += hpanel;
11393 0 : if (db_find_key(hDB, 0, path.c_str(), &hkey)==DB_SUCCESS)
11394 0 : db_delete_key(hDB, hkey, FALSE);
11395 :
11396 0 : redirect(r, "?cmd=oldhistory");
11397 0 : return;
11398 0 : }
11399 :
11400 0 : if (equal_ustring(hcmd, "createnew")) {
11401 :
11402 : /* strip leading/trailing spaces */
11403 0 : while (hpanel[0] == ' ') {
11404 : char str[256];
11405 0 : mstrlcpy(str, hpanel+1, sizeof(str));
11406 0 : mstrlcpy(hpanel, str, sizeof(hpanel));
11407 : }
11408 0 : while (strlen(hpanel)> 1 && hpanel[strlen(hpanel)-1] == ' ')
11409 0 : hpanel[strlen(hpanel)-1] = 0;
11410 :
11411 : /* use new group if present */
11412 0 : if (p->isparam("new_group") && *p->getparam("new_group"))
11413 0 : mstrlcpy(hgroup, p->getparam("new_group"), sizeof(hgroup));
11414 :
11415 : /* configure that panel */
11416 0 : show_hist_config_page(odb, p, r, hgroup, hpanel);
11417 0 : return;
11418 : }
11419 :
11420 0 : const char* pscale = p->getparam("scale");
11421 0 : if (pscale == NULL || *pscale == 0)
11422 0 : pscale = p->getparam("hscale");
11423 0 : const char* pwidth = p->getparam("width");
11424 0 : if (pwidth == NULL || *pwidth == 0)
11425 0 : pwidth = p->getparam("hwidth");
11426 0 : const char* pheight = p->getparam("height");
11427 0 : if (pheight == NULL || *pheight == 0)
11428 0 : pheight = p->getparam("hheight");
11429 0 : const char* pindex = p->getparam("index");
11430 0 : if (pindex == NULL || *pindex == 0)
11431 0 : pindex = p->getparam("hindex");
11432 :
11433 0 : labels = 1;
11434 0 : if (*p->getparam("labels") && atoi(p->getparam("labels")) == 0)
11435 0 : labels = 0;
11436 :
11437 0 : std::string bgcolor = "FFFFFF";
11438 0 : if (*p->getparam("bgcolor"))
11439 0 : bgcolor = p->xgetparam("bgcolor");
11440 :
11441 0 : std::string fgcolor = "000000";
11442 0 : if (*p->getparam("fgcolor"))
11443 0 : fgcolor = p->xgetparam("fgcolor");
11444 :
11445 0 : std::string gridcolor = "A0A0A0";
11446 0 : if (*p->getparam("gcolor"))
11447 0 : gridcolor = p->xgetparam("gcolor");
11448 :
11449 : /* evaluate scale and offset */
11450 :
11451 0 : time_t endtime = 0;
11452 0 : if (p->isparam("time"))
11453 0 : endtime = string_to_time(p->getparam("time"));
11454 0 : else if (p->isparam("htime"))
11455 0 : endtime = string_to_time(p->getparam("htime"));
11456 :
11457 0 : if (pscale && *pscale)
11458 0 : scale = time_to_sec(pscale);
11459 : else
11460 0 : scale = 0;
11461 :
11462 0 : index = -1;
11463 0 : if (pindex && *pindex)
11464 0 : index = atoi(pindex);
11465 :
11466 : #ifdef BROKEN
11467 : if (equal_ustring(hcmd, "Create ELog")) {
11468 : std::string xurl;
11469 : status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &xurl, FALSE);
11470 : if (status == DB_SUCCESS) {
11471 : char url[256];
11472 : get_elog_url(url, sizeof(url));
11473 :
11474 : /*---- use external ELOG ----*/
11475 : fsize = 100000;
11476 : char* fbuffer = (char*)M_MALLOC(fsize);
11477 : assert(fbuffer != NULL);
11478 :
11479 : int width = 640;
11480 : int height = 400;
11481 :
11482 : if (equal_ustring(pmag, "Large")) {
11483 : width = 1024;
11484 : height = 768;
11485 : } else if (equal_ustring(pmag, "Small")) {
11486 : width = 320;
11487 : height = 200;
11488 : } else if (atoi(pmag) > 0) {
11489 : width = atoi(pmag);
11490 : height = 200;
11491 : }
11492 :
11493 : printf("hereA\n");
11494 : generate_hist_graph(odb, r, hgroup, hpanel, fbuffer, &fsize, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11495 :
11496 : /* save temporary file */
11497 : std::string dir;
11498 : db_get_value_string(hDB, 0, "/Elog/Logbook Dir", 0, &dir, TRUE);
11499 : if (dir.length() > 0 && dir[dir.length()-1] != DIR_SEPARATOR)
11500 : dir += DIR_SEPARATOR_STR;
11501 :
11502 : time_t now = time(NULL);
11503 : localtime_r(&now, &tms);
11504 :
11505 : std::string file_name = msprintf("%02d%02d%02d_%02d%02d%02d_%s.gif",
11506 : tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday,
11507 : tms.tm_hour, tms.tm_min, tms.tm_sec, hpanel);
11508 : std::string fname = dir + file_name;
11509 :
11510 : /* save attachment */
11511 : fh = open(fname.c_str(), O_CREAT | O_RDWR | O_BINARY, 0644);
11512 : if (fh < 0) {
11513 : cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", open() errno %d (%s)", fname.c_str(), errno, strerror(errno));
11514 : } else {
11515 : int wr = write(fh, fbuffer, fsize);
11516 : if (wr != fsize) {
11517 : cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", write(%d) returned %d, errno %d (%s)", fname.c_str(), fsize, wr, errno, strerror(errno));
11518 : }
11519 : close(fh);
11520 : }
11521 :
11522 : /* redirect to ELOG */
11523 : if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11524 : mstrlcat(url, "/", sizeof(url));
11525 : mstrlcat(url, "?cmd=New&fa=", sizeof(url));
11526 : mstrlcat(url, file_name, sizeof(url));
11527 : redirect(r, url);
11528 :
11529 : M_FREE(fbuffer);
11530 : return;
11531 :
11532 : } else {
11533 : /*---- use internal ELOG ----*/
11534 : std::string str = msprintf("\\HS\\%s.gif", hpanel);
11535 : if (p->getparam("hscale") && *p->getparam("hscale"))
11536 : str += msprintf("?scale=%s", p->getparam("hscale"));
11537 : if (p->getparam("htime") && *p->getparam("htime")) {
11538 : if (strchr(str.c_str(), '?'))
11539 : str += "&";
11540 : else
11541 : str += "?";
11542 : str += msprintf("time=%s", p->getparam("htime"));
11543 : }
11544 : //if (p->getparam("hoffset") && *p->getparam("hoffset")) {
11545 : // if (strchr(str, '?'))
11546 : // mstrlcat(str, "&", sizeof(str));
11547 : // else
11548 : // mstrlcat(str, "?", sizeof(str));
11549 : // sprintf(str + strlen(str), "offset=%s", p->getparam("hoffset"));
11550 : //}
11551 : if (p->getparam("hwidth") && *p->getparam("hwidth")) {
11552 : if (strchr(str.c_str(), '?'))
11553 : str += "&";
11554 : else
11555 : str += "?";
11556 : str += msprintf("width=%s", p->getparam("hwidth"));
11557 : }
11558 : if (p->getparam("hindex") && *p->getparam("hindex")) {
11559 : if (strchr(str.c_str(), '?'))
11560 : str += "&";
11561 : else
11562 : str += "?";
11563 : str += msprintf("index=%s", p->getparam("hindex"));
11564 : }
11565 :
11566 : show_elog_new(r, hpanel, NULL, FALSE, str.c_str(), "../../EL/");
11567 : return;
11568 : }
11569 : }
11570 : #endif
11571 :
11572 0 : if (equal_ustring(hcmd, "Export")) {
11573 0 : export_hist(odb, r, hgroup, hpanel, endtime, scale, index, labels);
11574 0 : return;
11575 : }
11576 :
11577 0 : if (strstr(dec_path, ".gif")) {
11578 0 : int width = 640;
11579 0 : int height = 400;
11580 0 : if (equal_ustring(pwidth, "Large")) {
11581 0 : width = 1024;
11582 0 : height = 768;
11583 0 : } else if (equal_ustring(pwidth, "Small")) {
11584 0 : width = 320;
11585 0 : height = 200;
11586 0 : } else if (atoi(pwidth) > 0) {
11587 0 : width = atoi(pwidth);
11588 0 : if (atoi(pheight) > 0)
11589 0 : height = atoi(pheight);
11590 : else
11591 0 : height = (int)(0.625 * width);
11592 : }
11593 :
11594 : //printf("dec_path [%s], buf %p, %p, width %d, height %d, endtime %ld, scale %d, index %d, labels %d\n", dec_path, buffer, buffer_size, width, height, endtime, scale, index, labels);
11595 :
11596 0 : generate_hist_graph(odb, r, hgroup, hpanel, buffer, buffer_size, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11597 :
11598 0 : return;
11599 : }
11600 :
11601 0 : if (history_mode && index < 0)
11602 0 : return;
11603 :
11604 0 : time_t now = time(NULL);
11605 :
11606 : /* evaluate offset shift */
11607 0 : if (equal_ustring(p->getparam("shift"), "leftmaxall")) {
11608 0 : if (endtime == 0)
11609 0 : endtime = now;
11610 0 : time_t last_written = 0;
11611 0 : status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 1, &last_written);
11612 0 : if (status == HS_SUCCESS)
11613 0 : endtime = last_written + scale/2;
11614 : }
11615 :
11616 0 : if (equal_ustring(p->getparam("shift"), "leftmax")) {
11617 0 : if (endtime == 0)
11618 0 : endtime = now;
11619 0 : time_t last_written = 0;
11620 0 : status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 0, &last_written);
11621 0 : if (status == HS_SUCCESS)
11622 0 : if (last_written != endtime)
11623 0 : endtime = last_written + scale/2;
11624 : }
11625 :
11626 0 : if (equal_ustring(p->getparam("shift"), "left")) {
11627 0 : if (endtime == 0)
11628 0 : endtime = now;
11629 0 : endtime -= scale/2;
11630 : //offset -= scale / 2;
11631 : }
11632 :
11633 0 : if (equal_ustring(p->getparam("shift"), "right")) {
11634 0 : if (endtime == 0)
11635 0 : endtime = now;
11636 0 : endtime += scale/2;
11637 0 : if (endtime > now)
11638 0 : endtime = now;
11639 : }
11640 :
11641 0 : if (equal_ustring(p->getparam("shift"), "rightmax")) {
11642 0 : endtime = 0;
11643 : }
11644 :
11645 0 : if (equal_ustring(p->getparam("shift"), "zoomin")) {
11646 0 : if (endtime == 0)
11647 0 : endtime = now;
11648 0 : endtime -= scale / 4;
11649 0 : scale /= 2;
11650 : }
11651 :
11652 0 : if (equal_ustring(p->getparam("shift"), "zoomout")) {
11653 0 : if (endtime == 0)
11654 0 : endtime = now;
11655 0 : endtime += scale / 2;
11656 0 : if (endtime > now)
11657 0 : endtime = now;
11658 0 : scale *= 2;
11659 : }
11660 :
11661 0 : int xrefresh = refresh;
11662 0 : if (endtime != 0)
11663 0 : xrefresh = 0;
11664 0 : show_header(r, hpanel, "GET", "", xrefresh);
11665 :
11666 0 : r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
11667 0 : r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
11668 0 : show_navigation_bar(r, "History");
11669 :
11670 0 : r->rsprintf("<table class=\"mtable\">");
11671 0 : r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>History</th></tr>");
11672 :
11673 : {
11674 : /* check if panel exists */
11675 0 : std::string path;
11676 : //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11677 0 : path += "/History/Display/";
11678 0 : path += hgroup;
11679 0 : path += "/";
11680 0 : path += hpanel;
11681 0 : status = db_find_key(hDB, 0, path.c_str(), &hkey);
11682 0 : if (status != DB_SUCCESS && !equal_ustring(hpanel, "All") && !equal_ustring(hpanel,"")) {
11683 0 : r->rsprintf("<h1>Error: History panel \"%s\" in group \"%s\" does not exist</h1>\n", hpanel, hgroup);
11684 0 : r->rsprintf("</table>\r\n");
11685 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
11686 0 : r->rsprintf("</form>\n");
11687 0 : r->rsprintf("</body></html>\r\n");
11688 0 : return;
11689 : }
11690 0 : }
11691 :
11692 : /* define hidden field for parameters */
11693 0 : if (pscale && *pscale)
11694 0 : r->rsprintf("<input type=hidden name=hscale id=hscale value=%d>\n", scale);
11695 : else {
11696 : /* if no scale and offset given, get it from default */
11697 0 : if (hpanel[0] && !equal_ustring(hpanel, "All") && hgroup[0]) {
11698 0 : std::string path;
11699 0 : path += "/History/Display/";
11700 0 : path += hgroup;
11701 0 : path += "/";
11702 0 : path += hpanel;
11703 0 : path += "/Timescale";
11704 :
11705 0 : std::string scalestr = "1h";
11706 0 : status = db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11707 0 : if (status != DB_SUCCESS) {
11708 : /* delete old integer key */
11709 0 : db_find_key(hDB, 0, path.c_str(), &hkey);
11710 0 : if (hkey)
11711 0 : db_delete_key(hDB, hkey, FALSE);
11712 :
11713 0 : scalestr = "1h";
11714 0 : db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11715 : }
11716 :
11717 0 : r->rsprintf("<input type=hidden name=hscale id=hscale value=%s>\n", scalestr.c_str());
11718 0 : scale = time_to_sec(scalestr.c_str());
11719 0 : }
11720 : }
11721 :
11722 0 : if (endtime != 0)
11723 0 : r->rsprintf("<input type=hidden name=htime id=htime value=%s>\n", time_to_string(endtime).c_str());
11724 0 : if (pwidth && *pwidth)
11725 0 : r->rsprintf("<input type=hidden name=hwidth id=hwidth value=%s>\n", pwidth);
11726 0 : if (pheight && *pheight)
11727 0 : r->rsprintf("<input type=hidden name=hheight id=hheight value=%s>\n", pheight);
11728 0 : if (pindex && *pindex)
11729 0 : r->rsprintf("<input type=hidden name=hindex id=hindex value=%s>\n", pindex);
11730 :
11731 0 : r->rsprintf("</td></tr>\n");
11732 :
11733 0 : if (hgroup[0] == 0) {
11734 : /* "New" button */
11735 0 : r->rsprintf("<tr><td colspan=2><input type=\"button\" name=\"New\" value=\"New\" ");
11736 0 : r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New'\"></td></tr>\n");
11737 :
11738 : /* links for history panels */
11739 0 : r->rsprintf("<tr><td colspan=2 style=\"text-align:left;\">\n");
11740 0 : if (!hpanel[0])
11741 0 : r->rsprintf("<b>Please select panel:</b><br>\n");
11742 :
11743 : /* table for panel selection */
11744 0 : r->rsprintf("<table class=\"historyTable\">");
11745 :
11746 : /* "All" link */
11747 0 : r->rsprintf("<tr><td colspan=2 class=\"titleCell\">\n");
11748 0 : if (equal_ustring(hgroup, "All"))
11749 0 : r->rsprintf("All ");
11750 : else
11751 0 : r->rsprintf("<a href=\"?cmd=oldhistory&group=All\">ALL</a>\n");
11752 0 : r->rsprintf("</td></tr>\n");
11753 :
11754 : /* Setup History table links */
11755 0 : db_find_key(hDB, 0, "/History/Display", &hkey);
11756 0 : if (!hkey) {
11757 : /* create default panel */
11758 : char str[256];
11759 0 : strcpy(str, "System:Trigger per sec.");
11760 0 : strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11761 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables", str, 64, 2, TID_STRING);
11762 0 : strcpy(str, "1h");
11763 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale", str, NAME_LENGTH, 1, TID_STRING);
11764 :
11765 0 : strcpy(str, "1h");
11766 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale", str, NAME_LENGTH, 1, TID_STRING);
11767 0 : i = 1;
11768 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11769 0 : i = 1;
11770 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11771 :
11772 0 : strcpy(str, "");
11773 0 : db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING);
11774 0 : db_set_value_index(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING, FALSE);
11775 : }
11776 :
11777 0 : db_find_key(hDB, 0, "/History/Display", &hkey);
11778 0 : if (hkey) {
11779 0 : for (i = 0;; i++) {
11780 0 : db_enum_link(hDB, hkey, i, &hkeyp);
11781 :
11782 0 : if (!hkeyp)
11783 0 : break;
11784 :
11785 : // Group key
11786 0 : db_get_key(hDB, hkeyp, &key);
11787 :
11788 : char enc_name[256];
11789 0 : mstrlcpy(enc_name, key.name, sizeof(enc_name));
11790 0 : urlEncode(enc_name, sizeof(enc_name));
11791 :
11792 0 : if (equal_ustring(hpanel, key.name))
11793 0 : r->rsprintf("<tr><td class=\"titleCell\">%s</td>\n<td>", key.name);
11794 : else
11795 0 : r->rsprintf("<tr><td class=\"titleCell\"><a href=\"?cmd=oldhistory&group=%s\">%s</a></td>\n<td>", enc_name, key.name);
11796 :
11797 0 : for (j = 0;; j++) {
11798 : // scan items
11799 0 : db_enum_link(hDB, hkeyp, j, &hikeyp);
11800 :
11801 0 : if (!hikeyp) {
11802 0 : r->rsprintf("</tr>");
11803 0 : break;
11804 : }
11805 : // Item key
11806 0 : db_get_key(hDB, hikeyp, &ikey);
11807 :
11808 : char enc_iname[256];
11809 0 : mstrlcpy(enc_iname, ikey.name, sizeof(enc_iname));
11810 0 : urlEncode(enc_iname, sizeof(enc_iname));
11811 :
11812 0 : if (equal_ustring(hpanel, ikey.name))
11813 0 : r->rsprintf("<small><b>%s</b></small> ", ikey.name);
11814 : else
11815 0 : r->rsprintf("<small><a href=\"?cmd=oldhistory&group=%s&panel=%s\">%s</a></small> \n", enc_name, enc_iname, ikey.name);
11816 0 : }
11817 0 : }
11818 : }
11819 :
11820 0 : r->rsprintf("</table></tr>\n");
11821 :
11822 : } else {
11823 0 : int found = 0;
11824 :
11825 : /* show drop-down selectors */
11826 0 : r->rsprintf("<tr><td colspan=2>\n");
11827 :
11828 0 : r->rsprintf("Group:\n");
11829 :
11830 0 : r->rsprintf("<select title=\"Select group\" id=\"fgroup\" onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value;\">\n");
11831 :
11832 0 : db_find_key(hDB, 0, "/History/Display", &hkey);
11833 0 : if (hkey) {
11834 0 : hkeyp = 0;
11835 0 : for (i = 0;; i++) {
11836 0 : db_enum_link(hDB, hkey, i, &hikeyp);
11837 :
11838 0 : if (!hikeyp)
11839 0 : break;
11840 :
11841 0 : if (i == 0)
11842 0 : hkeyp = hikeyp;
11843 :
11844 : // Group key
11845 0 : db_get_key(hDB, hikeyp, &key);
11846 :
11847 0 : if (equal_ustring(key.name, hgroup)) {
11848 0 : r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11849 0 : hkeyp = hikeyp;
11850 : } else
11851 0 : r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11852 : }
11853 :
11854 0 : if (equal_ustring("ALL", hgroup)) {
11855 0 : r->rsprintf("<option selected value=\"%s\">%s\n", "ALL", "ALL");
11856 : } else {
11857 0 : r->rsprintf("<option value=\"%s\">%s\n", "ALL", "ALL");
11858 : }
11859 :
11860 0 : r->rsprintf("</select>\n");
11861 0 : r->rsprintf(" Panel:\n");
11862 0 : r->rsprintf("<select title=\"Select panel\" id=\"fpanel\" ");
11863 0 : r->rsprintf("onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value+");
11864 0 : r->rsprintf("'&panel='+document.getElementById('fpanel').value;\">\n");
11865 :
11866 0 : found = 0;
11867 0 : if (hkeyp) {
11868 0 : for (i = 0;; i++) {
11869 : // scan panels
11870 0 : db_enum_link(hDB, hkeyp, i, &hikeyp);
11871 :
11872 0 : if (!hikeyp)
11873 0 : break;
11874 :
11875 : // Item key
11876 0 : db_get_key(hDB, hikeyp, &key);
11877 :
11878 0 : if (equal_ustring(hpanel, key.name)) {
11879 0 : r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11880 0 : found = 1;
11881 : } else
11882 0 : r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11883 : }
11884 : }
11885 :
11886 0 : if (found)
11887 0 : r->rsprintf("<option value=\"\">- all -\n");
11888 : else
11889 0 : r->rsprintf("<option selected value=\"\">- all -\n");
11890 :
11891 0 : r->rsprintf("</select>\n");
11892 : }
11893 :
11894 0 : r->rsprintf("<noscript>\n");
11895 0 : r->rsprintf("<input type=submit value=\"Go\">\n");
11896 0 : r->rsprintf("</noscript>\n");
11897 :
11898 0 : r->rsprintf(" <input type=\"button\" name=\"New\" value=\"New\" ");
11899 0 : r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New&group=%s'\">\n", hgroup);
11900 :
11901 0 : r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Reset\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Reset&group=%s&panel=%s'\">\n", hgroup, hpanel);
11902 :
11903 0 : r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Query\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Query&group=%s&panel=%s'\">\n", hgroup, hpanel);
11904 :
11905 0 : double xendtime = endtime;
11906 0 : if (xendtime == 0)
11907 0 : xendtime = now;
11908 0 : double xstarttime = xendtime - scale;
11909 :
11910 0 : r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"New history\" onClick=\"window.location.href='?cmd=history&group=%s&panel=%s&A=%.0f&B=%.0f'\">\n", hgroup, hpanel, xstarttime, xendtime);
11911 :
11912 0 : r->rsprintf("</td></tr>\n");
11913 : }
11914 :
11915 : //printf("hgroup [%s] hpanel [%s]\n", hgroup, hpanel);
11916 :
11917 : /* check if whole group should be displayed */
11918 0 : if (hgroup[0] && !equal_ustring(hgroup, "ALL") && hpanel[0] == 0) {
11919 0 : std::string strwidth = "Small";
11920 0 : db_get_value_string(hDB, 0, "/History/Display Settings/Width Group", 0, &strwidth, TRUE);
11921 :
11922 0 : std::string path;
11923 0 : path += "/History/Display/";
11924 0 : path += hgroup;
11925 0 : db_find_key(hDB, 0, path.c_str(), &hkey);
11926 0 : if (hkey) {
11927 0 : for (i = 0 ;; i++) { // scan group
11928 0 : db_enum_link(hDB, hkey, i, &hikeyp);
11929 :
11930 0 : if (!hikeyp)
11931 0 : break;
11932 :
11933 0 : db_get_key(hDB, hikeyp, &key);
11934 :
11935 : char enc_name[256];
11936 0 : mstrlcpy(enc_name, key.name, sizeof(enc_name));
11937 0 : urlEncode(enc_name, sizeof(enc_name));
11938 :
11939 0 : std::string ref;
11940 0 : ref += "graph.gif?width=";
11941 0 : ref += strwidth;
11942 0 : ref += "&cmd=oldhistory&group=";
11943 0 : ref += hgroup;
11944 0 : ref += "&panel=";
11945 0 : ref += enc_name;
11946 :
11947 0 : std::string ref2;
11948 0 : ref2 += "?cmd=oldhistory&group=";
11949 0 : ref2 += hgroup;
11950 0 : ref2 += "&panel=";
11951 0 : ref2 += enc_name;
11952 :
11953 0 : if (endtime != 0) {
11954 : char tmp[256];
11955 0 : sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
11956 0 : ref += "&";
11957 0 : ref += tmp;
11958 0 : ref2 += "?";
11959 0 : ref2 += tmp;
11960 : }
11961 :
11962 0 : if (i % 2 == 0)
11963 0 : r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
11964 : else
11965 0 : r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
11966 0 : }
11967 :
11968 : } else {
11969 0 : r->rsprintf("Group \"%s\" not found", hgroup);
11970 : }
11971 0 : }
11972 :
11973 : /* image panel */
11974 0 : else if (hpanel[0] && !equal_ustring(hpanel, "All")) {
11975 : /* navigation links */
11976 0 : r->rsprintf("<tr><td>\n");
11977 :
11978 0 : std::string path;
11979 0 : path += "/History/Display/";
11980 0 : path += hgroup;
11981 0 : path += "/";
11982 0 : path += hpanel;
11983 0 : path += "/Buttons";
11984 0 : db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11985 0 : if (hkeybutton == 0) {
11986 : /* create default buttons */
11987 0 : db_create_key(hDB, 0, path.c_str(), TID_STRING);
11988 0 : status = db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11989 0 : if (status != DB_SUCCESS || !hkey) {
11990 0 : cm_msg(MERROR, "show_hist_page", "Cannot create history panel with invalid ODB path \"%s\"", path.c_str());
11991 0 : return;
11992 : }
11993 0 : db_set_data(hDB, hkeybutton, def_button, sizeof(def_button), 7, TID_STRING);
11994 : }
11995 :
11996 0 : r->rsprintf("<script>\n");
11997 0 : r->rsprintf("function histDisp(p) {\n");
11998 0 : r->rsprintf(" var params = '?cmd=oldhistory&group=%s&panel=%s';\n", hgroup, hpanel);
11999 0 : r->rsprintf(" params += '&'+p;\n");
12000 0 : r->rsprintf(" if (document.getElementById(\'hscale\') !== null)\n");
12001 0 : r->rsprintf(" params += '&hscale='+document.getElementById(\'hscale\').value;\n");
12002 0 : r->rsprintf(" if (document.getElementById(\'htime\') !== null)\n");
12003 0 : r->rsprintf(" params += '&htime='+document.getElementById(\'htime\').value;\n");
12004 0 : r->rsprintf(" if (document.getElementById(\'hwdith\') !== null)\n");
12005 0 : r->rsprintf(" params += '&hwidth='+document.getElementById(\'hwidth\').value;\n");
12006 0 : r->rsprintf(" if (document.getElementById(\'hindex\') !== null)\n");
12007 0 : r->rsprintf(" params += '&hindex='+document.getElementById(\'hindex\').value;\n");
12008 0 : r->rsprintf(" window.location.search = params;\n");
12009 0 : r->rsprintf("}\n\n");
12010 0 : r->rsprintf("</script>\n");
12011 :
12012 0 : db_get_key(hDB, hkeybutton, &key);
12013 :
12014 0 : for (i = 0; i < key.num_values; i++) {
12015 : char str[256];
12016 0 : size = sizeof(str);
12017 0 : db_get_data_index(hDB, hkeybutton, str, &size, i, TID_STRING);
12018 0 : r->rsprintf("<input type=\"button\" title=\"display last %s\" value=%s onclick=\"histDisp('scale=%s')\">\n", str, str, str);
12019 : }
12020 :
12021 0 : r->rsprintf("<input type=\"button\" value=\"<<<\" title=\"go back in time to last available data for all variables on the plot\" onclick=\"histDisp('shift=leftmaxall')\">");
12022 0 : r->rsprintf("<input type=\"button\" value=\"<<\" title=\"go back in time to last available data\" onclick=\"histDisp('shift=leftmax')\">");
12023 0 : r->rsprintf("<input type=\"button\" value=\"<\" title=\"go back in time\" onclick=\"histDisp('shift=left')\">");
12024 :
12025 0 : r->rsprintf("<input type=\"button\" value=\" + \" title=\"zoom in\" onclick=\"histDisp('shift=zoomin')\">");
12026 0 : r->rsprintf("<input type=\"button\" value=\" - \" title=\"zoom out\" onclick=\"histDisp('shift=zoomout')\">");
12027 :
12028 0 : if (endtime != 0) {
12029 0 : r->rsprintf("<input type=\"button\" value=\">\" title=\"go forward in time\" onclick=\"histDisp('shift=right')\">");
12030 0 : r->rsprintf("<input type=\"button\" value=\">>\" title=\"go to currently updated fresh data\" onclick=\"histDisp('shift=rightmax')\">");
12031 : }
12032 :
12033 0 : r->rsprintf("<td>\n");
12034 0 : r->rsprintf("<input type=\"button\" value=\"Large\" title=\"large display\" onclick=\"histDisp('width=Large')\">\n");
12035 0 : r->rsprintf("<input type=\"button\" value=\"Small\" title=\"large display\" onclick=\"histDisp('width=Small')\">\n");
12036 0 : r->rsprintf("<input type=\"button\" value=\"Create Elog\" title=\"large display\" onclick=\"histDisp('hcmd=Create Elog')\">\n");
12037 0 : r->rsprintf("<input type=\"button\" value=\"Config\" title=\"large display\" onclick=\"histDisp('hcmd=Config')\">\n");
12038 0 : r->rsprintf("<input type=\"button\" value=\"Export\" title=\"large display\" onclick=\"histDisp('hcmd=Export')\">\n");
12039 0 : r->rsprintf("</tr>\n");
12040 :
12041 : char paramstr[256];
12042 :
12043 0 : paramstr[0] = 0;
12044 0 : sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12045 0 : if (endtime != 0)
12046 0 : sprintf(paramstr + strlen(paramstr), "&time=%s", time_to_string(endtime).c_str());
12047 0 : if (pwidth && *pwidth)
12048 0 : sprintf(paramstr + strlen(paramstr), "&width=%s", pwidth);
12049 : else {
12050 0 : std::string wi = "640";
12051 0 : db_get_value_string(hDB, 0, "/History/Display Settings/Width Individual", 0, &wi, TRUE);
12052 0 : sprintf(paramstr + strlen(paramstr), "&width=%s", wi.c_str());
12053 0 : }
12054 0 : if (pheight && *pheight)
12055 0 : sprintf(paramstr + strlen(paramstr), "&height=%s", pheight);
12056 :
12057 : /* define image map */
12058 0 : r->rsprintf("<map name=\"%s\">\r\n", hpanel);
12059 :
12060 0 : if (!(pindex && *pindex)) {
12061 0 : std::string path;
12062 0 : path += "/History/Display/";
12063 0 : path += hgroup;
12064 0 : path += "/";
12065 0 : path += hpanel;
12066 0 : path += "/Variables";
12067 0 : db_find_key(hDB, 0, path.c_str(), &hkey);
12068 0 : if (hkey) {
12069 0 : db_get_key(hDB, hkey, &key);
12070 :
12071 0 : for (i = 0; i < key.num_values; i++) {
12072 0 : std::string ref;
12073 : //if (paramstr[0]) {
12074 : // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&%s&index=%d", hgroup, hpanel, paramstr, i);
12075 : //} else {
12076 : // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&index=%d", hgroup, hpanel, i);
12077 : //}
12078 :
12079 0 : ref += "?cmd=oldhistory&group=";
12080 0 : ref += hgroup;
12081 0 : ref += "&panel=";
12082 0 : ref += hpanel;
12083 0 : if (paramstr[0]) {
12084 0 : ref += "&";
12085 0 : ref += paramstr;
12086 : }
12087 0 : ref += "&index=";
12088 0 : ref += toString(i);
12089 :
12090 0 : r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 30, 31 + 23 * i, 150, 30 + 23 * i + 17, ref.c_str());
12091 0 : }
12092 : }
12093 0 : } else {
12094 0 : std::string ref = "?cmd=oldhistory&group=";
12095 0 : ref += hgroup;
12096 0 : ref += "&panel=";
12097 0 : ref += hpanel;
12098 :
12099 0 : if (paramstr[0]) {
12100 0 : ref += "&";
12101 0 : ref += paramstr;
12102 : }
12103 :
12104 0 : if (equal_ustring(pwidth, "Large"))
12105 0 : width = 1024;
12106 0 : else if (equal_ustring(pwidth, "Small"))
12107 0 : width = 320;
12108 0 : else if (atoi(pwidth) > 0)
12109 0 : width = atoi(pwidth);
12110 : else
12111 0 : width = 640;
12112 :
12113 0 : r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 0, 0, width, 20, ref.c_str());
12114 0 : }
12115 :
12116 0 : r->rsprintf("</map>\r\n");
12117 :
12118 : /* Display individual panels */
12119 0 : if (pindex && *pindex)
12120 0 : sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12121 :
12122 0 : std::string ref;
12123 : //sprintf(ref, "graph.gif?cmd=oldhistory&group=%s&panel=%s%s", hgroup, hpanel, paramstr);
12124 0 : ref += "graph.gif?cmd=oldhistory&group=";
12125 0 : ref += hgroup;
12126 0 : ref += "&panel=";
12127 0 : ref += hpanel;
12128 0 : ref += paramstr;
12129 :
12130 : /* put reference to graph */
12131 0 : r->rsprintf("<tr><td colspan=2><img src=\"%s\" usemap=\"#%s\"></tr>\n", ref.c_str(), hpanel);
12132 0 : }
12133 :
12134 0 : else if (equal_ustring(hgroup, "All")) {
12135 : /* Display all panels */
12136 0 : db_find_key(hDB, 0, "/History/Display", &hkey);
12137 0 : if (hkey)
12138 0 : for (i = 0, k = 0;; i++) { // scan Groups
12139 0 : db_enum_link(hDB, hkey, i, &hkeyp);
12140 :
12141 0 : if (!hkeyp)
12142 0 : break;
12143 :
12144 0 : db_get_key(hDB, hkeyp, &key);
12145 :
12146 : char enc_group_name[256];
12147 0 : mstrlcpy(enc_group_name, key.name, sizeof(enc_group_name));
12148 0 : urlEncode(enc_group_name, sizeof(enc_group_name));
12149 :
12150 0 : for (j = 0;; j++, k++) {
12151 : // scan items
12152 0 : db_enum_link(hDB, hkeyp, j, &hikeyp);
12153 :
12154 0 : if (!hikeyp)
12155 0 : break;
12156 :
12157 0 : db_get_key(hDB, hikeyp, &ikey);
12158 :
12159 : char enc_panel_name[256];
12160 0 : mstrlcpy(enc_panel_name, ikey.name, sizeof(enc_panel_name));
12161 0 : urlEncode(enc_panel_name, sizeof(enc_panel_name));
12162 :
12163 0 : std::string ref;
12164 0 : ref += "graph.gif?width=Small";
12165 0 : ref += "&cmd=oldhistory&group=";
12166 0 : ref += enc_group_name;
12167 0 : ref += "&panel=";
12168 0 : ref += enc_panel_name;
12169 :
12170 0 : std::string ref2;
12171 0 : ref2 += "?cmd=oldhistory&group=";
12172 0 : ref2 += enc_group_name;
12173 0 : ref2 += "&panel=";
12174 0 : ref2 += enc_panel_name;
12175 :
12176 0 : if (endtime != 0) {
12177 : char tmp[256];
12178 0 : sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
12179 0 : ref += "&";
12180 0 : ref += tmp;
12181 0 : ref2 += "&";
12182 0 : ref2 += tmp;
12183 : }
12184 :
12185 0 : if (k % 2 == 0)
12186 0 : r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
12187 : else
12188 0 : r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
12189 0 : } // items loop
12190 0 : } // Groups loop
12191 : } // All
12192 0 : r->rsprintf("</table>\r\n");
12193 0 : r->rsprintf("</div>\n"); // closing for <div id="mmain">
12194 0 : r->rsprintf("</form>\n");
12195 0 : r->rsprintf("</body></html>\r\n");
12196 0 : }
12197 :
12198 :
12199 : /*------------------------------------------------------------------*/
12200 :
12201 0 : void send_icon(Return* r, const char *icon)
12202 : {
12203 : int length;
12204 : const unsigned char *picon;
12205 : char str[256], format[256];
12206 : time_t now;
12207 :
12208 0 : if (strstr(icon, "favicon.ico") != 0) {
12209 0 : length = sizeof(favicon_ico);
12210 0 : picon = favicon_ico;
12211 0 : } else if (strstr(icon, "favicon.png") != 0) {
12212 0 : length = sizeof(favicon_png);
12213 0 : picon = favicon_png;
12214 : } else
12215 0 : return;
12216 :
12217 0 : r->rsprintf("HTTP/1.1 200 Document follows\r\n");
12218 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12219 0 : r->rsprintf("Accept-Ranges: bytes\r\n");
12220 :
12221 : /* set expiration time to one day */
12222 0 : time(&now);
12223 0 : now += (int) (3600 * 24);
12224 : struct tm gmt_tms;
12225 0 : gmtime_r(&now, &gmt_tms);
12226 0 : strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12227 0 : strftime(str, sizeof(str), format, &gmt_tms);
12228 0 : r->rsprintf("Expires: %s\r\n", str);
12229 :
12230 0 : if (equal_ustring(icon, "favicon.ico"))
12231 0 : r->rsprintf("Content-Type: image/x-icon\r\n");
12232 : else
12233 0 : r->rsprintf("Content-Type: image/png\r\n");
12234 :
12235 0 : r->rsprintf("Content-Length: %d\r\n\r\n", length);
12236 :
12237 0 : r->rmemcpy(picon, length);
12238 : }
12239 :
12240 : /*------------------------------------------------------------------*/
12241 :
12242 : struct Cookies
12243 : {
12244 : std::string cookie_pwd;
12245 : std::string cookie_wpwd;
12246 : std::string cookie_cpwd;
12247 : int refresh = 0;
12248 : //int expand_equipment = 0;
12249 : };
12250 :
12251 : /*------------------------------------------------------------------*/
12252 :
12253 0 : void Lock(RequestTrace* t)
12254 : {
12255 0 : gMutex.lock();
12256 0 : t->fTimeLocked = GetTimeSec();
12257 0 : }
12258 :
12259 0 : void Unlock(RequestTrace* t)
12260 : {
12261 0 : t->fTimeUnlocked = GetTimeSec();
12262 0 : gMutex.unlock();
12263 0 : }
12264 :
12265 : /*------------------------------------------------------------------*/
12266 :
12267 0 : void interprete(Param* p, Return* r, Attachment* a, const Cookies* c, const char *dec_path, RequestTrace* t)
12268 : /********************************************************************\
12269 :
12270 : Routine: interprete
12271 :
12272 : Purpose: Main interpreter of web commands
12273 :
12274 : \********************************************************************/
12275 : {
12276 : int status;
12277 : HNDLE hkey, hDB;
12278 :
12279 : //printf("dec_path [%s]\n", dec_path);
12280 :
12281 0 : if (strstr(dec_path, "favicon.ico") != 0 ||
12282 0 : strstr(dec_path, "favicon.png")) {
12283 0 : send_icon(r, dec_path);
12284 0 : return;
12285 : }
12286 :
12287 0 : const char* password = p->getparam("pwd");
12288 0 : const char* wpassword = p->getparam("wpwd");
12289 0 : const char* command = p->getparam("cmd");
12290 :
12291 : //printf("interprete: dec_path [%s], command [%s]\n", dec_path, command);
12292 :
12293 0 : cm_get_experiment_database(&hDB, NULL);
12294 0 : MVOdb* odb = gOdb;
12295 :
12296 0 : if (history_mode) {
12297 0 : if (equal_ustring(command, "history")) {
12298 0 : if (equal_ustring(command, "config")) {
12299 0 : return;
12300 : }
12301 :
12302 0 : Lock(t);
12303 0 : show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12304 0 : Unlock(t);
12305 0 : return;
12306 : }
12307 0 : return;
12308 : }
12309 :
12310 : /* check for password */
12311 0 : db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12312 0 : if (!password[0] && hkey) {
12313 : char str[256];
12314 0 : int size = sizeof(str);
12315 0 : db_get_data(hDB, hkey, str, &size, TID_STRING);
12316 :
12317 : /* check for excemption */
12318 0 : db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12319 0 : if (hkey == 0 && strcmp(c->cookie_pwd.c_str(), str) != 0) {
12320 0 : Lock(t);
12321 0 : show_password_page(r, dec_path, "");
12322 0 : Unlock(t);
12323 0 : return;
12324 : }
12325 : }
12326 :
12327 : /*---- redirect with cookie if password given --------------------*/
12328 :
12329 0 : if (password[0]) {
12330 0 : r->rsprintf("HTTP/1.1 302 Found\r\n");
12331 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12332 :
12333 : time_t now;
12334 0 : time(&now);
12335 :
12336 0 : now += 3600 * 24;
12337 :
12338 : struct tm gmt_tms;
12339 0 : gmtime_r(&now, &gmt_tms);
12340 :
12341 : char str[256];
12342 0 : strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12343 :
12344 0 : r->rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12345 : ss_crypt(password, "mi"), str);
12346 :
12347 0 : r->rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12348 0 : return;
12349 : }
12350 :
12351 0 : if (wpassword[0]) {
12352 : /* check if password correct */
12353 0 : if (!check_web_password(r, hDB, dec_path, ss_crypt(wpassword, "mi"), p->getparam("redir")))
12354 0 : return;
12355 :
12356 0 : r->rsprintf("HTTP/1.1 302 Found\r\n");
12357 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12358 :
12359 : time_t now;
12360 0 : time(&now);
12361 :
12362 0 : now += 3600 * 24;
12363 :
12364 : struct tm gmt_tms;
12365 0 : gmtime_r(&now, &gmt_tms);
12366 :
12367 : char str[256];
12368 0 : strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", &gmt_tms);
12369 :
12370 0 : r->rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", ss_crypt(wpassword, "mi"), str);
12371 :
12372 0 : sprintf(str, "./%s", p->getparam("redir"));
12373 0 : r->rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12374 0 : return;
12375 : }
12376 :
12377 : /*---- send sound file -------------------------------------------*/
12378 :
12379 0 : if (strlen(dec_path) > 3 &&
12380 0 : dec_path[strlen(dec_path)-3] == 'm' &&
12381 0 : dec_path[strlen(dec_path)-2] == 'p' &&
12382 0 : dec_path[strlen(dec_path)-1] == '3') {
12383 0 : if (strrchr(dec_path, '/'))
12384 0 : send_resource(r, strrchr(dec_path, '/')+1);
12385 : else
12386 0 : send_resource(r, dec_path);
12387 0 : return;
12388 : }
12389 :
12390 : /*---- send midas.js and midas.css -------------------------------*/
12391 :
12392 0 : if (strstr(dec_path, "midas.js")) {
12393 0 : send_resource(r, "midas.js");
12394 0 : return;
12395 : }
12396 :
12397 0 : if (strstr(dec_path, "midas.css")) {
12398 0 : send_resource(r, "midas.css");
12399 0 : return;
12400 : }
12401 :
12402 : /*---- send mhttpd.js --------------------------------------------*/
12403 :
12404 0 : if (strstr(dec_path, "mhttpd.js")) {
12405 0 : send_resource(r, "mhttpd.js");
12406 0 : return;
12407 : }
12408 :
12409 : /*---- send obsolete.js ------------------------------------------*/
12410 :
12411 0 : if (strstr(dec_path, "obsolete.js")) {
12412 0 : send_resource(r, "obsolete.js");
12413 0 : return;
12414 : }
12415 :
12416 : /*---- send the obsolete mhttpd.css ------------------------------*/
12417 :
12418 0 : if (strstr(dec_path, "mhttpd.css")) {
12419 0 : send_resource(r, "mhttpd.css");
12420 0 : return;
12421 : }
12422 :
12423 : /*---- send controls.js ------------------------------------------*/
12424 :
12425 0 : if (strstr(dec_path, "controls.js")) {
12426 0 : send_resource(r, "controls.js");
12427 0 : return;
12428 : }
12429 :
12430 : /*---- send example web page -------------------------------------*/
12431 :
12432 0 : if (equal_ustring(command, "example")) {
12433 0 : send_resource(r, "example.html");
12434 0 : return;
12435 : }
12436 :
12437 : /*---- send example custom page -------------------------------------*/
12438 :
12439 0 : if (equal_ustring(command, "custom_example")) {
12440 0 : send_resource(r, "custom_example.html");
12441 0 : return;
12442 : }
12443 :
12444 0 : if (equal_ustring(command, "plot_example")) {
12445 0 : send_resource(r, "plot_example.html");
12446 0 : return;
12447 : }
12448 :
12449 : /*---- script command --------------------------------------------*/
12450 :
12451 0 : if (p->getparam("script") && *p->getparam("script")) {
12452 :
12453 0 : std::string str = msprintf("%s?script=%s", dec_path, p->getparam("script"));
12454 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12455 0 : return;
12456 :
12457 0 : std::string path;
12458 0 : path += "/Script/";
12459 0 : path += p->getparam("script");
12460 :
12461 0 : Lock(t);
12462 :
12463 0 : cm_exec_script(path.c_str());
12464 :
12465 0 : Unlock(t);
12466 :
12467 0 : if (p->isparam("redir"))
12468 0 : redirect2(r, p->getparam("redir"));
12469 : else
12470 0 : redirect2(r, "");
12471 :
12472 0 : return;
12473 0 : }
12474 :
12475 : /*---- customscript command --------------------------------------*/
12476 :
12477 0 : if (p->getparam("customscript") && *p->getparam("customscript")) {
12478 :
12479 0 : std::string str = msprintf("%s?customscript=%s", dec_path, p->getparam("customscript"));
12480 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12481 0 : return;
12482 :
12483 0 : std::string path;
12484 0 : path += "/CustomScript/";
12485 0 : path += p->getparam("customscript");
12486 :
12487 0 : Lock(t);
12488 :
12489 0 : cm_exec_script(path.c_str());
12490 :
12491 0 : Unlock(t);
12492 :
12493 0 : if (p->isparam("redir"))
12494 0 : redirect2(r, p->getparam("redir"));
12495 : else
12496 0 : redirect2(r, str.c_str());
12497 :
12498 0 : return;
12499 0 : }
12500 :
12501 : /*---- send the new html pages -----------------------------------*/
12502 :
12503 0 : if (equal_ustring(command, "start")) {
12504 0 : send_resource(r, "start.html");
12505 0 : return;
12506 : }
12507 :
12508 0 : if ((equal_ustring(command, "") || equal_ustring(command, "status")) && strlen(dec_path) == 0) {
12509 0 : if (midas::odb::exists("/Custom/Status")) {
12510 0 : midas::odb custom("/Custom");
12511 :
12512 0 : std::string filename = custom["Status"];
12513 0 : filename = add_custom_path(filename);
12514 :
12515 : // if custom file exists, send it (like normal web server)
12516 0 : if (ss_file_exist(filename.c_str())) {
12517 0 : send_file(r, filename);
12518 0 : return;
12519 : }
12520 0 : } else
12521 0 : send_resource(r, "status.html");
12522 0 : return;
12523 : }
12524 :
12525 0 : if (equal_ustring(command, "eqtable")) {
12526 0 : send_resource(r, "eqtable.html");
12527 0 : return;
12528 : }
12529 :
12530 0 : if (equal_ustring(command, "newODB")) {
12531 0 : send_resource(r, "odb.html");
12532 0 : return;
12533 : }
12534 :
12535 0 : if (equal_ustring(command, "programs")) {
12536 0 : send_resource(r, "programs.html");
12537 0 : return;
12538 : }
12539 :
12540 0 : if (equal_ustring(command, "alarms")) {
12541 0 : send_resource(r, "alarms.html");
12542 0 : return;
12543 : }
12544 :
12545 0 : if (equal_ustring(command, "transition")) {
12546 0 : send_resource(r, "transition.html");
12547 0 : return;
12548 : }
12549 :
12550 0 : if (equal_ustring(command, "messages")) {
12551 0 : send_resource(r, "messages.html");
12552 0 : return;
12553 : }
12554 :
12555 0 : if (equal_ustring(command, "config") &&
12556 0 : !(dec_path[0] == 'H' && dec_path[1] == 'S' && dec_path[2] == '/')) {
12557 0 : send_resource(r, "config.html");
12558 0 : return;
12559 : }
12560 :
12561 0 : if (equal_ustring(command, "chat")) {
12562 0 : send_resource(r, "chat.html");
12563 0 : return;
12564 : }
12565 :
12566 0 : if (equal_ustring(command, "buffers")) {
12567 0 : send_resource(r, "buffers.html");
12568 0 : return;
12569 : }
12570 :
12571 0 : if (equal_ustring(command, "Show elog")) {
12572 0 : send_resource(r, "elog_show.html");
12573 0 : return;
12574 : }
12575 :
12576 0 : if (equal_ustring(command, "Query elog")) {
12577 0 : send_resource(r, "elog_query_form.html");
12578 0 : return;
12579 : }
12580 :
12581 0 : if (equal_ustring(command, "New elog")) {
12582 0 : send_resource(r, "elog_edit.html");
12583 0 : return;
12584 : }
12585 :
12586 0 : if (equal_ustring(command, "Edit elog")) {
12587 0 : send_resource(r, "elog_edit.html");
12588 0 : return;
12589 : }
12590 :
12591 0 : if (equal_ustring(command, "Reply Elog")) {
12592 0 : send_resource(r, "elog_edit.html");
12593 0 : return;
12594 : }
12595 :
12596 0 : if (equal_ustring(command, "Last elog")) {
12597 0 : send_resource(r, "elog_show.html");
12598 0 : return;
12599 : }
12600 :
12601 0 : if (equal_ustring(command, "Submit Query")) {
12602 0 : send_resource(r, "elog_query.html");
12603 0 : return;
12604 : }
12605 :
12606 0 : if (equal_ustring(dec_path, "spinning-wheel.gif")) {
12607 0 : send_resource(r, "spinning-wheel.gif");
12608 0 : return;
12609 : }
12610 :
12611 : /*---- java script commands --------------------------------------*/
12612 :
12613 0 : if (equal_ustring(command, "jset") ||
12614 0 : equal_ustring(command, "jget") ||
12615 0 : equal_ustring(command, "jcopy") ||
12616 0 : equal_ustring(command, "jpaste") ||
12617 0 : equal_ustring(command, "jkey") ||
12618 0 : equal_ustring(command, "jcreate") ||
12619 0 : equal_ustring(command, "jresize") ||
12620 0 : equal_ustring(command, "jlink") ||
12621 0 : equal_ustring(command, "jrename") ||
12622 0 : equal_ustring(command, "jreorder") ||
12623 0 : equal_ustring(command, "jdelete") ||
12624 0 : equal_ustring(command, "jmsg") ||
12625 0 : equal_ustring(command, "jalm") ||
12626 0 : equal_ustring(command, "jgenmsg") ||
12627 0 : equal_ustring(command, "jrpc_rev0") ||
12628 0 : equal_ustring(command, "jrpc_rev1") ||
12629 0 : equal_ustring(command, "jrpc")) {
12630 0 : Lock(t);
12631 0 : javascript_commands(p, r, c->cookie_cpwd.c_str());
12632 0 : Unlock(t);
12633 0 : return;
12634 : }
12635 :
12636 : /*---- history editord -------------------------------------------*/
12637 :
12638 0 : if (equal_ustring(command, "hs_edit")) {
12639 0 : send_resource(r, "hs_edit.html");
12640 0 : return;
12641 : }
12642 :
12643 : /*---- history command -------------------------------------------*/
12644 :
12645 0 : if (equal_ustring(command, "oldhistory")) {
12646 0 : Lock(t);
12647 0 : show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12648 0 : Unlock(t);
12649 0 : return;
12650 : }
12651 :
12652 0 : if (equal_ustring(command, "history")) {
12653 0 : send_resource(r, "history.html");
12654 0 : return;
12655 : }
12656 :
12657 : /*---- MSCB command ----------------------------------------------*/
12658 :
12659 0 : if (equal_ustring(command, "MSCB")) {
12660 0 : if (equal_ustring(command, "set")) {
12661 0 : std::string str;
12662 0 : str += dec_path;
12663 0 : str += "?";
12664 0 : str += add_param_to_url("cmd", command);
12665 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12666 0 : return;
12667 0 : }
12668 :
12669 0 : Lock(t);
12670 :
12671 : #ifdef HAVE_MSCB
12672 0 : show_mscb_page(p, r, c->refresh);
12673 : #else
12674 : show_error(r, "MSCB support not compiled into this version of mhttpd");
12675 : #endif
12676 :
12677 0 : Unlock(t);
12678 0 : return;
12679 : }
12680 :
12681 : /*---- help command ----------------------------------------------*/
12682 :
12683 0 : if (equal_ustring(command, "help")) {
12684 0 : Lock(t);
12685 0 : show_help_page(r, dec_path);
12686 0 : Unlock(t);
12687 0 : return;
12688 : }
12689 :
12690 : /*---- trigger equipment readout ---------------------------*/
12691 :
12692 0 : if (strncmp(command, "Trigger", 7) == 0) {
12693 0 : std::string cmd;
12694 0 : cmd += "?cmd=";
12695 0 : cmd += command;
12696 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), cmd.c_str())) {
12697 0 : return;
12698 : }
12699 :
12700 0 : Lock(t);
12701 :
12702 : /* extract equipment name */
12703 : char eq_name[NAME_LENGTH];
12704 :
12705 0 : mstrlcpy(eq_name, command + 8, sizeof(eq_name));
12706 0 : if (strchr(eq_name, ' '))
12707 0 : *strchr(eq_name, ' ') = 0;
12708 :
12709 : /* get frontend name */
12710 0 : std::string path;
12711 0 : path += "/Equipment/";
12712 0 : path += eq_name;
12713 0 : path += "/Common/Frontend name";
12714 : char fe_name[NAME_LENGTH];
12715 0 : int size = NAME_LENGTH;
12716 0 : db_get_value(hDB, 0, path.c_str(), fe_name, &size, TID_STRING, TRUE);
12717 :
12718 : /* and ID */
12719 0 : path = "";
12720 0 : path += "/Equipment/";
12721 0 : path += eq_name;
12722 0 : path += "/Common/Event ID";
12723 0 : WORD event_id = 0;
12724 0 : size = sizeof(event_id);
12725 0 : db_get_value(hDB, 0, path.c_str(), &event_id, &size, TID_WORD, TRUE);
12726 :
12727 0 : if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12728 0 : std::string str;
12729 0 : str += "Frontend \"";
12730 0 : str += fe_name;
12731 0 : str += "\" not running!";
12732 0 : show_error(r, str.c_str());
12733 0 : } else {
12734 : HNDLE hconn;
12735 0 : status = cm_connect_client(fe_name, &hconn);
12736 0 : if (status != RPC_SUCCESS) {
12737 0 : std::string str;
12738 0 : str += "Cannot connect to frontend \"";
12739 0 : str += fe_name;
12740 0 : str +="\" !";
12741 0 : show_error(r, str.c_str());
12742 0 : } else {
12743 0 : status = rpc_client_call(hconn, RPC_MANUAL_TRIG, event_id);
12744 0 : if (status != CM_SUCCESS)
12745 0 : show_error(r, "Error triggering event");
12746 : else
12747 0 : redirect(r, "");
12748 :
12749 : //cm_disconnect_client(hconn, FALSE);
12750 : }
12751 : }
12752 :
12753 0 : Unlock(t);
12754 :
12755 0 : return;
12756 0 : }
12757 :
12758 : /*---- switch to next subrun -------------------------------------*/
12759 :
12760 0 : if (strncmp(command, "Next Subrun", 11) == 0) {
12761 0 : int i = TRUE;
12762 0 : db_set_value(hDB, 0, "/Logger/Next subrun", &i, sizeof(i), 1, TID_BOOL);
12763 0 : redirect(r, "");
12764 0 : return;
12765 : }
12766 :
12767 : /*---- cancel command --------------------------------------------*/
12768 :
12769 0 : if (equal_ustring(command, "cancel")) {
12770 0 : if (p->isparam("redir"))
12771 0 : redirect(r, p->getparam("redir"));
12772 : else
12773 0 : redirect(r, "");
12774 0 : return;
12775 : }
12776 :
12777 : /*---- set command -----------------------------------------------*/
12778 :
12779 0 : if (equal_ustring(command, "set")) {
12780 : char str[256];
12781 0 : mstrlcpy(str, "?cmd=set", sizeof(str));
12782 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str))
12783 0 : return;
12784 :
12785 0 : const char* group = p->getparam("group");
12786 0 : int index = atoi(p->getparam("index"));
12787 0 : const char* value = p->getparam("value");
12788 :
12789 0 : Lock(t);
12790 0 : show_set_page(p, r, group, index, value);
12791 0 : Unlock(t);
12792 0 : return;
12793 : }
12794 :
12795 : /*---- find command ----------------------------------------------*/
12796 :
12797 0 : if (equal_ustring(command, "find")) {
12798 0 : const char* value = p->getparam("value");
12799 0 : Lock(t);
12800 0 : show_find_page(r, value);
12801 0 : Unlock(t);
12802 0 : return;
12803 : }
12804 :
12805 : /*---- CAMAC CNAF command ----------------------------------------*/
12806 :
12807 0 : if (equal_ustring(command, "CNAF") || strncmp(dec_path, "CNAF", 4) == 0) {
12808 0 : if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), "?cmd=CNAF"))
12809 0 : return;
12810 :
12811 0 : Lock(t);
12812 0 : show_cnaf_page(p, r);
12813 0 : Unlock(t);
12814 0 : return;
12815 : }
12816 :
12817 : /*---- ELog command ----------------------------------------------*/
12818 :
12819 0 : if (equal_ustring(command, "elog")) {
12820 : /* redirect to external ELOG if URL present */
12821 0 : cm_get_experiment_database(&hDB, NULL);
12822 0 : BOOL external_elog = FALSE;
12823 0 : std::string external_elog_url;
12824 0 : int size = sizeof(external_elog);
12825 0 : status = db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
12826 0 : status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
12827 0 : if (external_elog && (external_elog_url.length() > 0)) {
12828 0 : redirect(r, external_elog_url.c_str());
12829 0 : return;
12830 : }
12831 0 : send_resource(r, "elog_show.html");
12832 0 : return;
12833 0 : }
12834 :
12835 : // special processing for "Elog last 7d", etc
12836 :
12837 : char cmdx[32];
12838 0 : mstrlcpy(cmdx, command, sizeof(cmdx));
12839 0 : cmdx[9] = 0;
12840 :
12841 0 : if (equal_ustring(cmdx, "Elog last")) {
12842 : // "Elog last 7d", etc
12843 0 : send_resource(r, "elog_query.html");
12844 0 : return;
12845 : }
12846 :
12847 0 : if (equal_ustring(command, "Create ELog from this page")) {
12848 0 : std::string redir;
12849 0 : redir += "?cmd=New+elog";
12850 0 : redir += "&odb_path=";
12851 0 : redir += p->getparam("odb_path");
12852 0 : redirect(r, redir.c_str());
12853 0 : return;
12854 0 : }
12855 :
12856 0 : if (equal_ustring(command, "Submit elog")) {
12857 0 : Lock(t);
12858 0 : submit_elog(odb, p, r, a);
12859 0 : Unlock(t);
12860 0 : return;
12861 : }
12862 :
12863 0 : if (equal_ustring(command, "elog_att")) {
12864 0 : Lock(t);
12865 0 : show_elog_attachment(p, r, dec_path);
12866 0 : Unlock(t);
12867 0 : return;
12868 : }
12869 :
12870 : /*---- accept command --------------------------------------------*/
12871 :
12872 0 : if (equal_ustring(command, "accept")) {
12873 0 : int refresh = atoi(p->getparam("refr"));
12874 :
12875 : /* redirect with cookie */
12876 0 : r->rsprintf("HTTP/1.1 302 Found\r\n");
12877 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12878 0 : r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
12879 :
12880 : time_t now;
12881 0 : time(&now);
12882 :
12883 0 : now += 3600 * 24 * 365;
12884 :
12885 : struct tm gmt_tms;
12886 0 : gmtime_r(&now, &gmt_tms);
12887 :
12888 : char str[256];
12889 0 : strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12890 :
12891 0 : r->rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
12892 0 : r->rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
12893 :
12894 0 : return;
12895 : }
12896 :
12897 : #ifdef OBSOLETE
12898 : /*---- slow control display --------------------------------------*/
12899 :
12900 0 : if (equal_ustring(command, "eqtable")) {
12901 0 : Lock(t);
12902 0 : show_eqtable_page(p, r, c->refresh);
12903 0 : Unlock(t);
12904 0 : return;
12905 : }
12906 : #endif
12907 :
12908 : /*---- sequencer page --------------------------------------------*/
12909 :
12910 0 : if (equal_ustring(command, "Sequencer")) {
12911 0 : send_resource(r, "sequencer.html");
12912 0 : return;
12913 : }
12914 :
12915 : // obsolete
12916 0 : if (equal_ustring(command, "seq")) {
12917 0 : send_resource(r, "sequencer.html");
12918 0 : return;
12919 : }
12920 :
12921 0 : if (equal_ustring(command, "start_script")) {
12922 0 : send_resource(r, "start_script.html");
12923 0 : return;
12924 : }
12925 :
12926 0 : if (equal_ustring(command, "load_script")) {
12927 0 : send_resource(r, "load_script.html");
12928 0 : return;
12929 : }
12930 :
12931 0 : if (equal_ustring(command, "edit_script")) {
12932 0 : send_resource(r, "edit_script.html");
12933 0 : return;
12934 : }
12935 :
12936 : /*---- show ODB --------------------------------------------------*/
12937 :
12938 0 : if (equal_ustring(command, "oldOdb")) {
12939 0 : int write_access = TRUE;
12940 0 : db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
12941 0 : if (hkey) {
12942 : char str[256];
12943 0 : int size = sizeof(str);
12944 0 : db_get_data(hDB, hkey, str, &size, TID_STRING);
12945 0 : if (strcmp(c->cookie_wpwd.c_str(), str) == 0)
12946 0 : write_access = TRUE;
12947 : else
12948 0 : write_access = FALSE;
12949 : }
12950 :
12951 0 : std::string odb_path;
12952 0 : if (p->getparam("odb_path") && *p->getparam("odb_path"))
12953 0 : odb_path = p->getparam("odb_path");
12954 :
12955 0 : Lock(t);
12956 0 : show_odb_page(p, r, odb_path.c_str(), write_access);
12957 0 : Unlock(t);
12958 0 : return;
12959 0 : }
12960 :
12961 : /*---- New ODB browser --------------------------------------------*/
12962 :
12963 0 : if (equal_ustring(command, "odb")) {
12964 0 : send_resource(r, "odb.html");
12965 0 : return;
12966 : }
12967 :
12968 : /*---- ODB show open records --------------------------------------*/
12969 :
12970 0 : if (equal_ustring(command, "odb_sor")) {
12971 0 : send_resource(r, "odb_sor.html");
12972 0 : return;
12973 : }
12974 :
12975 : /*---- ODB show clients -------------------------------------------*/
12976 :
12977 0 : if (equal_ustring(command, "odb_scl")) {
12978 0 : send_resource(r, "odb_scl.html");
12979 0 : return;
12980 : }
12981 :
12982 : /*---- old ODB path ----------------------------------------------*/
12983 :
12984 0 : if ((command[0]==0) && dec_path[0]) {
12985 0 : if (equal_ustring(dec_path, "root")) {
12986 0 : std::string new_url = "./?cmd=odb";
12987 : //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
12988 0 : redirect_307(r, new_url.c_str());
12989 0 : return;
12990 0 : }
12991 : }
12992 :
12993 0 : if ((command[0]==0) && dec_path[0]) {
12994 : HNDLE hkey;
12995 0 : status = db_find_key(hDB, 0, dec_path, &hkey);
12996 : //printf("try odb path [%s], status %d\n", dec_path, status);
12997 0 : if (status == DB_SUCCESS) {
12998 0 : int level = 0;
12999 0 : for (const char* s = dec_path; *s; s++) {
13000 0 : if (*s == '/')
13001 0 : level++;
13002 : }
13003 0 : std::string new_url;
13004 0 : if (level == 0) {
13005 : // Top-level directory like /Logger, (which appears in dec_path as "Logger")
13006 0 : new_url += "./";
13007 : } else {
13008 0 : for (int i=0; i<level; i++) {
13009 0 : if (i>0)
13010 0 : new_url += "/";
13011 0 : new_url += "..";
13012 : }
13013 : }
13014 0 : new_url += "?cmd=odb";
13015 0 : new_url += "&odb_path=";
13016 0 : new_url += urlEncode(dec_path);
13017 : //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13018 0 : redirect_307(r, new_url.c_str());
13019 0 : return;
13020 0 : }
13021 : }
13022 :
13023 : /*---- event dump ------------------------------------------------*/
13024 :
13025 0 : if (equal_ustring(command, "event dump")) {
13026 0 : send_resource(r, "event_dump.html");
13027 0 : return;
13028 : }
13029 :
13030 : /*---- custom page -----------------------------------------------*/
13031 :
13032 0 : if (equal_ustring(command, "custom")) {
13033 0 : Lock(t);
13034 0 : show_custom_page(p, r, c->cookie_cpwd.c_str());
13035 0 : Unlock(t);
13036 0 : return;
13037 : }
13038 :
13039 : /*---- custom page accessed by direct URL that used to be under /CS/... ----*/
13040 :
13041 0 : if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13042 0 : std::string odb_path;
13043 0 : std::string value;
13044 : int status;
13045 :
13046 0 : odb_path = "";
13047 0 : odb_path += "/Custom/Images/";
13048 0 : odb_path += dec_path;
13049 0 : odb_path += "/Background";
13050 :
13051 0 : status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13052 :
13053 : //printf("Try custom gif [%s] status %d\n", odb_path.c_str(), status);
13054 :
13055 0 : if (status == DB_SUCCESS) {
13056 0 : if (strstr(dec_path, "..")) {
13057 0 : std::string str;
13058 0 : str += "Invalid custom gif name \'";
13059 0 : str += dec_path;
13060 0 : str += "\' contains \'..\'";
13061 0 : show_error_404(r, str.c_str());
13062 0 : return;
13063 0 : }
13064 :
13065 0 : Lock(t);
13066 0 : show_custom_gif(r, dec_path);
13067 0 : Unlock(t);
13068 0 : return;
13069 : }
13070 :
13071 0 : bool found_custom = false;
13072 :
13073 0 : odb_path = "";
13074 0 : odb_path += "/Custom/";
13075 0 : odb_path += dec_path;
13076 :
13077 0 : status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13078 :
13079 : //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13080 :
13081 0 : if (status == DB_SUCCESS) {
13082 0 : found_custom = true;
13083 : } else {
13084 0 : odb_path = "";
13085 0 : odb_path += "/Custom/";
13086 0 : odb_path += dec_path;
13087 0 : odb_path += "&";
13088 :
13089 0 : status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13090 :
13091 : //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13092 :
13093 0 : if (status == DB_SUCCESS) {
13094 0 : found_custom = true;
13095 : } else {
13096 0 : odb_path = "";
13097 0 : odb_path += "/Custom/";
13098 0 : odb_path += dec_path;
13099 0 : odb_path += "!";
13100 :
13101 0 : status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13102 :
13103 : //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13104 :
13105 0 : if (status == DB_SUCCESS) {
13106 0 : found_custom = true;
13107 : }
13108 : }
13109 : }
13110 :
13111 0 : if (found_custom) {
13112 : //printf("custom file: serving [%s] value [%s]\n", dec_path, value.c_str());
13113 0 : if (strstr(dec_path, "..")) {
13114 0 : std::string str;
13115 0 : str += "Invalid custom page name \'";
13116 0 : str += dec_path;
13117 0 : str += "\' contains \'..\'";
13118 0 : show_error_404(r, str.c_str());
13119 0 : return;
13120 0 : }
13121 :
13122 0 : p->setparam("page", dec_path);
13123 0 : Lock(t);
13124 0 : show_custom_page(p, r, c->cookie_cpwd.c_str());
13125 0 : Unlock(t);
13126 0 : return;
13127 : }
13128 0 : }
13129 :
13130 : /* new custom pages */
13131 0 : if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13132 0 : std::string custom_path;
13133 0 : status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
13134 0 : if ((status == DB_SUCCESS) && (custom_path.length() > 0)) {
13135 0 : if (strstr(dec_path, "..")) {
13136 0 : std::string str;
13137 0 : str += "Invalid custom file name \'";
13138 0 : str += dec_path;
13139 0 : str += "\' contains \'..\'";
13140 0 : show_error_404(r, str.c_str());
13141 0 : return;
13142 0 : }
13143 :
13144 0 : std::string full_filename = add_custom_path(dec_path);
13145 :
13146 : // if custom file exists, send it (like normal web server)
13147 0 : if (ss_file_exist(full_filename.c_str())) {
13148 0 : send_file(r, full_filename);
13149 0 : return;
13150 : }
13151 0 : }
13152 0 : }
13153 :
13154 : /*---- redirect if web page --------------------------------------*/
13155 :
13156 : //if (strlen(command) > 0) {
13157 : // if (send_resource(r, std::string(command) + ".html", false))
13158 : // return;
13159 : //}
13160 :
13161 : /*---- serve url as a resource file ------------------------------*/
13162 :
13163 0 : if (strlen(p->getparam("path")) > 0) {
13164 0 : if (send_resource(r, p->getparam("path"), false)) {
13165 0 : return;
13166 : }
13167 : }
13168 :
13169 : /*---- show status -----------------------------------------------*/
13170 :
13171 0 : if (elog_mode) {
13172 0 : redirect(r, "EL/");
13173 0 : return;
13174 : }
13175 :
13176 : /* header */
13177 0 : r->rsprintf("HTTP/1.1 400 Bad Request\r\n");
13178 0 : r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
13179 0 : r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
13180 0 : r->rsprintf("\r\n");
13181 0 : r->rsprintf("Error: Invalid URL \"%s\" or query \"%s\" or command \"%s\"\n", p->getparam("path"), p->getparam("query"), command);
13182 : }
13183 :
13184 : /*------------------------------------------------------------------*/
13185 :
13186 0 : void decode_query(Param* pp, const char *query_string)
13187 : {
13188 0 : int len = strlen(query_string);
13189 0 : char *buf = (char *)malloc(len+1);
13190 0 : assert(buf != NULL);
13191 0 : memcpy(buf, query_string, len+1);
13192 0 : char* p = buf;
13193 0 : p = strtok(p, "&");
13194 0 : while (p != NULL) {
13195 0 : char *pitem = p;
13196 0 : p = strchr(p, '=');
13197 0 : if (p != NULL) {
13198 0 : *p++ = 0;
13199 0 : urlDecode(pitem); // parameter name
13200 0 : if (!equal_ustring(pitem, "format"))
13201 0 : urlDecode(p); // parameter value
13202 :
13203 0 : pp->setparam(pitem, p); // decoded query parameters
13204 :
13205 0 : p = strtok(NULL, "&");
13206 : }
13207 : }
13208 0 : free(buf);
13209 0 : }
13210 :
13211 0 : void decode_get(Return* rr, char *string, const Cookies* c, const char* url, const char* query_string, RequestTrace* t)
13212 : {
13213 : char path[256];
13214 :
13215 : //printf("decode_get: string [%s], decode_url %d, url [%s], query_string [%s]\n", string, decode_url, url, query_string);
13216 :
13217 0 : Param* param = new Param();
13218 :
13219 0 : param->initparam();
13220 :
13221 0 : if (url)
13222 0 : mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13223 : else {
13224 0 : mstrlcpy(path, string + 1, sizeof(path)); /* strip leading '/' */
13225 :
13226 0 : if (strchr(path, '?'))
13227 0 : *strchr(path, '?') = 0;
13228 : }
13229 :
13230 0 : param->setparam("path", path);
13231 :
13232 0 : assert(query_string != NULL);
13233 :
13234 0 : decode_query(param, query_string);
13235 :
13236 0 : param->setparam("query", query_string);
13237 :
13238 : char dec_path[256];
13239 0 : mstrlcpy(dec_path, path, sizeof(dec_path));
13240 :
13241 0 : interprete(param, rr, NULL, c, dec_path, t);
13242 :
13243 0 : param->freeparam();
13244 0 : delete param;
13245 0 : }
13246 :
13247 : /*------------------------------------------------------------------*/
13248 :
13249 0 : void decode_post(Return* rr, const char *header, const char *string, const char *boundary, int length, const Cookies* c, const char* url, RequestTrace* t)
13250 : {
13251 0 : bool debug_decode_post = false;
13252 :
13253 0 : Param* param = new Param;
13254 :
13255 0 : param->initparam();
13256 :
13257 : char path[256];
13258 :
13259 0 : if (url)
13260 0 : mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13261 : else {
13262 0 : mstrlcpy(path, header + 1, sizeof(path)); /* strip leading '/' */
13263 0 : if (strchr(path, '?'))
13264 0 : *strchr(path, '?') = 0;
13265 0 : if (strchr(path, ' '))
13266 0 : *strchr(path, ' ') = 0;
13267 : }
13268 0 : param->setparam("path", path); // undecoded path
13269 :
13270 0 : Attachment* a = new Attachment;
13271 :
13272 0 : const char* pinit = string;
13273 :
13274 : /* return if no boundary defined */
13275 0 : if (!boundary[0])
13276 0 : return;
13277 :
13278 0 : if (strstr(string, boundary))
13279 0 : string = strstr(string, boundary) + strlen(boundary);
13280 :
13281 0 : if (debug_decode_post)
13282 0 : printf("decode_post: -->[%s]<--\n", string);
13283 :
13284 : do {
13285 : //printf("decode_post: [%s]\n", string);
13286 0 : if (strstr(string, "name=")) {
13287 0 : const char* pitem = strstr(string, "name=") + 5;
13288 0 : if (*pitem == '\"')
13289 0 : pitem++;
13290 :
13291 : //printf("decode_post: pitem [%s]\n", pitem);
13292 :
13293 0 : if (strncmp(pitem, "attfile", 7) == 0) {
13294 0 : int n = pitem[7] - '1';
13295 :
13296 : char file_name[256];
13297 0 : file_name[0] = 0;
13298 :
13299 : /* evaluate file attachment */
13300 0 : if (strstr(pitem, "filename=")) {
13301 0 : const char* p = strstr(pitem, "filename=") + 9;
13302 0 : if (*p == '\"')
13303 0 : p++;
13304 0 : if (strstr(p, "\r\n\r\n"))
13305 0 : string = strstr(p, "\r\n\r\n") + 4;
13306 0 : else if (strstr(p, "\r\r\n\r\r\n"))
13307 0 : string = strstr(p, "\r\r\n\r\r\n") + 6;
13308 :
13309 0 : mstrlcpy(file_name, p, sizeof(file_name));
13310 :
13311 0 : char* pp = file_name;
13312 0 : if (strchr(pp, '\"'))
13313 0 : *strchr(pp, '\"') = 0;
13314 :
13315 : /* set attachment filename */
13316 : char str[256];
13317 0 : sprintf(str, "attachment%d", n);
13318 0 : if (debug_decode_post)
13319 0 : printf("decode_post: [%s] = [%s]\n", str, file_name);
13320 0 : param->setparam(str, file_name); // file_name should be decoded?
13321 : }
13322 :
13323 : /* find next boundary */
13324 0 : const char* ptmp = string;
13325 0 : const char* p = NULL;
13326 : do {
13327 0 : while (*ptmp != '-')
13328 0 : ptmp++;
13329 :
13330 0 : p = strstr(ptmp, boundary);
13331 0 : if (p != NULL) {
13332 0 : while (*p == '-')
13333 0 : p--;
13334 0 : if (*p == 10)
13335 0 : p--;
13336 0 : if (*p == 13)
13337 0 : p--;
13338 0 : p++;
13339 0 : break;
13340 : } else
13341 0 : ptmp += strlen(ptmp);
13342 :
13343 : } while (TRUE);
13344 :
13345 : /* save pointer to file */
13346 0 : if (file_name[0]) {
13347 0 : size_t size = (POINTER_T) p - (POINTER_T) string;
13348 0 : char* buf = (char*)malloc(size+1);
13349 0 : if (!buf) {
13350 0 : return;
13351 : }
13352 0 : memcpy(buf, string, size);
13353 0 : buf[size] = 0; // make sure string is NUL terminated
13354 0 : a->attachment_buffer[n] = buf;
13355 0 : a->attachment_size[n] = size;
13356 0 : if (debug_decode_post)
13357 0 : printf("decode_post: attachment[%d] size %d data --->[%s]<---\n", n, (int)a->attachment_size[n], a->attachment_buffer[n]);
13358 : }
13359 :
13360 0 : string = strstr(p, boundary) + strlen(boundary);
13361 : } else {
13362 0 : const char* p = pitem;
13363 0 : if (strstr(p, "\r\n\r\n"))
13364 0 : p = strstr(p, "\r\n\r\n") + 4;
13365 0 : else if (strstr(p, "\r\r\n\r\r\n"))
13366 0 : p = strstr(p, "\r\r\n\r\r\n") + 6;
13367 :
13368 0 : char* ppitem = (char*)strchr(pitem, '\"'); // NB: defeat "const char* string"
13369 0 : if (ppitem)
13370 0 : *ppitem = 0;
13371 :
13372 0 : char* pb = (char*)(strstr(p, boundary)); // NB: defeat "const char* string"
13373 0 : if (pb) {
13374 0 : string = pb + strlen(boundary);
13375 0 : *pb = 0;
13376 0 : char* ptmp = (char*)(p + (strlen(p) - 1)); // NB: defeat "const char* string"
13377 0 : while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13378 0 : *ptmp-- = 0;
13379 : } else {
13380 0 : show_error(rr, "Invalid POST request");
13381 0 : return;
13382 : }
13383 0 : if (debug_decode_post)
13384 0 : printf("decode_post: [%s] = [%s]\n", pitem, p);
13385 0 : param->setparam(pitem, p); // in decode_post()
13386 : }
13387 :
13388 0 : while (*string == '-' || *string == '\n' || *string == '\r')
13389 0 : string++;
13390 : }
13391 :
13392 0 : } while ((POINTER_T) string - (POINTER_T) pinit < length);
13393 :
13394 : char dec_path[256];
13395 0 : mstrlcpy(dec_path, path, sizeof(dec_path));
13396 :
13397 0 : interprete(param, rr, a, c, dec_path, t);
13398 :
13399 0 : delete a;
13400 0 : delete param;
13401 : }
13402 :
13403 : /*------------------------------------------------------------------*/
13404 :
13405 0 : INT check_odb_records(MVOdb* odb)
13406 : {
13407 : HNDLE hDB, hKeyEq, hKey;
13408 0 : RUNINFO_STR(runinfo_str);
13409 : int i, status;
13410 : KEY key;
13411 :
13412 : /* check /Runinfo structure */
13413 0 : status = cm_get_experiment_database(&hDB, NULL);
13414 0 : assert(status == DB_SUCCESS);
13415 :
13416 0 : status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), FALSE);
13417 0 : if (status == DB_STRUCT_MISMATCH) {
13418 0 : status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), TRUE);
13419 0 : if (status == DB_SUCCESS) {
13420 0 : cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo corrected successfully");
13421 : } else {
13422 0 : cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13423 0 : return 0;
13424 : }
13425 0 : } else if (status == DB_NO_KEY) {
13426 0 : cm_msg(MERROR, "check_odb_records", "ODB subtree /Runinfo does not exist");
13427 0 : status = db_create_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str());
13428 0 : if (status == DB_SUCCESS) {
13429 0 : cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo created successfully");
13430 : } else {
13431 0 : cm_msg(MERROR, "check_odb_records", "Cannot create ODB subtree /Runinfo, db_create_record() status %d", status);
13432 0 : return 0;
13433 : }
13434 0 : } else if (status != DB_SUCCESS) {
13435 0 : cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13436 0 : return 0;
13437 : }
13438 :
13439 : /* check /Equipment/<name>/Common structures */
13440 0 : if (db_find_key(hDB, 0, "/equipment", &hKeyEq) == DB_SUCCESS) {
13441 0 : for (i = 0 ;; i++) {
13442 0 : db_enum_key(hDB, hKeyEq, i, &hKey);
13443 0 : if (!hKey)
13444 0 : break;
13445 0 : db_get_key(hDB, hKey, &key);
13446 :
13447 0 : status = db_check_record(hDB, hKey, "Common", EQUIPMENT_COMMON_STR, FALSE);
13448 0 : if (status == DB_STRUCT_MISMATCH) {
13449 0 : status = db_check_record(hDB, hKey, "Common", EQUIPMENT_COMMON_STR, TRUE);
13450 0 : if (status == DB_SUCCESS) {
13451 0 : cm_msg(MINFO, "check_odb_records", "ODB subtree /Equipment/%s/Common corrected successfully", key.name);
13452 : } else {
13453 0 : cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13454 : }
13455 0 : } else if (status != DB_SUCCESS) {
13456 0 : cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13457 : }
13458 : }
13459 : }
13460 :
13461 0 : return CM_SUCCESS;
13462 : }
13463 :
13464 :
13465 : /*------------------------------------------------------------------*/
13466 :
13467 : std::atomic_bool _abort{false};
13468 :
13469 0 : void ctrlc_handler(int sig)
13470 : {
13471 0 : _abort = true;
13472 0 : }
13473 :
13474 : /*------------------------------------------------------------------*/
13475 :
13476 : #ifdef HAVE_MONGOOSE6
13477 : static std::vector<std::string> gUserAllowedHosts;
13478 : #endif
13479 : static std::vector<std::string> gAllowedHosts;
13480 : #ifdef HAVE_MONGOOSE6
13481 : static const std::string gOdbAllowedHosts = "/Experiment/Security/mhttpd hosts/Allowed hosts";
13482 : #endif
13483 :
13484 : #ifdef HAVE_MONGOOSE6
13485 0 : static void load_allowed_hosts(HNDLE hDB, HNDLE hKey, int index, void* info)
13486 : {
13487 0 : if (hKey != 0)
13488 0 : cm_msg(MINFO, "load_allowed_hosts", "Reloading mhttpd hosts access control list via hotlink callback");
13489 :
13490 0 : gAllowedHosts.clear();
13491 :
13492 : // copy the user allowed hosts
13493 0 : for (unsigned int i=0; i<gUserAllowedHosts.size(); i++)
13494 0 : gAllowedHosts.push_back(gUserAllowedHosts[i]);
13495 :
13496 0 : int total = 0;
13497 0 : int last = 0;
13498 0 : for (int i=0; ; i++) {
13499 0 : std::string s;
13500 0 : int status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), i, &s, FALSE);
13501 : //printf("get %d, status %d, string [%s]\n", i, status, s.c_str());
13502 0 : if (status != DB_SUCCESS) {
13503 0 : total = i;
13504 0 : break;
13505 : }
13506 :
13507 0 : if (s.length() < 1) // skip emties
13508 0 : continue;
13509 :
13510 0 : if (s[0] == '#') // skip commented-out entries
13511 0 : continue;
13512 :
13513 : //printf("add allowed hosts %d [%s]\n", i, s.c_str());
13514 0 : gAllowedHosts.push_back(s);
13515 0 : last = i;
13516 0 : }
13517 :
13518 : //printf("total %d, last %d\n", total, last);
13519 :
13520 0 : if (total - last < 5) {
13521 0 : int new_size = last + 10;
13522 : //printf("new size %d\n", new_size);
13523 0 : int status = db_resize_string(hDB, 0, gOdbAllowedHosts.c_str(), new_size, 256);
13524 0 : if (status != DB_SUCCESS) {
13525 0 : cm_msg(MERROR, "load_allowed_hosts", "Cannot resize the allowed hosts access control list, db_resize_string(%d) status %d", new_size, status);
13526 : }
13527 : }
13528 0 : }
13529 :
13530 0 : static int init_allowed_hosts()
13531 : {
13532 : HNDLE hDB;
13533 : HNDLE hKey;
13534 : int status;
13535 :
13536 0 : cm_get_experiment_database(&hDB, NULL);
13537 :
13538 : // create "allowed hosts" so we can watch it
13539 :
13540 0 : std::string s;
13541 0 : status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), 0, &s, TRUE);
13542 :
13543 0 : if (status != DB_SUCCESS) {
13544 0 : cm_msg(MERROR, "init_allowed_hosts", "Cannot create the mhttpd hosts access control list, db_get_value_string() status %d", status);
13545 0 : return status;
13546 : }
13547 :
13548 0 : status = db_find_key(hDB, 0, gOdbAllowedHosts.c_str(), &hKey);
13549 :
13550 0 : if (status != DB_SUCCESS || hKey == 0) {
13551 0 : cm_msg(MERROR, "init_allowed_hosts", "Cannot find the mhttpd hosts access control list, db_find_key() status %d", status);
13552 0 : return status;
13553 : }
13554 :
13555 0 : load_allowed_hosts(hDB, 0, 0, NULL);
13556 :
13557 0 : status = db_watch(hDB, hKey, load_allowed_hosts, NULL);
13558 :
13559 0 : if (status != DB_SUCCESS) {
13560 0 : cm_msg(MERROR, "init_allowed_hosts", "Cannot watch the mhttpd hosts access control list, db_watch() status %d", status);
13561 0 : return status;
13562 : }
13563 :
13564 0 : return SUCCESS;
13565 0 : }
13566 :
13567 0 : int check_midas_acl(const struct sockaddr *sa, int len) {
13568 : // access control list is empty?
13569 0 : if (gAllowedHosts.size() == 0)
13570 0 : return 1;
13571 :
13572 : char hname[NI_MAXHOST];
13573 0 : hname[0] = 0;
13574 :
13575 : int status;
13576 0 : const char* status_string = "success";
13577 :
13578 0 : status = getnameinfo(sa, len, hname, sizeof(hname), NULL, 0, 0);
13579 :
13580 0 : if (status)
13581 0 : status_string = gai_strerror(status);
13582 :
13583 : //printf("connection from [%s], status %d (%s)\n", hname, status, status_string);
13584 :
13585 0 : if (status != 0) {
13586 0 : printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, status, status_string);
13587 0 : return 0;
13588 : }
13589 :
13590 : /* always permit localhost */
13591 0 : if (strcmp(hname, "localhost.localdomain") == 0)
13592 0 : return 1;
13593 0 : if (strcmp(hname, "localhost") == 0)
13594 0 : return 1;
13595 :
13596 0 : for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++)
13597 0 : if (gAllowedHosts[i] == hname) {
13598 0 : return 1;
13599 : }
13600 :
13601 0 : printf("Rejecting connection from \'%s\'\n", hname);
13602 0 : return 0;
13603 : }
13604 :
13605 0 : int open_listening_socket(int port)
13606 : {
13607 : int status;
13608 : struct sockaddr_in bind_addr;
13609 :
13610 : /* create a new socket */
13611 0 : int lsock = socket(AF_INET, SOCK_STREAM, 0);
13612 :
13613 0 : if (lsock == -1) {
13614 0 : printf("Cannot create socket, socket() errno %d (%s)\n", errno, strerror(errno));
13615 0 : return -1;
13616 : }
13617 :
13618 : /* bind local node name and port to socket */
13619 0 : memset(&bind_addr, 0, sizeof(bind_addr));
13620 0 : bind_addr.sin_family = AF_INET;
13621 0 : bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13622 0 : bind_addr.sin_port = htons((short) port);
13623 :
13624 : /* try reusing address */
13625 0 : int flag = 1;
13626 0 : status = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13627 :
13628 0 : if (status < 0) {
13629 0 : printf("Cannot setsockopt(SOL_SOCKET, SO_REUSEADDR), errno %d (%s)\n", errno, strerror(errno));
13630 0 : return -1;
13631 : }
13632 :
13633 0 : status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13634 :
13635 0 : if (status < 0) {
13636 0 : printf("Cannot bind() to port %d, bind() errno %d (%s)\n", port, errno, strerror(errno));
13637 0 : return -1;
13638 : }
13639 :
13640 : /* listen for connection */
13641 0 : status = listen(lsock, SOMAXCONN);
13642 0 : if (status < 0) {
13643 0 : printf("Cannot listen() on port %d, errno %d (%s), bye!\n", port, errno, strerror(errno));
13644 0 : return -1;
13645 : }
13646 :
13647 0 : printf("mhttpd is listening on port %d\n", port);
13648 :
13649 0 : return lsock;
13650 : }
13651 : #endif
13652 :
13653 : /*------------------------------------------------------------------*/
13654 :
13655 0 : int try_file_mg(const char* try_dir, const char* filename, std::string& path, FILE** fpp, bool trace)
13656 : {
13657 0 : if (fpp)
13658 0 : *fpp = NULL;
13659 0 : if (!try_dir)
13660 0 : return SS_FILE_ERROR;
13661 0 : if (strlen(try_dir) < 1)
13662 0 : return SS_FILE_ERROR;
13663 :
13664 0 : path = try_dir;
13665 0 : if (path[path.length()-1] != DIR_SEPARATOR)
13666 0 : path += DIR_SEPARATOR_STR;
13667 0 : path += filename;
13668 :
13669 0 : FILE* fp = fopen(path.c_str(), "r");
13670 :
13671 0 : if (trace) {
13672 0 : if (fp)
13673 0 : printf("file \"%s\": OK!\n", path.c_str());
13674 : else
13675 0 : printf("file \"%s\": not found.\n", path.c_str());
13676 : }
13677 :
13678 0 : if (!fp)
13679 0 : return SS_FILE_ERROR;
13680 0 : else if (fpp)
13681 0 : *fpp = fp;
13682 : else
13683 0 : fclose(fp);
13684 :
13685 0 : return SUCCESS;
13686 : }
13687 :
13688 0 : int find_file_mg(const char* filename, std::string& path, FILE** fpp, bool trace)
13689 : {
13690 0 : std::string exptdir = cm_get_path();
13691 :
13692 0 : if (try_file_mg(".", filename, path, fpp, trace) == SUCCESS)
13693 0 : return SUCCESS;
13694 :
13695 0 : if (try_file_mg(getenv("MIDAS_DIR"), filename, path, fpp, trace) == SUCCESS)
13696 0 : return SUCCESS;
13697 :
13698 0 : if (try_file_mg(exptdir.c_str(), filename, path, fpp, trace) == SUCCESS)
13699 0 : return SUCCESS;
13700 :
13701 0 : if (try_file_mg(getenv("MIDASSYS"), filename, path, fpp, trace) == SUCCESS)
13702 0 : return SUCCESS;
13703 :
13704 : // setup default filename
13705 0 : try_file_mg(exptdir.c_str(), filename, path, NULL, false);
13706 0 : return SS_FILE_ERROR;
13707 0 : }
13708 :
13709 : #ifdef HAVE_MONGOOSE6
13710 : #include "mongoose6.h"
13711 : #endif
13712 :
13713 : #ifdef HAVE_MONGOOSE616
13714 : #undef closesocket
13715 : #include "mongoose616.h"
13716 : // cs_md5() in not in mongoose.h
13717 : extern void cs_md5(char buf[33], ...);
13718 : #endif
13719 :
13720 : static bool verbose_mg = false;
13721 : static bool trace_mg = false;
13722 : static bool trace_mg_recv = false;
13723 : static bool trace_mg_send = false;
13724 : static bool trace_mg_verbose = false;
13725 : #ifdef HAVE_MONGOOSE616
13726 : static bool multithread_mg = true;
13727 : #endif
13728 :
13729 : #ifdef HAVE_MONGOOSE6
13730 : static struct mg_mgr mgr_mg;
13731 : #endif
13732 :
13733 : struct AuthEntry {
13734 : std::string username;
13735 : std::string realm;
13736 : std::string password;
13737 : };
13738 :
13739 : class Auth {
13740 : public:
13741 : std::string realm;
13742 : std::string passwd_filename;
13743 : std::vector<AuthEntry> passwords;
13744 : public:
13745 : int Init();
13746 : };
13747 :
13748 : static bool read_passwords(Auth* auth);
13749 :
13750 0 : int Auth::Init()
13751 : {
13752 0 : std::string exptname = cm_get_experiment_name();
13753 :
13754 0 : if (!exptname.empty())
13755 0 : realm = exptname;
13756 : else
13757 0 : realm = "midas";
13758 :
13759 0 : bool ok = read_passwords(this);
13760 0 : if (!ok) {
13761 0 : cm_msg(MERROR, "mongoose", "mongoose web server password file \"%s\" has no passwords for realm \"%s\"", passwd_filename.c_str(), realm.c_str());
13762 0 : cm_msg(MERROR, "mongoose", "please add passwords by running: htdigest %s %s midas", passwd_filename.c_str(), realm.c_str());
13763 0 : return SS_FILE_ERROR;
13764 : }
13765 :
13766 0 : return SUCCESS;
13767 0 : }
13768 :
13769 : static Auth *gAuthMg = NULL;
13770 :
13771 0 : static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri,
13772 : size_t uri_len, const char *ha1, size_t ha1_len,
13773 : const char *nonce, size_t nonce_len, const char *nc,
13774 : size_t nc_len, const char *cnonce, size_t cnonce_len,
13775 : const char *qop, size_t qop_len, char *resp) {
13776 : static const char colon[] = ":";
13777 : static const size_t one = 1;
13778 : char ha2[33];
13779 :
13780 0 : cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
13781 0 : cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
13782 : nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
13783 : colon, one, ha2, sizeof(ha2) - 1, NULL);
13784 0 : }
13785 :
13786 : /*
13787 : * Check for authentication timeout.
13788 : * Clients send time stamp encoded in nonce. Make sure it is not too old,
13789 : * to prevent replay attacks.
13790 : * Assumption: nonce is a hexadecimal number of seconds since 1970.
13791 : */
13792 0 : static int xmg_check_nonce(const char *nonce) {
13793 0 : unsigned long now = (unsigned long) time(NULL);
13794 0 : unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
13795 0 : return now < val || now - val < 3600;
13796 : }
13797 :
13798 : /*
13799 : * Authenticate HTTP request against opened passwords file.
13800 : * Returns 1 if authenticated, 0 otherwise.
13801 : */
13802 :
13803 0 : static void xmg_http_send_digest_auth_request(struct mg_connection *c,
13804 : const char *domain) {
13805 0 : mg_printf(c,
13806 : "HTTP/1.1 401 Unauthorized\r\n"
13807 : "WWW-Authenticate: Digest qop=\"auth\", "
13808 : "realm=\"%s\", nonce=\"%lu\"\r\n"
13809 : "Content-Length: 0\r\n\r\n",
13810 0 : domain, (unsigned long) time(NULL));
13811 0 : }
13812 :
13813 0 : static bool read_passwords(Auth* auth)
13814 : {
13815 0 : std::string path;
13816 : FILE *fp;
13817 0 : int status = find_file_mg("htpasswd.txt", path, &fp, trace_mg||verbose_mg);
13818 :
13819 0 : auth->passwd_filename = path;
13820 0 : auth->passwords.clear();
13821 :
13822 0 : if (status != SUCCESS || fp == NULL) {
13823 0 : cm_msg(MERROR, "mongoose", "mongoose web server cannot find password file \"%s\"", path.c_str());
13824 0 : cm_msg(MERROR, "mongoose", "please create password file: touch %s", path.c_str());
13825 0 : return false;
13826 : }
13827 :
13828 0 : bool have_realm = false;
13829 : char buf[256];
13830 :
13831 : /*
13832 : * Read passwords file line by line. If should have htdigest format,
13833 : * i.e. each line should be a colon-separated sequence:
13834 : * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
13835 : */
13836 0 : while (fgets(buf, sizeof(buf), fp) != NULL) {
13837 : char f_user[256];
13838 : char f_domain[256];
13839 : char f_ha1[256];
13840 :
13841 0 : if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3) {
13842 0 : AuthEntry e;
13843 0 : e.realm = f_domain;
13844 0 : e.username = f_user;
13845 0 : e.password = f_ha1;
13846 :
13847 0 : if (e.realm == auth->realm) {
13848 0 : have_realm = true;
13849 0 : auth->passwords.push_back(e);
13850 : }
13851 0 : }
13852 : }
13853 :
13854 0 : fclose(fp);
13855 :
13856 0 : return have_realm;
13857 0 : }
13858 :
13859 : #ifdef HAVE_MONGOOSE6
13860 0 : std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13861 : {
13862 0 : assert(!"this code is untested!");
13863 :
13864 : char* buf = NULL;
13865 : int buf_size = 0;
13866 :
13867 : while (1) {
13868 : if (buf_size == 0) {
13869 : buf_size = 256;
13870 : buf = (char*)malloc(buf_size);
13871 : assert(buf != NULL);
13872 : }
13873 :
13874 : int size = mg_http_parse_header(hdr, var_name, buf, buf_size);
13875 :
13876 : if (size <= 0) {
13877 : free(buf);
13878 : return "";
13879 : }
13880 :
13881 : if (size < buf_size) {
13882 : std::string s = buf;
13883 : free(buf);
13884 : return s;
13885 : }
13886 :
13887 : buf_size = buf_size*2 + 16;
13888 : buf = (char*)realloc(buf, buf_size);
13889 : assert(buf != NULL);
13890 : }
13891 : }
13892 : #endif
13893 :
13894 : #ifdef HAVE_MONGOOSE616
13895 0 : std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13896 : {
13897 0 : char* buf = NULL;
13898 0 : int buf_size = 0;
13899 0 : int size = mg_http_parse_header2(hdr, var_name, &buf, buf_size);
13900 0 : if (size <= 0)
13901 0 : return "";
13902 0 : assert(buf != NULL);
13903 0 : std::string s = buf;
13904 0 : free(buf);
13905 0 : return s;
13906 0 : }
13907 : #endif
13908 :
13909 0 : static std::string check_digest_auth(struct http_message *hm, Auth* auth)
13910 : {
13911 : char expected_response[33];
13912 :
13913 : //printf("HereA!\n");
13914 :
13915 : /* Parse "Authorization:" header, fail fast on parse error */
13916 0 : struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
13917 :
13918 0 : if (!hdr)
13919 0 : return "";
13920 :
13921 : //printf("HereB!\n");
13922 :
13923 0 : std::string user = find_var_mg(hdr, "username");
13924 0 : std::string cnonce = find_var_mg(hdr, "cnonce");
13925 0 : std::string response = find_var_mg(hdr, "response");
13926 0 : std::string uri = find_var_mg(hdr, "uri");
13927 0 : std::string qop = find_var_mg(hdr, "qop");
13928 0 : std::string nc = find_var_mg(hdr, "nc");
13929 0 : std::string nonce = find_var_mg(hdr, "nonce");
13930 :
13931 0 : if (user.length()<1) return "";
13932 0 : if (cnonce.length()<1) return "";
13933 0 : if (response.length()<1) return "";
13934 0 : if (uri.length()<1) return "";
13935 0 : if (qop.length()<1) return "";
13936 0 : if (nc.length()<1) return "";
13937 0 : if (nonce.length()<1) return "";
13938 :
13939 0 : if (xmg_check_nonce(nonce.c_str()) == 0) return "";
13940 : //printf("HereB8!\n");
13941 :
13942 : //printf("HereC!\n");
13943 :
13944 0 : const char* uri_end = strchr(hm->uri.p, ' ');
13945 0 : if (!uri_end) return "";
13946 :
13947 0 : size_t uri_length = uri_end - hm->uri.p;
13948 :
13949 0 : if (uri_length != uri.length())
13950 0 : return "";
13951 :
13952 0 : int cmp = strncmp(hm->uri.p, uri.c_str(), uri_length);
13953 :
13954 : //printf("check URI: message %d %d [%d] authorization [%s]\n", (int)hm->uri.len, uri_length, cmp, uri);
13955 :
13956 0 : if (cmp != 0)
13957 0 : return "";
13958 :
13959 0 : for (unsigned i=0; i<auth->passwords.size(); i++) {
13960 0 : AuthEntry* e = &auth->passwords[i];
13961 0 : if (e->username != user)
13962 0 : continue;
13963 0 : if (e->realm != auth->realm)
13964 0 : continue;
13965 0 : const char* f_ha1 = e->password.c_str();
13966 0 : int uri_len = hm->uri.len;
13967 0 : if (hm->uri.p[uri_len] == '?')
13968 0 : uri_len += hm->query_string.len + 1; // "+1" accounts for the "?" character
13969 0 : xmg_mkmd5resp(hm->method.p, hm->method.len,
13970 : hm->uri.p, uri_len,
13971 : f_ha1, strlen(f_ha1),
13972 : nonce.c_str(), nonce.length(),
13973 : nc.c_str(), nc.length(),
13974 : cnonce.c_str(), cnonce.length(),
13975 : qop.c_str(), qop.length(),
13976 : expected_response);
13977 0 : int cmp = strcasecmp(response.c_str(), expected_response);
13978 : //printf("digest_auth: expected %s, got %s, cmp %d\n", expected_response, response.c_str(), cmp);
13979 0 : if (cmp == 0) {
13980 0 : return e->username;
13981 : }
13982 : }
13983 :
13984 0 : return "";
13985 0 : }
13986 :
13987 : #ifdef HAVE_MONGOOSE616
13988 :
13989 : struct HostlistCacheEntry
13990 : {
13991 : time_t time_created = 0;
13992 : time_t time_last_used = 0;
13993 : int count_used = 0;
13994 : bool ipv4 = false;
13995 : bool ipv6 = false;
13996 : uint32_t ipv4addr = 0;
13997 : struct in6_addr ipv6addr;
13998 : std::string hostname;
13999 : int gai_status = 0;
14000 : std::string gai_strerror;
14001 : bool ok = false;
14002 : };
14003 :
14004 : static std::vector<HostlistCacheEntry*> gHostlistCache;
14005 :
14006 0 : static void print_hostlist_cache()
14007 : {
14008 0 : time_t now = time(NULL);
14009 :
14010 0 : for (unsigned i=0; i<gHostlistCache.size(); i++) {
14011 0 : HostlistCacheEntry* e = gHostlistCache[i];
14012 0 : if (!e) {
14013 : // empty slot
14014 0 : continue;
14015 : }
14016 :
14017 0 : printf("%3d: %s \"%s\", ok %d, count_used %d, age created: %d, last_used %d",
14018 : i,
14019 0 : e->ipv4?"IPv4":(e->ipv6?"IPv6":"????"),
14020 : e->hostname.c_str(),
14021 0 : e->ok,
14022 : e->count_used,
14023 0 : (int)(now - e->time_created),
14024 0 : (int)(now - e->time_last_used));
14025 :
14026 0 : if (e->gai_status) {
14027 0 : printf(", getnameinfo() status %d (%s)", e->gai_status, e->gai_strerror.c_str());
14028 : }
14029 :
14030 0 : printf("\n");
14031 : }
14032 0 : }
14033 :
14034 0 : static bool mongoose_check_hostlist(const union socket_address *sa)
14035 : {
14036 0 : time_t now = time(NULL);
14037 0 : bool ipv4 = false;
14038 0 : bool ipv6 = false;
14039 0 : uint32_t ipv4addr = 0;
14040 : struct in6_addr ipv6addr;
14041 :
14042 0 : if (sa->sa.sa_family == AF_INET) {
14043 0 : ipv4 = true;
14044 0 : ipv4addr = sa->sin.sin_addr.s_addr;
14045 0 : } else if (sa->sa.sa_family == AF_INET6) {
14046 0 : ipv6 = true;
14047 0 : memcpy(&ipv6addr, &sa->sin6.sin6_addr, sizeof(ipv6addr));
14048 : } else {
14049 0 : printf("Rejecting connection from unknown address family %d (AF_xxx)\n", sa->sa.sa_family);
14050 0 : return false;
14051 : }
14052 :
14053 0 : for (unsigned i=0; i<gHostlistCache.size(); i++) {
14054 0 : HostlistCacheEntry* e = gHostlistCache[i];
14055 0 : if (!e) {
14056 : // empty slot
14057 0 : continue;
14058 : }
14059 :
14060 0 : if ((ipv4 == e->ipv4) && (ipv4addr == e->ipv4addr)) {
14061 : // IPv4 address match
14062 0 : e->time_last_used = now;
14063 0 : e->count_used++;
14064 0 : return e->ok;
14065 : }
14066 :
14067 0 : if ((ipv6 == e->ipv6) && (memcmp(&ipv6addr, &e->ipv6addr, sizeof(ipv6addr)) == 0)) {
14068 : // IPv6 address match
14069 0 : e->time_last_used = now;
14070 0 : e->count_used++;
14071 0 : return e->ok;
14072 : }
14073 :
14074 : // not this one. maybe expire old entries?
14075 :
14076 0 : if (e->time_last_used < now - 24*60*60) {
14077 0 : printf("hostlist: expire \"%s\", ok %d, age %d, count_used: %d\n", e->hostname.c_str(), e->ok, (int)(now - e->time_last_used), e->count_used);
14078 0 : gHostlistCache[i] = NULL;
14079 0 : delete e;
14080 : }
14081 : }
14082 :
14083 : // not found in cache
14084 :
14085 0 : assert(ipv4 || ipv6);
14086 :
14087 0 : HostlistCacheEntry* e = new HostlistCacheEntry;
14088 :
14089 0 : bool found = false;
14090 0 : for (unsigned i=0; i<gHostlistCache.size(); i++) {
14091 0 : if (gHostlistCache[i] == NULL) {
14092 0 : gHostlistCache[i] = e;
14093 0 : found = true;
14094 : }
14095 : }
14096 0 : if (!found) {
14097 0 : gHostlistCache.push_back(e);
14098 : }
14099 :
14100 0 : e->time_created = now;
14101 0 : e->time_last_used = now;
14102 0 : e->count_used = 1;
14103 0 : e->ipv4 = ipv4;
14104 0 : e->ipv6 = ipv6;
14105 0 : if (ipv4)
14106 0 : e->ipv4addr = ipv4addr;
14107 0 : if (ipv6)
14108 0 : memcpy(&e->ipv6addr, &ipv6addr, sizeof(ipv6addr));
14109 0 : e->ok = false;
14110 :
14111 : char hname[NI_MAXHOST];
14112 0 : hname[0] = 0;
14113 :
14114 0 : e->gai_status = getnameinfo(&sa->sa, sizeof(*sa), hname, sizeof(hname), NULL, 0, 0);
14115 :
14116 0 : if (e->gai_status) {
14117 0 : e->gai_strerror = gai_strerror(e->gai_status);
14118 :
14119 0 : printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, e->gai_status, e->gai_strerror.c_str());
14120 :
14121 0 : e->ok = false;
14122 0 : return e->ok;
14123 : }
14124 :
14125 0 : printf("connection from \"%s\"\n", hname);
14126 :
14127 0 : e->hostname = hname;
14128 :
14129 : /* always permit localhost */
14130 0 : if (e->hostname == "localhost.localdomain")
14131 0 : e->ok = true;
14132 0 : else if (e->hostname == "localhost")
14133 0 : e->ok = true;
14134 : else {
14135 0 : for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++) {
14136 0 : if (e->hostname == gAllowedHosts[i]) {
14137 0 : e->ok = true;
14138 : }
14139 : }
14140 : }
14141 :
14142 0 : if (!e->ok) {
14143 0 : printf("Rejecting connection from \'%s\'\n", hname);
14144 : }
14145 :
14146 0 : print_hostlist_cache();
14147 :
14148 0 : return e->ok;
14149 : }
14150 :
14151 : #endif
14152 :
14153 0 : static std::string mgstr(const mg_str* s)
14154 : {
14155 0 : return std::string(s->p, s->len);
14156 : }
14157 :
14158 0 : static const std::string find_header_mg(const struct http_message *msg, const char* name)
14159 : {
14160 0 : size_t nlen = strlen(name);
14161 0 : for (int i=0; i<MG_MAX_HTTP_HEADERS; i++) {
14162 0 : if (msg->header_names[i].len != nlen)
14163 0 : continue;
14164 0 : if (strncmp(msg->header_names[i].p, name, nlen) != 0)
14165 0 : continue;
14166 0 : return mgstr(&msg->header_values[i]);
14167 : }
14168 0 : return "";
14169 : }
14170 :
14171 0 : static const std::string find_cookie_mg(const struct http_message *msg, const char* cookie_name)
14172 : {
14173 0 : const std::string cookies = find_header_mg(msg, "Cookie");
14174 0 : if (cookies.length() < 1)
14175 0 : return "";
14176 0 : const char* p = strstr(cookies.c_str(), cookie_name);
14177 0 : if (!p)
14178 0 : return "";
14179 0 : const char* v = p+strlen(cookie_name);
14180 0 : if (*v != '=')
14181 0 : return "";
14182 0 : v++;
14183 : //printf("cookie [%s] value [%s]\n", cookie_name, v);
14184 0 : return v;
14185 0 : }
14186 :
14187 : // Generic event handler
14188 :
14189 0 : static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
14190 : {
14191 0 : struct mbuf *io = &nc->recv_mbuf;
14192 0 : switch (ev) {
14193 0 : case MG_EV_POLL: // periodic call from loop_mg() via mg_mgr_poll()
14194 0 : break;
14195 0 : case MG_EV_ACCEPT:
14196 0 : if (trace_mg)
14197 0 : printf("handle_event_mg: nc %p, ev %d, ev_data %p -> accept\n", nc, ev, ev_data);
14198 0 : break;
14199 0 : case MG_EV_RECV:
14200 0 : if (trace_mg)
14201 0 : printf("handle_event_mg: nc %p, ev %d, ev_data %p -> recv %d, buffered %d bytes\n", nc, ev, ev_data, *(int*)ev_data, (int)io->len);
14202 : #if 0
14203 : // This event handler implements simple TCP echo server
14204 : mg_send(nc, io->buf, io->len); // Echo received data back
14205 : mbuf_remove(io, io->len); // Discard data from recv buffer
14206 : #endif
14207 0 : break;
14208 0 : case MG_EV_SEND:
14209 0 : if (trace_mg)
14210 0 : printf("handle_event_mg: nc %p, ev %d, ev_data %p -> send %d bytes\n", nc, ev, ev_data, *(int*)ev_data);
14211 0 : break;
14212 0 : case MG_EV_CLOSE:
14213 0 : if (trace_mg)
14214 0 : printf("handle_event_mg: nc %p, ev %d, ev_data %p -> close\n", nc, ev, ev_data);
14215 0 : break;
14216 0 : default:
14217 0 : if (trace_mg)
14218 0 : printf("handle_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
14219 0 : break;
14220 : }
14221 0 : }
14222 :
14223 0 : void decode_cookies(Cookies *c, const http_message* msg)
14224 : {
14225 : // extract password cookies
14226 :
14227 : char cookie_pwd[256]; // general access password
14228 : char cookie_wpwd[256]; // "write mode" password
14229 : char cookie_cpwd[256]; // custom page and javascript password
14230 :
14231 0 : cookie_pwd[0] = 0;
14232 0 : cookie_wpwd[0] = 0;
14233 0 : cookie_cpwd[0] = 0;
14234 :
14235 0 : std::string s = find_cookie_mg(msg, "midas_pwd");
14236 0 : if (s.length() > 0) {
14237 0 : mstrlcpy(cookie_pwd, s.c_str(), sizeof(cookie_pwd));
14238 0 : cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
14239 : }
14240 :
14241 0 : s = find_cookie_mg(msg, "midas_wpwd");
14242 0 : if (s.length()) {
14243 0 : mstrlcpy(cookie_wpwd, s.c_str(), sizeof(cookie_pwd));
14244 0 : cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
14245 : }
14246 :
14247 0 : s = find_cookie_mg(msg, "cpwd");
14248 0 : if (s.length()) {
14249 0 : mstrlcpy(cookie_cpwd, s.c_str(), sizeof(cookie_pwd));
14250 0 : cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
14251 : }
14252 :
14253 : // extract refresh rate
14254 0 : c->refresh = DEFAULT_REFRESH;
14255 0 : s = find_cookie_mg(msg, "midas_refr");
14256 0 : if (s.length() > 0)
14257 0 : c->refresh = atoi(s.c_str());
14258 :
14259 : // extract equipment expand flag
14260 : //c->expand_equipment = 0;
14261 : //s = find_cookie_mg(msg, "midas_expeq");
14262 : //if (s.length() > 0)
14263 : // c->expand_equipment = atoi(s.c_str());
14264 :
14265 0 : c->cookie_pwd = cookie_pwd;
14266 0 : c->cookie_wpwd = cookie_wpwd;
14267 0 : c->cookie_cpwd = cookie_cpwd;
14268 0 : }
14269 :
14270 : #define RESPONSE_SENT 1
14271 : #define RESPONSE_QUEUED 2
14272 : #define RESPONSE_501 3
14273 :
14274 0 : static int handle_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14275 : {
14276 0 : Cookies cookies;
14277 :
14278 0 : decode_cookies(&cookies, msg);
14279 :
14280 : // lock shared structures
14281 :
14282 : #ifdef HAVE_MONGOOSE6
14283 0 : int status = ss_mutex_wait_for(request_mutex, 0);
14284 0 : assert(status == SS_SUCCESS);
14285 : #endif
14286 :
14287 : //t->fTimeLocked = GetTimeSec();
14288 :
14289 : // prepare return buffer
14290 :
14291 0 : Return *rr = new Return();
14292 :
14293 0 : rr->zero();
14294 :
14295 : // call midas
14296 :
14297 0 : decode_get(rr, NULL, &cookies, uri, query_string, t);
14298 :
14299 0 : if (trace_mg)
14300 0 : printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14301 :
14302 0 : t->fTimeProcessed = GetTimeSec();
14303 :
14304 0 : if (rr->return_length == -1) {
14305 0 : delete rr;
14306 : #ifdef HAVE_MONGOOSE6
14307 : //t->fTimeUnlocked = GetTimeSec();
14308 0 : ss_mutex_release(request_mutex);
14309 : #endif
14310 0 : return RESPONSE_501;
14311 : }
14312 :
14313 0 : if (rr->return_length == 0)
14314 0 : rr->return_length = strlen(rr->return_buffer);
14315 :
14316 : //t->fTimeUnlocked = GetTimeSec();
14317 :
14318 : #ifdef HAVE_MONGOOSE6
14319 0 : ss_mutex_release(request_mutex);
14320 : #endif
14321 :
14322 0 : mg_send(nc, rr->return_buffer, rr->return_length);
14323 :
14324 0 : if (!strstr(rr->return_buffer, "Content-Length")) {
14325 : // cannot do pipelined http if response generated by mhttpd
14326 : // decode_get() has no Content-Length header.
14327 : // must close the connection.
14328 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
14329 : }
14330 :
14331 0 : t->fTimeSent = GetTimeSec();
14332 :
14333 0 : delete rr;
14334 :
14335 0 : return RESPONSE_SENT;
14336 0 : }
14337 :
14338 : #ifdef HAVE_MONGOOSE616
14339 :
14340 : static uint32_t s_ncseqno = 1;
14341 :
14342 : struct MongooseNcUserData
14343 : {
14344 : uint32_t ncseqno = 0;
14345 :
14346 0 : MongooseNcUserData() // ctor
14347 0 : {
14348 0 : ncseqno = s_ncseqno++;
14349 : //printf("MongooseNcUserData::ctor! ncseqno %d\n", ncseqno);
14350 0 : }
14351 :
14352 0 : ~MongooseNcUserData() // ctor
14353 : {
14354 : //printf("MongooseNcUserData::dtor! ncseqno %d\n", ncseqno);
14355 0 : }
14356 : };
14357 :
14358 0 : static uint32_t GetNcSeqno(const mg_connection* nc)
14359 : {
14360 0 : if (nc == NULL)
14361 0 : return 0;
14362 0 : if (nc->user_data == NULL)
14363 0 : return 0;
14364 0 : const MongooseNcUserData* ncud = (const MongooseNcUserData*)nc->user_data;
14365 0 : return ncud->ncseqno;
14366 : }
14367 :
14368 : static uint32_t s_wseqno = 1;
14369 :
14370 : struct MongooseWorkObject
14371 : {
14372 : uint32_t wseqno = 0;
14373 : mg_connection* nc = NULL;
14374 : uint32_t wncseqno = 0;
14375 : bool http_get = false;
14376 : bool http_post = false;
14377 : bool mjsonrpc = false;
14378 : Cookies cookies;
14379 : std::string origin;
14380 : std::string uri;
14381 : std::string query_string;
14382 : std::string post_body;
14383 : std::string post_boundary;
14384 : RequestTrace* t = NULL;
14385 : bool send_done = false;
14386 :
14387 0 : MongooseWorkObject(mg_connection* xnc) // ctor
14388 0 : {
14389 0 : wseqno = s_wseqno++;
14390 0 : nc = xnc;
14391 0 : wncseqno = GetNcSeqno(nc);
14392 :
14393 : //printf("MongooseWorkObject::ctor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14394 0 : }
14395 :
14396 0 : ~MongooseWorkObject() // dtor
14397 : {
14398 : //printf("MongooseWorkObject::dtor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14399 :
14400 : // poison pointers
14401 0 : nc = NULL;
14402 0 : t = NULL;
14403 0 : }
14404 : };
14405 :
14406 : struct MongooseThreadObject
14407 : {
14408 : std::atomic_bool fIsRunning{false};
14409 : std::thread* fThread = NULL; // thread
14410 : void* fNc = NULL; // thread is attached to this network connection
14411 : std::mutex fMutex;
14412 : std::deque<MongooseWorkObject*> fQueue;
14413 : std::condition_variable fNotify;
14414 :
14415 : //MongooseThreadObject() // ctor
14416 : //{
14417 : // printf("MongooseThreadObject %p created!\n", this);
14418 : //}
14419 :
14420 : //~MongooseThreadObject() // dtor
14421 : //{
14422 : // printf("MongooseThreadObject %p destroyed!\n", this);
14423 : //}
14424 : };
14425 :
14426 : static std::vector<MongooseThreadObject*> gMongooseThreads;
14427 :
14428 : static void mongoose_thread(MongooseThreadObject*);
14429 :
14430 0 : MongooseThreadObject* FindThread(void* nc)
14431 : {
14432 : //printf("FindThread: nc %p, thread %s\n", nc, ss_tid_to_string(ss_gettid()).c_str());
14433 :
14434 0 : MongooseThreadObject* last_not_connected = NULL;
14435 :
14436 0 : for (auto it : gMongooseThreads) {
14437 0 : MongooseThreadObject* to = it;
14438 0 : if (to->fNc == nc) {
14439 : //printf("to %p, nc %p: found thread\n", to, nc);
14440 0 : return to;
14441 : }
14442 0 : if (to->fNc == NULL) {
14443 0 : last_not_connected = to;
14444 : }
14445 : }
14446 :
14447 0 : if (last_not_connected) {
14448 0 : MongooseThreadObject* to = last_not_connected;
14449 0 : to->fNc = nc;
14450 : //printf("to %p, nc %p: reusing thread\n", to, nc);
14451 0 : return to;
14452 : }
14453 :
14454 0 : MongooseThreadObject* to = new MongooseThreadObject();
14455 :
14456 0 : to->fNc = nc;
14457 :
14458 : //printf("to %p, nc %p: new thread\n", to, nc);
14459 :
14460 0 : gMongooseThreads.push_back(to);
14461 :
14462 0 : printf("Mongoose web server is using %d threads \r", (int)gMongooseThreads.size());
14463 0 : fflush(stdout);
14464 :
14465 0 : to->fThread = new std::thread(mongoose_thread, to);
14466 :
14467 0 : return to;
14468 : }
14469 :
14470 0 : void FreeThread(void* nc)
14471 : {
14472 : //printf("FreeThread, nc %p\n", nc);
14473 :
14474 0 : for (auto it : gMongooseThreads) {
14475 0 : MongooseThreadObject* to = it;
14476 0 : if (to->fNc == nc) {
14477 : //printf("to %p, nc %p: connection closed\n", to, nc);
14478 0 : to->fNc = NULL;
14479 0 : return;
14480 : }
14481 : }
14482 :
14483 : //printf("to %p, nc %p: connection closed, but no thread\n", nullptr, nc);
14484 : }
14485 :
14486 0 : static void mongoose_queue(mg_connection* nc, MongooseWorkObject* w)
14487 : {
14488 0 : w->nc = nc;
14489 0 : MongooseThreadObject* to = FindThread(nc);
14490 0 : assert(to->fNc == nc);
14491 0 : to->fMutex.lock();
14492 0 : to->fQueue.push_back(w);
14493 0 : to->fMutex.unlock();
14494 0 : to->fNotify.notify_one();
14495 0 : }
14496 :
14497 : static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag = false);
14498 :
14499 0 : static int queue_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14500 : {
14501 0 : MongooseWorkObject* w = new MongooseWorkObject(nc);
14502 0 : w->http_get = true;
14503 0 : decode_cookies(&w->cookies, msg);
14504 0 : w->uri = uri;
14505 0 : w->query_string = query_string;
14506 0 : w->t = t;
14507 :
14508 0 : mongoose_queue(nc, w);
14509 :
14510 0 : return RESPONSE_QUEUED;
14511 : }
14512 :
14513 0 : static int queue_decode_post(struct mg_connection *nc, const http_message* msg, const char* boundary, const char* uri, const char* query_string, RequestTrace* t)
14514 : {
14515 0 : MongooseWorkObject* w = new MongooseWorkObject(nc);
14516 0 : w->http_post = true;
14517 0 : decode_cookies(&w->cookies, msg);
14518 0 : w->uri = uri;
14519 0 : w->query_string = query_string;
14520 0 : w->post_body = mgstr(&msg->body);
14521 0 : w->post_boundary = boundary;
14522 0 : w->t = t;
14523 :
14524 0 : mongoose_queue(nc, w);
14525 :
14526 0 : return RESPONSE_QUEUED;
14527 : }
14528 :
14529 0 : static int queue_mjsonrpc(struct mg_connection *nc, const std::string& origin, const std::string& post_body, RequestTrace* t)
14530 : {
14531 0 : MongooseWorkObject* w = new MongooseWorkObject(nc);
14532 0 : w->mjsonrpc = true;
14533 0 : w->origin = origin;
14534 0 : w->post_body = post_body;
14535 0 : w->t = t;
14536 :
14537 0 : mongoose_queue(nc, w);
14538 :
14539 0 : return RESPONSE_QUEUED;
14540 : }
14541 :
14542 0 : static int thread_http_get(mg_connection *nc, MongooseWorkObject *w)
14543 : {
14544 : // lock shared structures
14545 :
14546 : //int status = ss_mutex_wait_for(request_mutex, 0);
14547 : //assert(status == SS_SUCCESS);
14548 :
14549 : //w->t->fTimeLocked = GetTimeSec();
14550 :
14551 : // prepare return buffer
14552 :
14553 0 : Return *rr = new Return();
14554 :
14555 0 : rr->zero();
14556 :
14557 : // call midas
14558 :
14559 0 : decode_get(rr, NULL, &w->cookies, w->uri.c_str(), w->query_string.c_str(), w->t);
14560 :
14561 0 : if (trace_mg)
14562 0 : printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14563 :
14564 0 : w->t->fTimeProcessed = GetTimeSec();
14565 :
14566 0 : if (rr->return_length == -1) {
14567 0 : delete rr;
14568 : //w->t->fTimeUnlocked = GetTimeSec();
14569 : //ss_mutex_release(request_mutex);
14570 0 : return RESPONSE_501;
14571 : }
14572 :
14573 0 : if (rr->return_length == 0)
14574 0 : rr->return_length = strlen(rr->return_buffer);
14575 :
14576 : //w->t->fTimeUnlocked = GetTimeSec();
14577 :
14578 : //ss_mutex_release(request_mutex);
14579 :
14580 0 : bool close_flag = false;
14581 :
14582 0 : if (!strstr(rr->return_buffer, "Content-Length")) {
14583 : // cannot do pipelined http if response generated by mhttpd
14584 : // decode_get() has no Content-Length header.
14585 : // must close the connection.
14586 0 : close_flag = true;
14587 : }
14588 :
14589 0 : mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14590 :
14591 0 : w->t->fTimeSent = GetTimeSec();
14592 :
14593 0 : delete rr;
14594 :
14595 0 : return RESPONSE_SENT;
14596 : }
14597 :
14598 0 : static int thread_http_post(mg_connection *nc, MongooseWorkObject *w)
14599 : {
14600 0 : const char* post_data = w->post_body.c_str();
14601 0 : int post_data_len = w->post_body.length();
14602 :
14603 : // lock shared strctures
14604 :
14605 : //int status = ss_mutex_wait_for(request_mutex, 0);
14606 : //assert(status == SS_SUCCESS);
14607 :
14608 : // prepare return buffer
14609 :
14610 0 : Return* rr = new Return;
14611 :
14612 0 : rr->zero();
14613 :
14614 : //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14615 :
14616 0 : decode_post(rr, NULL, (char*)post_data, w->post_boundary.c_str(), post_data_len, &w->cookies, w->uri.c_str(), w->t);
14617 :
14618 0 : if (trace_mg)
14619 0 : printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14620 :
14621 0 : if (rr->return_length == -1) {
14622 : //ss_mutex_release(request_mutex);
14623 0 : delete rr;
14624 0 : return RESPONSE_501;
14625 : }
14626 :
14627 0 : if (rr->return_length == 0)
14628 0 : rr->return_length = strlen(rr->return_buffer);
14629 :
14630 : //ss_mutex_release(request_mutex);
14631 :
14632 0 : bool close_flag = false;
14633 0 : if (!strstr(rr->return_buffer, "Content-Length")) {
14634 : // cannot do pipelined http if response generated by mhttpd
14635 : // decode_get() has no Content-Length header.
14636 : // must close the connection.
14637 0 : close_flag = true;
14638 : }
14639 :
14640 0 : mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14641 :
14642 0 : delete rr;
14643 :
14644 0 : return RESPONSE_SENT;
14645 :
14646 : }
14647 :
14648 0 : static int thread_mjsonrpc(mg_connection *nc, MongooseWorkObject *w)
14649 : {
14650 0 : w->t->fRPC = w->post_body;
14651 :
14652 : //int status = ss_mutex_wait_for(request_mutex, 0);
14653 : //assert(status == SS_SUCCESS);
14654 :
14655 : //gMutex.lock();
14656 : //w->t->fTimeLocked = GetTimeSec();
14657 :
14658 0 : MJsonNode* reply = mjsonrpc_decode_post_data(w->post_body.c_str());
14659 :
14660 : //w->t->fTimeUnlocked = GetTimeSec();
14661 : //gMutex.unlock();
14662 :
14663 : //ss_mutex_release(request_mutex);
14664 :
14665 0 : if (reply->GetType() == MJSON_ARRAYBUFFER) {
14666 : const char* ptr;
14667 : size_t size;
14668 0 : reply->GetArrayBuffer(&ptr, &size);
14669 :
14670 0 : std::string headers;
14671 0 : headers += "HTTP/1.1 200 OK\n";
14672 0 : if (w->origin.length() > 0)
14673 0 : headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14674 : else
14675 0 : headers += "Access-Control-Allow-Origin: *\n";
14676 0 : headers += "Access-Control-Allow-Credentials: true\n";
14677 0 : headers += "Content-Length: " + toString(size) + "\n";
14678 0 : headers += "Content-Type: application/octet-stream\n";
14679 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14680 :
14681 : //printf("sending headers: %s\n", headers.c_str());
14682 : //printf("sending reply: %s\n", reply_string.c_str());
14683 :
14684 0 : std::string send = headers + "\n";
14685 :
14686 0 : w->t->fTimeProcessed = GetTimeSec();
14687 :
14688 0 : mongoose_send(nc, w, send.c_str(), send.length(), ptr, size);
14689 :
14690 0 : w->t->fTimeSent = GetTimeSec();
14691 :
14692 0 : delete reply;
14693 :
14694 0 : return RESPONSE_SENT;
14695 0 : }
14696 :
14697 0 : std::string reply_string = reply->Stringify();
14698 0 : int reply_length = reply_string.length();
14699 :
14700 0 : std::string headers;
14701 0 : headers += "HTTP/1.1 200 OK\n";
14702 0 : if (w->origin.length() > 0)
14703 0 : headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14704 : else
14705 0 : headers += "Access-Control-Allow-Origin: *\n";
14706 0 : headers += "Access-Control-Allow-Credentials: true\n";
14707 0 : headers += "Content-Length: " + toString(reply_length) + "\n";
14708 0 : headers += "Content-Type: application/json\n";
14709 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14710 :
14711 0 : if (trace_mg_verbose) {
14712 0 : printf("-----------------------\nSending headers: %s", headers.c_str());
14713 0 : std::string r = reply_string.substr(0, 128);
14714 0 : printf("-----------------------\nSending reply (%d bytes): %s\n\n\n", (int)reply_string.size(), r.c_str());
14715 0 : }
14716 :
14717 0 : std::string send = headers + "\n" + reply_string;
14718 :
14719 0 : w->t->fTimeProcessed = GetTimeSec();
14720 :
14721 0 : mongoose_send(nc, w, send.c_str(), send.length(), NULL, 0);
14722 :
14723 0 : w->t->fTimeSent = GetTimeSec();
14724 :
14725 0 : delete reply;
14726 :
14727 0 : return RESPONSE_SENT;
14728 0 : }
14729 :
14730 0 : static int thread_work_function(mg_connection *nc, MongooseWorkObject *w)
14731 : {
14732 0 : if (w->http_get)
14733 0 : return thread_http_get(nc, w);
14734 0 : else if (w->http_post)
14735 0 : return thread_http_post(nc, w);
14736 0 : else if (w->mjsonrpc)
14737 0 : return thread_mjsonrpc(nc, w);
14738 : else
14739 0 : return RESPONSE_501;
14740 : }
14741 :
14742 : #endif
14743 :
14744 0 : static int handle_decode_post(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14745 : {
14746 :
14747 : char boundary[256];
14748 0 : boundary[0] = 0;
14749 0 : const std::string ct = find_header_mg(msg, "Content-Type");
14750 0 : if (ct.length() > 0) {
14751 0 : const char* s = strstr(ct.c_str(), "boundary=");
14752 0 : if (s)
14753 0 : mstrlcpy(boundary, s+9, sizeof(boundary));
14754 : }
14755 :
14756 : #ifdef HAVE_MONGOOSE616
14757 0 : if (multithread_mg)
14758 0 : return queue_decode_post(nc, msg, boundary, uri, query_string, t);
14759 : #endif
14760 :
14761 0 : Cookies cookies;
14762 :
14763 0 : decode_cookies(&cookies, msg);
14764 :
14765 0 : const char* post_data = msg->body.p;
14766 0 : int post_data_len = msg->body.len;
14767 :
14768 : // lock shared strctures
14769 :
14770 : #ifdef HAVE_MONGOOSE6
14771 0 : int status = ss_mutex_wait_for(request_mutex, 0);
14772 0 : assert(status == SS_SUCCESS);
14773 : #endif
14774 :
14775 : // prepare return buffer
14776 :
14777 0 : Return* rr = new Return;
14778 :
14779 0 : rr->zero();
14780 :
14781 : //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14782 :
14783 0 : decode_post(rr, NULL, (char*)post_data, boundary, post_data_len, &cookies, uri, t);
14784 :
14785 0 : if (trace_mg)
14786 0 : printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14787 :
14788 0 : if (rr->return_length == -1) {
14789 : #ifdef HAVE_MONGOOSE6
14790 0 : ss_mutex_release(request_mutex);
14791 : #endif
14792 0 : delete rr;
14793 0 : return RESPONSE_501;
14794 : }
14795 :
14796 0 : if (rr->return_length == 0)
14797 0 : rr->return_length = strlen(rr->return_buffer);
14798 :
14799 : #ifdef HAVE_MONGOOSE6
14800 0 : ss_mutex_release(request_mutex);
14801 : #endif
14802 :
14803 0 : mg_send(nc, rr->return_buffer, rr->return_length);
14804 :
14805 0 : if (!strstr(rr->return_buffer, "Content-Length")) {
14806 : // cannot do pipelined http if response generated by mhttpd
14807 : // decode_get() has no Content-Length header.
14808 : // must close the connection.
14809 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
14810 : }
14811 :
14812 0 : delete rr;
14813 :
14814 0 : return RESPONSE_SENT;
14815 0 : }
14816 :
14817 0 : static int handle_http_get(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14818 : {
14819 0 : std::string query_string = mgstr(&msg->query_string);
14820 :
14821 0 : if (trace_mg||verbose_mg)
14822 0 : printf("handle_http_get: uri [%s], query [%s]\n", uri, query_string.c_str());
14823 :
14824 0 : if (query_string == "mjsonrpc_schema") {
14825 0 : MJsonNode* s = mjsonrpc_get_schema();
14826 0 : std::string reply = s->Stringify();
14827 0 : delete s;
14828 :
14829 0 : int reply_length = reply.length();
14830 :
14831 0 : const std::string origin_header = find_header_mg(msg, "Origin");
14832 :
14833 0 : std::string headers;
14834 0 : headers += "HTTP/1.1 200 OK\n";
14835 0 : if (origin_header.length() > 0)
14836 0 : headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14837 : else
14838 0 : headers += "Access-Control-Allow-Origin: *\n";
14839 0 : headers += "Access-Control-Allow-Credentials: true\n";
14840 0 : headers += "Content-Length: " + toString(reply_length) + "\n";
14841 0 : headers += "Content-Type: application/json\n";
14842 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14843 :
14844 : //printf("sending headers: %s\n", headers.c_str());
14845 : //printf("sending reply: %s\n", reply.c_str());
14846 :
14847 0 : std::string send = headers + "\n" + reply;
14848 :
14849 0 : t->fTimeProcessed = GetTimeSec();
14850 :
14851 0 : mg_send(nc, send.c_str(), send.length());
14852 :
14853 0 : t->fTimeSent = GetTimeSec();
14854 :
14855 0 : return RESPONSE_SENT;
14856 0 : }
14857 :
14858 0 : if (query_string == "mjsonrpc_schema_text") {
14859 0 : MJsonNode* s = mjsonrpc_get_schema();
14860 0 : std::string reply = mjsonrpc_schema_to_text(s);
14861 0 : delete s;
14862 :
14863 0 : int reply_length = reply.length();
14864 :
14865 0 : const std::string origin_header = find_header_mg(msg, "Origin");
14866 :
14867 0 : std::string headers;
14868 0 : headers += "HTTP/1.1 200 OK\n";
14869 0 : if (origin_header.length() > 0)
14870 0 : headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14871 : else
14872 0 : headers += "Access-Control-Allow-Origin: *\n";
14873 0 : headers += "Access-Control-Allow-Credentials: true\n";
14874 0 : headers += "Content-Length: " + toString(reply_length) + "\n";
14875 0 : headers += "Content-Type: text/plain\n";
14876 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14877 :
14878 : //printf("sending headers: %s\n", headers.c_str());
14879 : //printf("sending reply: %s\n", reply.c_str());
14880 :
14881 0 : std::string send = headers + "\n" + reply;
14882 :
14883 0 : t->fTimeProcessed = GetTimeSec();
14884 :
14885 0 : mg_send(nc, send.c_str(), send.length());
14886 :
14887 0 : t->fTimeSent = GetTimeSec();
14888 :
14889 0 : return RESPONSE_SENT;
14890 0 : }
14891 :
14892 : #ifdef HAVE_MONGOOSE616
14893 0 : if (multithread_mg)
14894 0 : return queue_decode_get(nc, msg, uri, query_string.c_str(), t);
14895 : #endif
14896 :
14897 0 : return handle_decode_get(nc, msg, uri, query_string.c_str(), t);
14898 0 : }
14899 :
14900 0 : static int handle_http_post(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14901 : {
14902 0 : std::string query_string = mgstr(&msg->query_string);
14903 0 : std::string post_data = mgstr(&msg->body);
14904 :
14905 0 : if (trace_mg||verbose_mg)
14906 0 : printf("handle_http_post: uri [%s], query [%s], post data %d bytes\n", uri, query_string.c_str(), (int)post_data.length());
14907 0 : if (trace_mg_verbose)
14908 0 : printf("handle_http_post: post data = \n%s\n", post_data.c_str());
14909 :
14910 0 : if (query_string.substr(0, 8) == "mjsonrpc") { // ignore any parameter after "mjsonrpc"
14911 0 : const std::string origin_header = find_header_mg(msg, "Origin");
14912 0 : const std::string ctype_header = find_header_mg(msg, "Content-Type");
14913 :
14914 0 : if (strstr(ctype_header.c_str(), "application/json") == NULL) {
14915 0 : std::string headers;
14916 0 : headers += "HTTP/1.1 415 Unsupported Media Type\n";
14917 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14918 :
14919 : //printf("sending headers: %s\n", headers.c_str());
14920 : //printf("sending reply: %s\n", reply.c_str());
14921 :
14922 0 : if (trace_mg_verbose)
14923 0 : printf("handle_http_post: unsupported media type \"%s\"\n", ctype_header.c_str());
14924 :
14925 0 : std::string send = headers + "\n";
14926 :
14927 0 : t->fTimeProcessed = GetTimeSec();
14928 :
14929 0 : mg_send(nc, send.c_str(), send.length());
14930 :
14931 0 : t->fTimeSent = GetTimeSec();
14932 :
14933 0 : return RESPONSE_SENT;
14934 0 : }
14935 :
14936 : #ifdef HAVE_MONGOOSE616
14937 0 : if (multithread_mg)
14938 0 : return queue_mjsonrpc(nc, origin_header, post_data, t);
14939 : #endif
14940 :
14941 : //printf("post body: %s\n", post_data.c_str());
14942 :
14943 0 : t->fRPC = post_data;
14944 :
14945 : #ifdef HAVE_MONGOOSE6
14946 0 : int status = ss_mutex_wait_for(request_mutex, 0);
14947 0 : assert(status == SS_SUCCESS);
14948 : #endif
14949 :
14950 : //t->fTimeLocked = GetTimeSec();
14951 :
14952 0 : MJsonNode* reply = mjsonrpc_decode_post_data(post_data.c_str());
14953 :
14954 : //t->fTimeUnlocked = GetTimeSec();
14955 :
14956 : #ifdef HAVE_MONGOOSE6
14957 0 : ss_mutex_release(request_mutex);
14958 : #endif
14959 :
14960 0 : if (reply->GetType() == MJSON_ARRAYBUFFER) {
14961 : const char* ptr;
14962 : size_t size;
14963 0 : reply->GetArrayBuffer(&ptr, &size);
14964 :
14965 0 : std::string headers;
14966 0 : headers += "HTTP/1.1 200 OK\n";
14967 0 : if (origin_header.length() > 0)
14968 0 : headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14969 : else
14970 0 : headers += "Access-Control-Allow-Origin: *\n";
14971 0 : headers += "Access-Control-Allow-Credentials: true\n";
14972 0 : headers += "Content-Length: " + toString(size) + "\n";
14973 0 : headers += "Content-Type: application/octet-stream\n";
14974 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14975 :
14976 : //printf("sending headers: %s\n", headers.c_str());
14977 : //printf("sending reply: %s\n", reply_string.c_str());
14978 :
14979 0 : std::string send = headers + "\n";
14980 :
14981 0 : t->fTimeProcessed = GetTimeSec();
14982 :
14983 0 : mg_send(nc, send.c_str(), send.length());
14984 0 : mg_send(nc, ptr, size);
14985 :
14986 0 : t->fTimeSent = GetTimeSec();
14987 :
14988 0 : delete reply;
14989 :
14990 0 : return RESPONSE_SENT;
14991 0 : }
14992 :
14993 0 : std::string reply_string = reply->Stringify();
14994 0 : int reply_length = reply_string.length();
14995 :
14996 0 : std::string headers;
14997 0 : headers += "HTTP/1.1 200 OK\n";
14998 0 : if (origin_header.length() > 0)
14999 0 : headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
15000 : else
15001 0 : headers += "Access-Control-Allow-Origin: *\n";
15002 0 : headers += "Access-Control-Allow-Credentials: true\n";
15003 0 : headers += "Content-Length: " + toString(reply_length) + "\n";
15004 0 : headers += "Content-Type: application/json\n";
15005 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15006 :
15007 : //printf("sending headers: %s\n", headers.c_str());
15008 : //printf("sending reply: %s\n", reply_string.c_str());
15009 :
15010 0 : std::string send = headers + "\n" + reply_string;
15011 :
15012 0 : t->fTimeProcessed = GetTimeSec();
15013 :
15014 0 : mg_send(nc, send.c_str(), send.length());
15015 :
15016 0 : t->fTimeSent = GetTimeSec();
15017 :
15018 0 : delete reply;
15019 :
15020 0 : return RESPONSE_SENT;
15021 0 : }
15022 :
15023 0 : return handle_decode_post(nc, msg, uri, query_string.c_str(), t);
15024 0 : }
15025 :
15026 0 : static void handle_http_options_cors(struct mg_connection *nc, const http_message* msg, RequestTrace* t)
15027 : {
15028 : //
15029 : // JSON-RPC CORS pre-flight request, see
15030 : // https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
15031 : //
15032 : // OPTIONS /resources/post-here/ HTTP/1.1
15033 : // Host: bar.other
15034 : // User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
15035 : // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
15036 : // Accept-Language: en-us,en;q=0.5
15037 : // Accept-Encoding: gzip,deflate
15038 : // Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
15039 : // Connection: keep-alive
15040 : // Origin: http://foo.example
15041 : // Access-Control-Request-Method: POST
15042 : // Access-Control-Request-Headers: X-PINGOTHER
15043 : //
15044 : // HTTP/1.1 200 OK
15045 : // Date: Mon, 01 Dec 2008 01:15:39 GMT
15046 : // Server: Apache/2.0.61 (Unix)
15047 : // Access-Control-Allow-Origin: http://foo.example
15048 : // Access-Control-Allow-Methods: POST, GET, OPTIONS
15049 : // Access-Control-Allow-Headers: X-PINGOTHER
15050 : // Access-Control-Max-Age: 1728000
15051 : // Vary: Accept-Encoding, Origin
15052 : // Content-Encoding: gzip
15053 : // Content-Length: 0
15054 : // Keep-Alive: timeout=2, max=100
15055 : // Connection: Keep-Alive
15056 : // Content-Type: text/plain
15057 : //
15058 :
15059 0 : const std::string origin_header = find_header_mg(msg, "Origin");
15060 :
15061 0 : if (trace_mg||verbose_mg)
15062 0 : printf("handle_http_options_cors: origin [%s]\n", origin_header.c_str());
15063 :
15064 0 : std::string headers;
15065 0 : headers += "HTTP/1.1 200 OK\n";
15066 : //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15067 0 : if (origin_header.length() > 0)
15068 0 : headers += "Access-Control-Allow-Origin: " + origin_header + "\n";
15069 : else
15070 0 : headers += "Access-Control-Allow-Origin: *\n";
15071 0 : headers += "Access-Control-Allow-Headers: Content-Type\n";
15072 0 : headers += "Access-Control-Allow-Credentials: true\n";
15073 0 : headers += "Access-Control-Max-Age: 120\n";
15074 0 : headers += "Content-Length: 0\n";
15075 0 : headers += "Content-Type: text/plain\n";
15076 : //printf("sending headers: %s\n", headers.c_str());
15077 : //printf("sending reply: %s\n", reply.c_str());
15078 :
15079 0 : std::string send = headers + "\n";
15080 :
15081 0 : t->fTimeProcessed = GetTimeSec();
15082 :
15083 0 : mg_send(nc, send.c_str(), send.length());
15084 :
15085 0 : t->fTimeSent = GetTimeSec();
15086 0 : }
15087 :
15088 : // HTTP event handler
15089 :
15090 : static bool mongoose_passwords_enabled(const struct mg_connection *nc);
15091 :
15092 : #ifdef HAVE_MONGOOSE616
15093 : static MVOdb* gProxyOdb = NULL;
15094 : #endif
15095 :
15096 0 : static void handle_http_message(struct mg_connection *nc, http_message* msg)
15097 : {
15098 0 : std::string method = mgstr(&msg->method);
15099 0 : std::string query_string = mgstr(&msg->query_string);
15100 0 : std::string uri_encoded = mgstr(&msg->uri);
15101 0 : std::string uri = UrlDecode(uri_encoded.c_str());
15102 :
15103 0 : if (trace_mg)
15104 0 : printf("handle_http_message: method [%s] uri [%s] proto [%s]\n", method.c_str(), uri.c_str(), mgstr(&msg->proto).c_str());
15105 :
15106 0 : RequestTrace* t = new RequestTrace;
15107 0 : t->fTimeReceived = GetTimeSec();
15108 0 : t->fMethod = method;
15109 0 : t->fUri = uri;
15110 0 : t->fQuery = query_string;
15111 :
15112 : // process OPTIONS for Cross-origin (CORS) preflight request
15113 : // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
15114 0 : if (method == "OPTIONS" && query_string == "mjsonrpc" && mg_get_http_header(msg, "Access-Control-Request-Method") != NULL) {
15115 0 : handle_http_options_cors(nc, msg, t);
15116 0 : t->fCompleted = true;
15117 0 : gTraceBuf->AddTraceMTS(t);
15118 0 : return;
15119 : }
15120 :
15121 0 : if (gAuthMg && mongoose_passwords_enabled(nc)) {
15122 0 : std::string username = check_digest_auth(msg, gAuthMg);
15123 :
15124 : // Cannot re-read the password file - it is not thread safe to do so
15125 : // unless I lock gAuthMg for each call check_digest_auth() and if I do so,
15126 : // I will serialize (single-thread) all the http requests and defeat
15127 : // the whole point of multithreading the web server. K.O.
15128 : //
15129 : //// if auth failed, reread password file - maybe user added or password changed
15130 : //if (username.length() < 1) {
15131 : // bool ok = read_passwords(&gAuthMg);
15132 : // if (ok)
15133 : // username = check_digest_auth(msg, &gAuthMg);
15134 : //}
15135 :
15136 0 : if (trace_mg)
15137 0 : printf("handle_http_message: auth user: \"%s\"\n", username.c_str());
15138 :
15139 0 : if (username.length() == 0) {
15140 0 : if (trace_mg||verbose_mg)
15141 0 : printf("handle_http_message: method [%s] uri [%s] query [%s] proto [%s], sending auth request for realm \"%s\"\n", method.c_str(), uri.c_str(), query_string.c_str(), mgstr(&msg->proto).c_str(), gAuthMg->realm.c_str());
15142 :
15143 0 : xmg_http_send_digest_auth_request(nc, gAuthMg->realm.c_str());
15144 0 : t->fCompleted = true;
15145 0 : gTraceBuf->AddTraceMTS(t);
15146 0 : return;
15147 : }
15148 0 : t->fAuthOk = true;
15149 0 : } else {
15150 0 : t->fAuthOk = true;
15151 : }
15152 :
15153 : #ifdef HAVE_MONGOOSE616
15154 0 : if (gProxyOdb && starts_with(uri, "/proxy/")) {
15155 0 : std::string::size_type p1 = uri.find("/", 1);
15156 0 : if (p1 == uri.length()-1) {
15157 0 : std::string response = "404 Not Found (Proxy name is missing)";
15158 0 : mg_send_head(nc, 404, response.length(), NULL);
15159 0 : mg_send(nc, response.c_str(), response.length());
15160 0 : delete t;
15161 0 : return;
15162 0 : }
15163 0 : std::string::size_type p2 = uri.find("/", p1+1);
15164 0 : if (p2 == std::string::npos) {
15165 0 : std::string response = "404 Not Found (Proxy URL should end with a slash)";
15166 0 : mg_send_head(nc, 404, response.length(), NULL);
15167 0 : mg_send(nc, response.c_str(), response.length());
15168 0 : delete t;
15169 0 : return;
15170 0 : }
15171 0 : std::string p = uri.substr(p1+1, p2-p1-1);
15172 : //printf("uri [%s], p1: %d, p2: %d, substr: [%s]\n", uri.c_str(), (int)p1, (int)p2, p.c_str());
15173 0 : if (p.length() < 1) {
15174 0 : std::string response = "404 Not Found (Double-slash or Proxy name is too short)";
15175 0 : mg_send_head(nc, 404, response.length(), NULL);
15176 0 : mg_send(nc, response.c_str(), response.length());
15177 0 : delete t;
15178 0 : return;
15179 0 : }
15180 0 : std::string destination;
15181 0 : gProxyOdb->RS(p.c_str(), &destination);
15182 0 : if (destination.length() < 1) {
15183 0 : std::string response = "404 Not Found (Proxy not found in ODB)";
15184 0 : mg_send_head(nc, 404, response.length(), NULL);
15185 0 : mg_send(nc, response.c_str(), response.length());
15186 0 : delete t;
15187 0 : return;
15188 0 : } else if (destination[0] == '#') {
15189 0 : std::string response = "404 Not Found (Proxy commented-out in ODB)";
15190 0 : mg_send_head(nc, 404, response.length(), NULL);
15191 0 : mg_send(nc, response.c_str(), response.length());
15192 0 : delete t;
15193 0 : return;
15194 0 : } else if (ends_with_char(destination, '/')) {
15195 0 : std::string response = "404 Not Found (Proxy address should not end with a slash)";
15196 0 : mg_send_head(nc, 404, response.length(), NULL);
15197 0 : mg_send(nc, response.c_str(), response.length());
15198 0 : delete t;
15199 0 : return;
15200 0 : } else if (!starts_with(destination, "http")) {
15201 0 : std::string response = "404 Not Found (Proxy address does not start with http";
15202 0 : mg_send_head(nc, 404, response.length(), NULL);
15203 0 : mg_send(nc, response.c_str(), response.length());
15204 0 : delete t;
15205 0 : return;
15206 0 : } else {
15207 0 : std::string m;
15208 0 : m += "/proxy";
15209 0 : m += "/";
15210 0 : m += p;
15211 0 : mg_str mount = mg_mk_str(m.c_str());
15212 0 : mg_str upstream = mg_mk_str(destination.c_str());
15213 0 : if (verbose_mg||trace_mg) {
15214 0 : printf("proxy: uri [%s] mount [%s] upstream [%s]\n", uri.c_str(), mgstr(&mount).c_str(), mgstr(&upstream).c_str());
15215 : }
15216 0 : mg_http_reverse_proxy(nc, msg, mount, upstream);
15217 0 : delete t;
15218 0 : return;
15219 0 : }
15220 0 : }
15221 : #endif
15222 :
15223 0 : int response = RESPONSE_501;
15224 :
15225 0 : if (method == "GET")
15226 0 : response = handle_http_get(nc, msg, uri.c_str(), t);
15227 0 : else if (method == "POST")
15228 0 : response = handle_http_post(nc, msg, uri.c_str(), t);
15229 :
15230 0 : if (response == RESPONSE_501) {
15231 0 : if (trace_mg||verbose_mg)
15232 0 : printf("handle_http_message: sending 501 Not Implemented error\n");
15233 :
15234 0 : std::string response = "501 Not Implemented";
15235 0 : mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15236 0 : mg_send(nc, response.c_str(), response.length());
15237 0 : }
15238 :
15239 0 : if (response != RESPONSE_QUEUED) {
15240 0 : t->fCompleted = true;
15241 0 : gTraceBuf->AddTraceMTS(t);
15242 : }
15243 0 : }
15244 :
15245 : #ifdef HAVE_MONGOOSE6
15246 :
15247 0 : static void handle_http_event_mg(struct mg_connection *nc, int ev, void *ev_data)
15248 : {
15249 0 : switch (ev) {
15250 0 : case MG_EV_HTTP_REQUEST:
15251 0 : if (trace_mg)
15252 0 : printf("handle_http_event_mg: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15253 0 : handle_http_message(nc, (http_message*)ev_data);
15254 0 : break;
15255 0 : default:
15256 0 : if (trace_mg)
15257 0 : printf("handle_http_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15258 0 : break;
15259 : }
15260 0 : }
15261 :
15262 0 : static void handle_http_redirect(struct mg_connection *nc, int ev, void *ev_data)
15263 : {
15264 0 : switch (ev) {
15265 0 : case MG_EV_HTTP_REQUEST:
15266 : {
15267 0 : http_message* msg = (http_message*)ev_data;
15268 0 : if (trace_mg)
15269 0 : printf("handle_http_redirect: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15270 :
15271 0 : mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: https://%s%s\r\n\r\n",
15272 0 : ((std::string*)(nc->user_data))->c_str(),
15273 0 : mgstr(&msg->uri).c_str());
15274 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
15275 : }
15276 0 : break;
15277 0 : default:
15278 0 : if (trace_mg)
15279 0 : printf("handle_http_redirect: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15280 : }
15281 0 : }
15282 :
15283 : #endif
15284 :
15285 : #ifdef HAVE_MONGOOSE616
15286 :
15287 : // from mongoose examples/multithreaded/multithreaded.c
15288 :
15289 : //static sock_t s_sock[2];
15290 : static std::atomic_bool s_shutdown{false};
15291 : static struct mg_mgr s_mgr;
15292 : static std::atomic_int s_rseqno{1};
15293 : static std::mutex s_mg_broadcast_mutex;
15294 :
15295 : #if 0
15296 : // This info is passed to the worker thread
15297 : struct work_request {
15298 : void* nc;
15299 : MongooseWorkObject* w;
15300 : };
15301 : #endif
15302 :
15303 : // This info is passed by the worker thread to mg_broadcast
15304 : struct work_result {
15305 : mg_connection* nc = NULL;
15306 : uint32_t check = 0x12345678;
15307 : int rseqno = 0;
15308 : MongooseWorkObject* w = NULL;
15309 : const char* p1 = NULL;
15310 : size_t s1 = 0;
15311 : const char* p2 = NULL;
15312 : size_t s2 = 0;
15313 : bool close_flag = false;
15314 : bool send_501 = false;
15315 : };
15316 :
15317 : #if 0
15318 : static void mongoose_queue(void *nc, MongooseWorkObject *w)
15319 : {
15320 : struct work_request req = {nc, w};
15321 :
15322 : //printf("nc: %p: wseqno: %d, queue work object!\n", nc, w->wseqno);
15323 :
15324 : if (write(s_sock[0], &req, sizeof(req)) < 0) {
15325 : fprintf(stderr, "mongoose_queue: Error: write(s_sock(0)) error %d (%s)\n", errno, strerror(errno));
15326 : abort();
15327 : }
15328 : }
15329 : #endif
15330 :
15331 0 : static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data)
15332 : {
15333 : (void) ev;
15334 0 : struct work_result *res = (struct work_result *)ev_data;
15335 :
15336 0 : assert(res != NULL);
15337 0 : assert(res->w != NULL);
15338 :
15339 : //printf("nc: %p, ncseqno: %d, wseqno: %d, rseqno: %d, check 0x%08x, offered nc %p ncseqno %d, flags 0x%08x\n", res->nc, GetNcSeqno(res->nc), res->w->wseqno, res->rseqno, res->check, nc, GetNcSeqno(nc), (int)nc->flags);
15340 :
15341 : // check for correct connection, note that nc objects are reused and after a socket is closed
15342 : // and a new one is opened, the same nc address and the same nc->sock can now refer to a completely
15343 : // different tcp connection. So we check ncseqno instead of nc. K.O.
15344 :
15345 : //if (res->nc != nc)
15346 : //return;
15347 :
15348 0 : if (GetNcSeqno(nc) != res->w->wncseqno)
15349 0 : return;
15350 :
15351 : //printf("nc: %p, ncseqno: %d, wseqno: %d, wncseqno %d, on_work_complete: rseqno: %d, send_501: %d, s1 %d, s2: %d, close_flag: %d\n", res->nc, GetNcSeqno(nc), res->w->wseqno, res->w->wncseqno, res->rseqno, res->send_501, (int)res->s1, (int)res->s2, res->close_flag);
15352 :
15353 0 : if (res->send_501) {
15354 0 : std::string response = "501 Not Implemented";
15355 0 : mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15356 0 : mg_send(nc, response.c_str(), response.length());
15357 0 : }
15358 :
15359 0 : if (res->s1 > 0)
15360 0 : mg_send(nc, res->p1, res->s1);
15361 :
15362 0 : if (res->s2 > 0)
15363 0 : mg_send(nc, res->p2, res->s2);
15364 :
15365 0 : if (res->close_flag) {
15366 : // cannot do pipelined http if response generated by mhttpd
15367 : // decode_get() has no Content-Length header.
15368 : // must close the connection.
15369 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
15370 : }
15371 :
15372 0 : res->w->send_done = true;
15373 : }
15374 :
15375 0 : static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag)
15376 : {
15377 : //printf("nc: %p: send %d and %d\n", nc, (int)s1, (int)s2);
15378 0 : struct work_result res;
15379 0 : res.nc = nc;
15380 0 : res.w = w;
15381 0 : res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15382 0 : res.p1 = p1;
15383 0 : res.s1 = s1;
15384 0 : res.p2 = p2;
15385 0 : res.s2 = s2;
15386 0 : res.close_flag = close_flag;
15387 0 : res.send_501 = false;
15388 : //printf("nc: %p: call mg_broadcast()\n", nc);
15389 :
15390 : // NB: mg_broadcast() is advertised as thread-safe, but it is not.
15391 : //
15392 : // in mongoose 6.16, mg_brodacast() and mg_mgr_handle_ctl_sock() have several problems:
15393 : //
15394 : // a) "wrong thread" read from mgr->ctl[0], defeating the handshake
15395 : //
15396 : // b) "lost messages". if more than one message is written to mgr->ctl[0], the second message
15397 : // will be "eaten" by mg_mgr_handle_ctl_sock() because of mistatch between number of bytes read and written
15398 : // in the two functions. mg_mgr_handle_ctl_sock() always reads about 8000 bytes while mg_broadcast()
15399 : // writes 8 bytes per message, (per examples/multithreaded/multithreaded.c. mhttpd messages are a bit longer).
15400 : // So if multiple messages are present in the msg->ctl[0] pipe, the read call (of about 8000 bytes)
15401 : // in mg_mgr_handle_ctl_sock() will return several messages (last message may be truncated)
15402 : // but only the first message will be processed by the code. any additional messages are ignored.
15403 : //
15404 : // Problems (a) and (b) are easy to fix by using a mutex to serialize mg_broadcast().
15405 : //
15406 : // c) if the mg_broadcast() message contains pointers to the data buffer to be sent out,
15407 : // the caller of mg_broadcast() should not free these data buffers until mg_send() is called
15408 : // in "on_work_complete()". In theory, the caller of mg_broadcast() could wait until on_work_complete()
15409 : // sets a "done" flag. In practice, if the corresponding network connection is closed before
15410 : // mg_mgr_handle_ctl_sock() has looped over it, on_work_complete() will never run
15411 : // and the "done" flag will never be set. (Of course, network connections are permitted to close
15412 : // at any time without warning, but) the firefox browser closes the network connections "a lot"
15413 : // especially when user pressed the "page reload" button at the moment when HTTP transations
15414 : // are "in flight". (google-chrome tends to permit these "lame duck" transactions to complete and mongoose
15415 : // does not see unexpected socket closures, at least not as many).
15416 : //
15417 : // To fix problem (c) I need to know when mg_mgr_handle_ctl_sock()'s loop over network connections
15418 : // has completed (two cases: (a) my on_work_complete() was hopefully called and finished,
15419 : // and (b) the "right" network connection was already closed (for whatever reason) and my on_work_complete()
15420 : // was never called).
15421 : //
15422 : // My solution is to change the handshake between mg_broadcast() and mg_mgr_handle_ctl_sock() by sending
15423 : // the handshake reply after looping over the network connections instead of after reading the message
15424 : // from msg->ctl[1].
15425 : //
15426 : // This requires a modification to the code in mongoose.c. If this change is lost/undone, nothing will work.
15427 : //
15428 :
15429 0 : s_mg_broadcast_mutex.lock();
15430 0 : mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15431 0 : s_mg_broadcast_mutex.unlock();
15432 0 : }
15433 :
15434 0 : static void mongoose_send_501(mg_connection* nc, MongooseWorkObject* w)
15435 : {
15436 0 : struct work_result res;
15437 0 : res.nc = nc;
15438 0 : res.w = w;
15439 0 : res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15440 0 : res.p1 = 0;
15441 0 : res.s1 = 0;
15442 0 : res.p2 = 0;
15443 0 : res.s2 = 0;
15444 0 : res.close_flag = false;
15445 0 : res.send_501 = true;
15446 : //printf("nc: %p, call mg_broadcast()\n", nc);
15447 :
15448 0 : s_mg_broadcast_mutex.lock();
15449 0 : mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15450 0 : s_mg_broadcast_mutex.unlock();
15451 0 : }
15452 :
15453 : #if 0
15454 : void *worker_thread_proc(void *param)
15455 : {
15456 : //struct mg_mgr *mgr = (struct mg_mgr *) param;
15457 : struct work_request req = {0};
15458 :
15459 : while ((! _abort) && (! s_shutdown)) {
15460 : int rd = read(s_sock[1], &req, sizeof(req));
15461 : if (rd == 0) {
15462 : // socket closed, shutdown the thread
15463 : break;
15464 : }
15465 : if (rd < 0) {
15466 : if (_abort || s_shutdown) {
15467 : return NULL;
15468 : }
15469 : fprintf(stderr, "worker_thread_proc: Error: read(s_sock(1)) returned %d, error %d (%s)\n", rd, errno, strerror(errno));
15470 : abort();
15471 : return NULL;
15472 : }
15473 :
15474 : //printf("nc: %p: received request!\n", req.nc);
15475 :
15476 : int response = thread_work_function(req.nc, req.w);
15477 :
15478 : if (response == RESPONSE_501) {
15479 : if (trace_mg||verbose_mg)
15480 : printf("handle_http_message: sending 501 Not Implemented error\n");
15481 : mongoose_send_501(req.nc, req.w);
15482 : }
15483 :
15484 : req.w->t->fCompleted = true;
15485 : gTraceBuf->AddTraceMTS(req.w->t);
15486 :
15487 : //printf("nc: %p: wseqno: %d, delete work object!\n", req.nc, req.w->wseqno);
15488 :
15489 : delete req.w;
15490 : req.w = NULL;
15491 : }
15492 : return NULL;
15493 : }
15494 : #endif
15495 :
15496 0 : static void mongoose_thread(MongooseThreadObject* to)
15497 : {
15498 : //printf("to %p, nc %p: thread %p started!\n", to, to->fNc, to->fThread);
15499 :
15500 0 : std::unique_lock<std::mutex> ulm(to->fMutex, std::defer_lock);
15501 :
15502 0 : to->fIsRunning = true;
15503 :
15504 0 : while ((! _abort) && (! s_shutdown)) {
15505 0 : MongooseWorkObject *w = NULL;
15506 :
15507 0 : ulm.lock();
15508 0 : while (to->fQueue.empty()) {
15509 : //printf("to %p, nc %p, thread %p: waiting!\n", to, to->fNc, to->fThread);
15510 0 : to->fNotify.wait(ulm);
15511 0 : if (_abort || s_shutdown) {
15512 0 : break;
15513 : }
15514 : }
15515 :
15516 0 : if (_abort || s_shutdown) {
15517 0 : break;
15518 : }
15519 :
15520 0 : w = to->fQueue.front();
15521 0 : to->fQueue.pop_front();
15522 0 : ulm.unlock();
15523 :
15524 : //printf("to %p, nc %p: wseqno: %d, received request!\n", to, w->nc, w->wseqno);
15525 :
15526 0 : int response = thread_work_function(w->nc, w);
15527 :
15528 0 : if (response == RESPONSE_501) {
15529 0 : if (trace_mg||verbose_mg)
15530 0 : printf("handle_http_message: sending 501 Not Implemented error\n");
15531 0 : mongoose_send_501(w->nc, w);
15532 : }
15533 :
15534 : // mg_broadcast() called on_work_complete() on the main thread and waited until it finished
15535 :
15536 0 : if (!w->send_done) {
15537 : // NB: careful here, if connection nc was closed, pointer nc points to nowhere! do not dereference it!
15538 : // NB: stay quiet about it, nothing special about network connctions closing and opening as they wish.
15539 : //printf("to %p, nc %p: wseqno: %d, wncseqno: %d, request was not sent, maybe nc was closed while we were thinking\n", to, w->nc, w->wseqno, w->wncseqno);
15540 : }
15541 :
15542 0 : w->t->fCompleted = true;
15543 0 : gTraceBuf->AddTraceMTS(w->t);
15544 :
15545 : //printf("nc: %p: wseqno: %d, delete work object!\n", w->nc, w->wseqno);
15546 :
15547 0 : delete w;
15548 : }
15549 :
15550 0 : to->fIsRunning = false;
15551 :
15552 : //printf("to %p, nc %p: thread %p finished!\n", to, to->fNc, to->fThread);
15553 0 : }
15554 :
15555 : static bool mongoose_hostlist_enabled(const struct mg_connection *nc);
15556 :
15557 0 : static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
15558 : {
15559 : (void) nc;
15560 : (void) ev_data;
15561 :
15562 : //if (trace_mg && ev != 0) {
15563 : // printf("ev_handler: connection %p, event %d\n", nc, ev);
15564 : //}
15565 :
15566 0 : switch (ev) {
15567 0 : case 0:
15568 0 : break;
15569 0 : default: {
15570 0 : if (trace_mg) {
15571 0 : printf("ev_handler: connection %p, event %d\n", nc, ev);
15572 : }
15573 0 : break;
15574 : }
15575 0 : case MG_EV_ACCEPT:
15576 0 : assert(nc->user_data == NULL);
15577 0 : nc->user_data = new MongooseNcUserData();
15578 :
15579 0 : if (trace_mg) {
15580 0 : printf("ev_handler: connection %p, MG_EV_ACCEPT, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15581 : }
15582 0 : if (s_shutdown) {
15583 : //printf("XXX nc %p!\n", nc);
15584 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15585 0 : } else if (mongoose_hostlist_enabled(nc)) {
15586 0 : if (!mongoose_check_hostlist(&nc->sa)) {
15587 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15588 : }
15589 : }
15590 0 : break;
15591 0 : case MG_EV_RECV:
15592 0 : if (trace_mg_recv) {
15593 0 : printf("ev_handler: connection %p, MG_EV_RECV, %d bytes\n", nc, *(int*)ev_data);
15594 : }
15595 0 : if (s_shutdown) {
15596 : //printf("RRR nc %p!\n", nc);
15597 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15598 : }
15599 0 : break;
15600 0 : case MG_EV_SEND:
15601 0 : if (trace_mg_send) {
15602 0 : printf("ev_handler: connection %p, MG_EV_SEND, %d bytes\n", nc, *(int*)ev_data);
15603 : }
15604 0 : break;
15605 0 : case MG_EV_HTTP_CHUNK: {
15606 0 : if (trace_mg) {
15607 0 : printf("ev_handler: connection %p, MG_EV_HTTP_CHUNK\n", nc);
15608 : }
15609 0 : if (s_shutdown) {
15610 : //printf("RRR1 nc %p!\n", nc);
15611 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15612 : }
15613 0 : break;
15614 : }
15615 0 : case MG_EV_HTTP_REQUEST: {
15616 0 : struct http_message* msg = (struct http_message*)ev_data;
15617 0 : if (trace_mg) {
15618 0 : printf("ev_handler: connection %p, MG_EV_HTTP_REQUEST \"%s\" \"%s\"\n", nc, mgstr(&msg->method).c_str(), mgstr(&msg->uri).c_str());
15619 : }
15620 0 : if (s_shutdown) {
15621 : //printf("RRR2 nc %p!\n", nc);
15622 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15623 : } else {
15624 0 : handle_http_message(nc, msg);
15625 : }
15626 0 : break;
15627 : }
15628 0 : case MG_EV_CLOSE: {
15629 0 : if (trace_mg) {
15630 0 : printf("ev_handler: connection %p, MG_EV_CLOSE, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15631 : }
15632 : //printf("CCC nc %p!\n", nc);
15633 0 : FreeThread(nc);
15634 0 : if (nc->user_data) {
15635 0 : MongooseNcUserData* ncud = (MongooseNcUserData*)nc->user_data;
15636 0 : nc->user_data = NULL;
15637 0 : delete ncud;
15638 0 : ncud = NULL;
15639 : }
15640 : }
15641 : }
15642 0 : }
15643 :
15644 : #define FLAG_HTTPS MG_F_USER_1
15645 : #define FLAG_PASSWORDS MG_F_USER_2
15646 : #define FLAG_HOSTLIST MG_F_USER_3
15647 :
15648 0 : static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15649 : {
15650 0 : int flags = 0;
15651 0 : if (nc && nc->listener) {
15652 0 : flags = nc->listener->flags;
15653 : }
15654 : //printf("mongoose_passwords_enabled: nc %p, listener %p, flags 0x%lx, user_data %p, flags 0x%x\n", nc, nc->listener, nc->listener->flags, nc->listener->user_data, flags);
15655 0 : return flags & FLAG_PASSWORDS;
15656 : }
15657 :
15658 0 : static bool mongoose_hostlist_enabled(const struct mg_connection *nc)
15659 : {
15660 0 : int flags = 0;
15661 0 : if (nc && nc->listener) {
15662 0 : flags = nc->listener->flags;
15663 : }
15664 : //printf("mongoose_hostlist_enabled: nc %p, listener %p, flags 0x%lx, user_data %p, flags 0x%x\n", nc, nc->listener, nc->listener->flags, nc->listener->user_data, flags);
15665 0 : return flags & FLAG_HOSTLIST;
15666 : }
15667 :
15668 0 : static int mongoose_listen(const char* address, int flags)
15669 : {
15670 : #if MG_ENABLE_SSL
15671 : #else
15672 0 : if (flags & FLAG_HTTPS) {
15673 0 : cm_msg(MERROR, "mongoose_listen", "https port \"%s\" requested, but mhttpd compiled without MG_ENABLE_SSL", address);
15674 0 : return SS_SOCKET_ERROR;
15675 : }
15676 : #endif
15677 :
15678 0 : struct mg_connection *nc = mg_bind(&s_mgr, address, ev_handler);
15679 0 : if (nc == NULL) {
15680 0 : cm_msg(MERROR, "mongoose_listen", "Cannot mg_bind address \"%s\"", address);
15681 0 : return SS_SOCKET_ERROR;
15682 : }
15683 :
15684 0 : if (flags & FLAG_HTTPS) {
15685 : #if MG_ENABLE_SSL
15686 : std::string cert_file;
15687 :
15688 : int status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
15689 :
15690 : if (status != SUCCESS) {
15691 : cm_msg(MERROR, "mongoose_listen", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
15692 : cm_msg(MERROR, "mongoose_listen", "please create SSL certificate file using openssl: cd $MIDASSYS; openssl req -new -nodes -newkey rsa:2048 -sha256 -out ssl_cert.csr -keyout ssl_cert.key -subj \"/C=/ST=/L=/O=midas/OU=mhttpd/CN=localhost\"; openssl x509 -req -days 365 -sha256 -in ssl_cert.csr -signkey ssl_cert.key -out ssl_cert.pem; cat ssl_cert.key >> ssl_cert.pem");
15693 : cm_msg(MERROR, "mongoose_listen", "or using certbot (recommened): setup certbot per Let's Encrypt instructions, certificates are typically saved in /etc/letsencrypt/live/$HOSTNAME/, copy fullchain.pem and privkey.pem to $MIDASSYS; cd $MIDASSYS; cat fullchain.pem privkey.pem > ssl_cert.pem");
15694 : return SS_FILE_ERROR;
15695 : }
15696 :
15697 : printf("Mongoose web server will use https certificate file \"%s\"\n", cert_file.c_str());
15698 :
15699 : const char* errmsg = mg_set_ssl(nc, cert_file.c_str(), NULL);
15700 : if (errmsg) {
15701 : cm_msg(MERROR, "mongoose_listen", "Cannot enable https with certificate file \"%s\", error: %s", cert_file.c_str(), errmsg);
15702 : return SS_SOCKET_ERROR;
15703 : }
15704 :
15705 : // NB: where is the warning that the SSL certificate has expired?!? K.O.
15706 : #else
15707 0 : abort(); // cannot happen!
15708 : #endif
15709 : }
15710 :
15711 0 : mg_set_protocol_http_websocket(nc);
15712 :
15713 0 : nc->flags |= flags;
15714 :
15715 0 : printf("Listening on \"%s://%s\", passwords %s, hostlist %s\n", (flags&FLAG_HTTPS)?"https":"http", address, (flags&FLAG_PASSWORDS)?"enabled":"OFF", (flags&FLAG_HOSTLIST)?"enabled":"OFF");
15716 :
15717 0 : return SUCCESS;
15718 : }
15719 :
15720 0 : static int mongoose_init(MVOdb* odb, bool no_passwords, bool no_hostlist, const std::vector<std::string>& user_hostlist)
15721 : {
15722 0 : bool enable_localhost_port = true;
15723 0 : int localhost_port = 8080;
15724 0 : bool localhost_port_passwords = false;
15725 :
15726 0 : bool enable_insecure_port = false;
15727 0 : int insecure_port = 8081;
15728 0 : bool insecure_port_passwords = true;
15729 0 : bool insecure_port_hostlist = true;
15730 :
15731 0 : bool enable_https_port = false;
15732 0 : int https_port = 8443;
15733 0 : bool https_port_passwords = true;
15734 0 : bool https_port_hostlist = false;
15735 :
15736 0 : std::vector<std::string> hostlist;
15737 0 : hostlist.push_back("localhost");
15738 :
15739 0 : bool enable_ipv6 = true;
15740 :
15741 0 : odb->RB("Enable localhost port", &enable_localhost_port, true);
15742 0 : odb->RI("localhost port", &localhost_port, true);
15743 0 : odb->RB("localhost port passwords", &localhost_port_passwords, true);
15744 0 : odb->RB("Enable insecure port", &enable_insecure_port, true);
15745 0 : odb->RI("insecure port", &insecure_port, true);
15746 0 : odb->RB("insecure port passwords", &insecure_port_passwords, true);
15747 0 : odb->RB("insecure port host list", &insecure_port_hostlist, true);
15748 0 : odb->RB("Enable https port", &enable_https_port, true);
15749 0 : odb->RI("https port", &https_port, true);
15750 0 : odb->RB("https port passwords", &https_port_passwords, true);
15751 0 : odb->RB("https port host list", &https_port_hostlist, true);
15752 0 : odb->RSA("Host list", &hostlist, true, 10, 256);
15753 0 : odb->RB("Enable IPv6", &enable_ipv6, true);
15754 :
15755 : // populate the MIME.types table
15756 0 : gProxyOdb = odb->Chdir("Proxy", true);
15757 0 : std::string proxy_example = "#http://localhost:8080";
15758 0 : gProxyOdb->RS("example", &proxy_example, true);
15759 :
15760 : // populate the MIME.types table
15761 0 : SaveMimetypes(odb->Chdir("mime.types", true));
15762 :
15763 0 : if (!no_passwords
15764 0 : && ((enable_localhost_port && localhost_port_passwords)
15765 0 : || (enable_insecure_port && insecure_port_passwords)
15766 0 : || (enable_https_port && https_port_passwords))) {
15767 0 : gAuthMg = new Auth();
15768 0 : int status = gAuthMg->Init();
15769 0 : if (status != SUCCESS) {
15770 0 : printf("mongoose_init: Error: Cannot initialize authorization object!\n");
15771 0 : return status;
15772 : }
15773 0 : printf("HTTP Digest authentication with realm \"%s\" and password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
15774 0 : } else {
15775 0 : printf("Password protection is off\n");
15776 : }
15777 :
15778 0 : if (!no_hostlist
15779 0 : && ((enable_insecure_port && insecure_port_hostlist)
15780 0 : || (enable_https_port && https_port_hostlist))) {
15781 0 : gAllowedHosts.clear();
15782 :
15783 : // copy the user allowed hosts
15784 0 : for (unsigned int i=0; i<user_hostlist.size(); i++)
15785 0 : gAllowedHosts.push_back(user_hostlist[i]);
15786 :
15787 0 : for (unsigned i=0; i<hostlist.size(); i++) {
15788 0 : std::string s = hostlist[i];
15789 0 : if (s.length() < 1) // skip emties
15790 0 : continue;
15791 :
15792 0 : if (s[0] == '#') // skip commented-out entries
15793 0 : continue;
15794 :
15795 : //printf("add allowed hosts %d [%s]\n", i, s.c_str());
15796 0 : gAllowedHosts.push_back(s);
15797 0 : }
15798 :
15799 0 : printf("Hostlist active, connections will be accepted only from: ");
15800 0 : for (unsigned i=0; i<gAllowedHosts.size(); i++) {
15801 0 : if (i>0)
15802 0 : printf(", ");
15803 0 : printf("%s", gAllowedHosts[i].c_str());
15804 : }
15805 0 : printf("\n");
15806 0 : } else {
15807 0 : printf("Hostlist off, connections from anywhere will be accepted\n");
15808 : }
15809 :
15810 0 : mg_mgr_init(&s_mgr, NULL);
15811 :
15812 0 : bool listen_failed = false;
15813 :
15814 0 : if (enable_localhost_port) {
15815 : char str[256];
15816 0 : sprintf(str, "localhost:%d", localhost_port);
15817 0 : int status = mongoose_listen(str, 0);
15818 0 : if (status != SUCCESS)
15819 0 : listen_failed = true;
15820 0 : if (enable_ipv6) {
15821 0 : sprintf(str, "[::1]:%d", localhost_port);
15822 0 : status = mongoose_listen(str, 0);
15823 0 : if (status != SUCCESS)
15824 0 : listen_failed = true;
15825 : }
15826 : }
15827 :
15828 0 : if (enable_insecure_port) {
15829 : char str[256];
15830 0 : int flags = 0;
15831 0 : if (insecure_port_passwords)
15832 0 : flags |= FLAG_PASSWORDS;
15833 0 : if (insecure_port_hostlist)
15834 0 : flags |= FLAG_HOSTLIST;
15835 0 : if (enable_ipv6) {
15836 0 : sprintf(str, "[::]:%d", insecure_port);
15837 0 : int status = mongoose_listen(str, flags);
15838 0 : if (status != SUCCESS)
15839 0 : listen_failed = true;
15840 : } else {
15841 0 : sprintf(str, "%d", insecure_port);
15842 0 : int status = mongoose_listen(str, flags);
15843 0 : if (status != SUCCESS)
15844 0 : listen_failed = true;
15845 : }
15846 : }
15847 :
15848 0 : if (enable_https_port) {
15849 : char str[256];
15850 0 : int flags = 0;
15851 0 : if (https_port_passwords)
15852 0 : flags |= FLAG_PASSWORDS;
15853 0 : if (https_port_hostlist)
15854 0 : flags |= FLAG_HOSTLIST;
15855 0 : flags |= FLAG_HTTPS;
15856 0 : if (enable_ipv6) {
15857 0 : sprintf(str, "[::]:%d", https_port);
15858 0 : int status = mongoose_listen(str, flags);
15859 0 : if (status != SUCCESS)
15860 0 : listen_failed = true;
15861 : } else {
15862 0 : sprintf(str, "%d", https_port);
15863 0 : int status = mongoose_listen(str, flags);
15864 0 : if (status != SUCCESS)
15865 0 : listen_failed = true;
15866 : }
15867 : }
15868 :
15869 0 : if (listen_failed) {
15870 0 : cm_msg(MERROR, "mongoose_init", "Failed to listen on a TCP port enabled in ODB /WebServer");
15871 0 : return SS_SOCKET_ERROR;
15872 : }
15873 :
15874 0 : return SUCCESS;
15875 0 : }
15876 :
15877 0 : static void mongoose_poll(int msec = 200)
15878 : {
15879 0 : mg_mgr_poll(&s_mgr, msec);
15880 0 : }
15881 :
15882 0 : static void mongoose_cleanup()
15883 : {
15884 0 : printf("Mongoose web server shutting down\n");
15885 :
15886 0 : s_shutdown = true;
15887 :
15888 : // close listener sockets
15889 0 : if (s_mgr.active_connections) {
15890 0 : struct mg_connection* nc = s_mgr.active_connections;
15891 0 : while (nc) {
15892 : //printf("nc %p, next %p, user_data %p, listener %p, flags %lu\n", nc, nc->next, nc->user_data, nc->listener, nc->flags);
15893 0 : if (nc->flags & MG_F_LISTENING) {
15894 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15895 : }
15896 0 : nc = nc->next;
15897 : }
15898 : }
15899 :
15900 : // tell threads to shut down
15901 0 : for (auto it : gMongooseThreads) {
15902 0 : MongooseThreadObject* to = it;
15903 0 : to->fNotify.notify_one();
15904 : }
15905 :
15906 : // wait until all threads stop
15907 0 : for (int i=0; i<10; i++) {
15908 0 : int count_running = 0;
15909 0 : for (auto it : gMongooseThreads) {
15910 0 : MongooseThreadObject* to = it;
15911 : //printf("AAA6C %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15912 0 : if (to->fIsRunning) {
15913 0 : count_running++;
15914 : }
15915 : }
15916 0 : printf("Mongoose web server shutting down, %d threads still running\n", count_running);
15917 0 : if (count_running == 0)
15918 0 : break;
15919 0 : mongoose_poll(1000);
15920 : }
15921 :
15922 : // delete thread objects
15923 0 : for (auto it : gMongooseThreads) {
15924 0 : MongooseThreadObject* to = it;
15925 : //printf("AAA7B %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15926 0 : if (to->fIsRunning) {
15927 0 : cm_msg(MERROR, "mongoose", "thread failed to shut down");
15928 0 : continue;
15929 : }
15930 0 : to->fThread->join();
15931 0 : delete to->fThread;
15932 0 : delete to;
15933 : }
15934 0 : gMongooseThreads.clear();
15935 :
15936 0 : mg_mgr_free(&s_mgr);
15937 :
15938 : //closesocket(s_sock[0]);
15939 : //closesocket(s_sock[1]);
15940 :
15941 : // make leak sanitizer happy!
15942 0 : for (auto e : gHostlistCache) {
15943 0 : delete e;
15944 : }
15945 0 : gHostlistCache.clear();
15946 0 : if (gProxyOdb) {
15947 0 : delete gProxyOdb;
15948 0 : gProxyOdb = NULL;
15949 : }
15950 0 : if (gMimeTypesOdb) {
15951 0 : delete gMimeTypesOdb;
15952 0 : gMimeTypesOdb = NULL;
15953 : }
15954 :
15955 0 : printf("Mongoose web server shut down\n");
15956 0 : }
15957 :
15958 : #endif
15959 :
15960 : #ifdef HAVE_MONGOOSE6
15961 :
15962 0 : static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15963 : {
15964 0 : return true;
15965 : }
15966 :
15967 0 : int start_mg(int user_http_port, int user_https_port, int socket_priviledged_port, int verbose)
15968 : {
15969 : HNDLE hDB;
15970 : int size;
15971 : int status;
15972 :
15973 : //if (verbose)
15974 : // trace_mg = true;
15975 :
15976 0 : if (verbose)
15977 0 : verbose_mg = true;
15978 :
15979 0 : status = cm_get_experiment_database(&hDB, NULL);
15980 0 : assert(status == CM_SUCCESS);
15981 :
15982 0 : int http_port = 8080;
15983 0 : int https_port = 8443;
15984 0 : int http_redirect_to_https = 1;
15985 :
15986 0 : size = sizeof(http_port);
15987 0 : db_get_value(hDB, 0, "/Experiment/midas http port", &http_port, &size, TID_INT, TRUE);
15988 :
15989 0 : size = sizeof(https_port);
15990 0 : db_get_value(hDB, 0, "/Experiment/midas https port", &https_port, &size, TID_INT, TRUE);
15991 :
15992 0 : size = sizeof(http_redirect_to_https);
15993 0 : db_get_value(hDB, 0, "/Experiment/http redirect to https", &http_redirect_to_https, &size, TID_BOOL, TRUE);
15994 :
15995 0 : bool need_cert_file = false;
15996 0 : bool need_password_file = false;
15997 :
15998 0 : if (user_http_port)
15999 0 : http_port = user_http_port;
16000 :
16001 0 : if (user_https_port)
16002 0 : https_port = user_https_port;
16003 :
16004 0 : if (https_port) {
16005 0 : need_cert_file = true;
16006 0 : need_password_file = true;
16007 : }
16008 :
16009 0 : if (!https_port)
16010 0 : http_redirect_to_https = 0;
16011 :
16012 0 : if (http_port && !http_redirect_to_https) {
16013 : // no passwords serving over http unless
16014 : // http is just a redict to https
16015 0 : need_password_file = false;
16016 : }
16017 :
16018 0 : if (socket_priviledged_port >= 0) {
16019 : // no passwords if serving unencrypted http on port 80
16020 0 : need_password_file = false;
16021 0 : printf("Mongoose web server password portection is disabled: serving unencrypted http on port 80\n");
16022 : }
16023 :
16024 0 : bool have_at_least_one_port = false;
16025 :
16026 0 : std::string cert_file;
16027 :
16028 0 : if (need_cert_file) {
16029 0 : status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
16030 :
16031 0 : if (status != SUCCESS) {
16032 0 : cm_msg(MERROR, "mongoose", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
16033 0 : cm_msg(MERROR, "mongoose", "please create SSL certificate file: cd $MIDASSYS; openssl req -new -nodes -newkey rsa:2048 -sha256 -out ssl_cert.csr -keyout ssl_cert.key -subj \"/C=/ST=/L=/O=midas/OU=mhttpd/CN=localhost\"; openssl x509 -req -days 365 -sha256 -in ssl_cert.csr -signkey ssl_cert.key -out ssl_cert.pem; cat ssl_cert.key >> ssl_cert.pem");
16034 0 : return SS_FILE_ERROR;
16035 : }
16036 :
16037 0 : printf("Mongoose web server will use SSL certificate file \"%s\"\n", cert_file.c_str());
16038 : }
16039 :
16040 0 : if (need_password_file) {
16041 0 : gAuthMg = new Auth();
16042 0 : status = gAuthMg->Init();
16043 0 : if (status != SUCCESS) {
16044 0 : printf("Error: Cannot initialize authorization object!\n");
16045 0 : return status;
16046 : }
16047 0 : printf("Mongoose web server will use authentication realm \"%s\", password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
16048 : } else {
16049 0 : printf("Mongoose web server will not use password protection\n");
16050 : }
16051 :
16052 0 : if (trace_mg)
16053 0 : printf("start_mg!\n");
16054 :
16055 : #ifndef OS_WINNT
16056 0 : signal(SIGPIPE, SIG_IGN);
16057 : #endif
16058 :
16059 0 : if (!gTraceBuf) {
16060 0 : gTraceBuf = new RequestTraceBuf;
16061 : }
16062 :
16063 0 : if (!request_mutex) {
16064 0 : status = ss_mutex_create(&request_mutex, FALSE);
16065 0 : assert(status==SS_SUCCESS || status==SS_CREATED);
16066 : }
16067 :
16068 0 : mg_mgr_init(&mgr_mg, NULL);
16069 :
16070 : // use socket bound to priviledged port (setuid-mode)
16071 0 : if (socket_priviledged_port >= 0) {
16072 0 : struct mg_connection* nc = mg_add_sock(&mgr_mg, socket_priviledged_port, handle_event_mg);
16073 0 : if (nc == NULL) {
16074 0 : cm_msg(MERROR, "mongoose", "Cannot create mg_connection for set-uid-root privileged port");
16075 0 : return SS_SOCKET_ERROR;
16076 : }
16077 :
16078 0 : nc->flags |= MG_F_LISTENING;
16079 : #ifdef MG_ENABLE_THREADS
16080 0 : mg_enable_multithreading(nc);
16081 : #endif
16082 0 : mg_set_protocol_http_websocket(nc);
16083 0 : mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16084 :
16085 0 : have_at_least_one_port = true;
16086 0 : printf("mongoose web server is listening on the set-uid-root privileged port\n");
16087 : }
16088 :
16089 0 : if (http_port != 80) { // port 80 is already handled by socket_priviledged_port
16090 : char str[256];
16091 0 : sprintf(str, "%d", http_port);
16092 0 : struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16093 0 : if (nc == NULL) {
16094 0 : cm_msg(MERROR, "mongoose", "Cannot bind to port %d", http_port);
16095 0 : return SS_SOCKET_ERROR;
16096 : }
16097 :
16098 : #ifdef MG_ENABLE_THREADS
16099 0 : mg_enable_multithreading(nc);
16100 : #endif
16101 0 : mg_set_protocol_http_websocket(nc);
16102 :
16103 0 : if (http_redirect_to_https) {
16104 0 : std::string hostname = ss_gethostname();
16105 : char str[256];
16106 0 : sprintf(str, "%d", https_port);
16107 0 : std::string s = hostname + ":" + std::string(str);
16108 0 : nc->user_data = new std::string(s);
16109 0 : mg_register_http_endpoint(nc, "/", handle_http_redirect);
16110 0 : printf("mongoose web server is redirecting HTTP port %d to https://%s\n", http_port, s.c_str());
16111 0 : } else {
16112 0 : mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16113 : }
16114 :
16115 0 : have_at_least_one_port = true;
16116 0 : printf("mongoose web server is listening on the HTTP port %d\n", http_port);
16117 : }
16118 :
16119 0 : if (https_port) {
16120 : #ifdef MG_ENABLE_SSL
16121 : char str[256];
16122 : sprintf(str, "%d", https_port);
16123 : struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16124 : if (nc == NULL) {
16125 : cm_msg(MERROR, "mongoose", "Cannot bind to port %d", https_port);
16126 : return SS_SOCKET_ERROR;
16127 : }
16128 :
16129 : mg_set_ssl(nc, cert_file.c_str(), NULL);
16130 : #ifdef MG_ENABLE_THREADS
16131 : mg_enable_multithreading(nc);
16132 : #endif
16133 : mg_set_protocol_http_websocket(nc);
16134 : mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16135 :
16136 : have_at_least_one_port = true;
16137 : printf("mongoose web server is listening on the HTTPS port %d\n", https_port);
16138 : #else
16139 0 : cm_msg(MERROR, "mongoose", "https port %d requested, but mhttpd compiled without MG_ENABLE_SSL", https_port);
16140 0 : return SS_SOCKET_ERROR;
16141 : #endif
16142 : }
16143 :
16144 0 : if (!have_at_least_one_port) {
16145 0 : cm_msg(MERROR, "mongoose", "cannot start: no ports defined");
16146 0 : return SS_FILE_ERROR;
16147 : }
16148 :
16149 0 : return SUCCESS;
16150 0 : }
16151 :
16152 0 : int stop_mg()
16153 : {
16154 0 : if (trace_mg)
16155 0 : printf("stop_mg!\n");
16156 :
16157 : // Stop the server.
16158 0 : mg_mgr_free(&mgr_mg);
16159 :
16160 0 : if (trace_mg)
16161 0 : printf("stop_mg done!\n");
16162 0 : return SUCCESS;
16163 : }
16164 :
16165 0 : int loop_mg()
16166 : {
16167 0 : int status = SUCCESS;
16168 :
16169 : /* establish Ctrl-C handler - will set _abort to TRUE */
16170 0 : ss_ctrlc_handler(ctrlc_handler);
16171 :
16172 0 : while (!_abort) {
16173 :
16174 : /* cm_yield() is not thread safe, need to take a lock */
16175 :
16176 : #ifdef HAVE_MONGOOSE6
16177 0 : status = ss_mutex_wait_for(request_mutex, 0);
16178 : #endif
16179 0 : gMutex.lock();
16180 :
16181 : /* check for shutdown message */
16182 0 : status = cm_yield(0);
16183 0 : if (status == RPC_SHUTDOWN)
16184 0 : break;
16185 :
16186 0 : gMutex.unlock();
16187 : #ifdef HAVE_MONGOOSE6
16188 0 : status = ss_mutex_release(request_mutex);
16189 : #endif
16190 :
16191 : //ss_sleep(10);
16192 :
16193 0 : mg_mgr_poll(&mgr_mg, 10);
16194 : }
16195 :
16196 0 : return status;
16197 : }
16198 : #endif
16199 :
16200 0 : static MJsonNode* get_http_trace(const MJsonNode* params)
16201 : {
16202 0 : if (!params) {
16203 0 : MJSO *doc = MJSO::I();
16204 0 : doc->D("get current value of mhttpd http_trace");
16205 0 : doc->P(NULL, 0, "there are no input parameters");
16206 0 : doc->R(NULL, MJSON_INT, "current value of http_trace");
16207 0 : return doc;
16208 : }
16209 :
16210 0 : return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16211 : }
16212 :
16213 0 : static MJsonNode* set_http_trace(const MJsonNode* params)
16214 : {
16215 0 : if (!params) {
16216 0 : MJSO* doc = MJSO::I();
16217 0 : doc->D("set new value of mhttpd http_trace");
16218 0 : doc->P(NULL, MJSON_INT, "new value of http_trace");
16219 0 : doc->R(NULL, MJSON_INT, "new value of http_trace");
16220 0 : return doc;
16221 : }
16222 :
16223 0 : http_trace = params->GetInt();
16224 0 : return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16225 : }
16226 :
16227 0 : static void add_rpc_functions()
16228 : {
16229 0 : mjsonrpc_add_handler("set_http_trace", set_http_trace);
16230 0 : mjsonrpc_add_handler("get_http_trace", get_http_trace);
16231 0 : }
16232 :
16233 : /*------------------------------------------------------------------*/
16234 :
16235 0 : int main(int argc, const char *argv[])
16236 : {
16237 : int status;
16238 0 : int daemon = FALSE;
16239 : #ifdef HAVE_MONGOOSE6
16240 0 : int user_http_port = 0;
16241 0 : int user_https_port = 0;
16242 : #endif
16243 : #ifdef HAVE_MONGOOSE616
16244 0 : bool no_passwords = false;
16245 0 : bool no_hostlist = false;
16246 : #endif
16247 0 : const char *myname = "mhttpd";
16248 :
16249 0 : setbuf(stdout, NULL);
16250 0 : setbuf(stderr, NULL);
16251 : #ifdef SIGPIPE
16252 : /* avoid getting killed by "Broken pipe" signals */
16253 0 : signal(SIGPIPE, SIG_IGN);
16254 : #endif
16255 :
16256 : #ifdef HAVE_MONGOOSE6
16257 : //
16258 : // if running setuid-root, unconditionally bind to port 80.
16259 : //
16260 :
16261 0 : int socket_priviledged_port = -1;
16262 :
16263 : #ifdef OS_UNIX
16264 : // in setuid-root mode bind to priviledged port
16265 0 : if (getuid() != geteuid()) {
16266 0 : int port80 = 80;
16267 :
16268 0 : printf("mhttpd is running in setuid-root mode.\n");
16269 :
16270 0 : socket_priviledged_port = open_listening_socket(port80);
16271 0 : if (socket_priviledged_port < 0) {
16272 0 : printf("Cannot open listening socket on TCP port %d, aborting.\n", port80);
16273 0 : exit(1);
16274 : }
16275 :
16276 : // give up root privilege
16277 0 : status = setuid(getuid());
16278 0 : if (status != 0) {
16279 0 : printf("Cannot give up root privelege, aborting.\n");
16280 0 : exit(1);
16281 : }
16282 0 : status = setuid(getuid());
16283 0 : if (status != 0) {
16284 0 : printf("Cannot give up root privelege, aborting.\n");
16285 0 : exit(1);
16286 : }
16287 : }
16288 : #endif
16289 : #endif
16290 :
16291 : char midas_hostname[256];
16292 : char midas_expt[256];
16293 :
16294 : /* get default from environment */
16295 0 : cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
16296 :
16297 : /* parse command line parameters */
16298 : #ifdef HAVE_MONGOOSE6
16299 0 : gUserAllowedHosts.clear();
16300 : #else
16301 0 : std::vector<std::string> user_hostlist;
16302 : #endif
16303 0 : for (int i = 1; i < argc; i++) {
16304 0 : if (argv[i][0] == '-' && argv[i][1] == 'D')
16305 0 : daemon = TRUE;
16306 0 : else if (argv[i][0] == '-' && argv[i][1] == 'v')
16307 0 : verbose = TRUE;
16308 0 : else if (argv[i][0] == '-' && argv[i][1] == 'E')
16309 0 : elog_mode = TRUE;
16310 0 : else if (argv[i][0] == '-' && argv[i][1] == 'H') {
16311 0 : history_mode = TRUE;
16312 : #ifdef HAVE_MONGOOSE6
16313 0 : } else if (strcmp(argv[i], "--http") == 0) {
16314 0 : if (argv[i+1]) {
16315 0 : user_http_port = atoi(argv[i+1]);
16316 : }
16317 0 : } else if (strcmp(argv[i], "--https") == 0) {
16318 0 : if (argv[i+1]) {
16319 0 : user_https_port = atoi(argv[i+1]);
16320 : }
16321 : #endif
16322 0 : } else if (strcmp(argv[i], "--trace-mg") == 0) {
16323 0 : trace_mg = true;
16324 0 : trace_mg_recv = true;
16325 0 : trace_mg_send = true;
16326 0 : } else if (strcmp(argv[i], "--trace-mg-verbose") == 0) {
16327 0 : trace_mg_verbose = true;
16328 0 : } else if (strcmp(argv[i], "--no-trace-mg-recv") == 0) {
16329 0 : trace_mg_recv = false;
16330 0 : } else if (strcmp(argv[i], "--no-trace-mg-send") == 0) {
16331 0 : trace_mg_send = false;
16332 0 : } else if (strcmp(argv[i], "--verbose-mg") == 0) {
16333 0 : verbose_mg = true;
16334 : #ifdef HAVE_MONGOOSE616
16335 0 : } else if (strcmp(argv[i], "--no-multithread") == 0) {
16336 0 : multithread_mg = false;
16337 0 : } else if (strcmp(argv[i], "--no-passwords") == 0) {
16338 0 : no_passwords = true;
16339 0 : } else if (strcmp(argv[i], "--no-hostlist") == 0) {
16340 0 : no_hostlist = true;
16341 : #endif
16342 0 : } else if (argv[i][0] == '-') {
16343 0 : if (i + 1 >= argc || argv[i + 1][0] == '-')
16344 0 : goto usage;
16345 0 : if (argv[i][1] == 'h')
16346 0 : mstrlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
16347 0 : else if (argv[i][1] == 'e')
16348 0 : mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
16349 0 : else if (argv[i][1] == 'a') {
16350 : #ifdef HAVE_MONGOOSE6
16351 0 : gUserAllowedHosts.push_back(argv[++i]);
16352 : #else
16353 0 : user_hostlist.push_back(argv[++i]);
16354 : #endif
16355 0 : } else if (argv[i][1] == 'p') {
16356 0 : printf("Option \"-p port_number\" for the old web server is obsolete.\n");
16357 0 : printf("mongoose web server is the new default, port number is set in ODB or with \"--http port_number\".\n");
16358 0 : printf("To run the obsolete old web server, please use \"--oldserver\" switch.\n");
16359 0 : return 1;
16360 : } else {
16361 0 : usage:
16362 0 : printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-v] [-D] [-a Hostname]\n\n", argv[0]);
16363 0 : printf(" -a add hostname to the hostlist of hosts allowed to connect to mhttpd\n");
16364 0 : printf(" -e experiment to connect to\n");
16365 0 : printf(" -h connect to midas server (mserver) on given host\n");
16366 0 : printf(" -v display verbose HTTP communication\n");
16367 0 : printf(" -D become a daemon\n");
16368 0 : printf(" -E only display ELog system\n");
16369 0 : printf(" -H only display history plots\n");
16370 : #ifdef HAVE_MONGOOSE6
16371 0 : printf(" --http port - bind to specified HTTP port (default is ODB \"/Experiment/midas http port\")\n");
16372 0 : printf(" --https port - bind to specified HTTP port (default is ODB \"/Experiment/midas https port\")\n");
16373 : #endif
16374 0 : printf(" --verbose-mg - trace mongoose web requests\n");
16375 0 : printf(" --trace-mg - trace mongoose events\n");
16376 0 : printf(" --no-trace-mg-recv - do not trace mongoose recv events\n");
16377 0 : printf(" --no-trace-mg-send - dop not trace mongoose send events\n");
16378 : #ifdef HAVE_MONGOOSE616
16379 0 : printf(" --no-multithread - disable mongoose multithreading\n");
16380 0 : printf(" --no-passwords - disable password protection\n");
16381 0 : printf(" --no-hostlist - disable access control host list\n");
16382 : #endif
16383 0 : return 0;
16384 : }
16385 : }
16386 : }
16387 :
16388 0 : if (daemon) {
16389 0 : printf("Becoming a daemon...\n");
16390 0 : ss_daemon_init(FALSE);
16391 : }
16392 :
16393 : #ifdef OS_LINUX
16394 : /* write PID file */
16395 0 : FILE *f = fopen("/var/run/mhttpd.pid", "w");
16396 0 : if (f != NULL) {
16397 0 : fprintf(f, "%d", ss_getpid());
16398 0 : fclose(f);
16399 : }
16400 : #endif
16401 :
16402 0 : if (history_mode)
16403 0 : myname = "mhttpd_history";
16404 :
16405 : /*---- connect to experiment ----*/
16406 0 : status = cm_connect_experiment1(midas_hostname, midas_expt, myname, NULL,
16407 : DEFAULT_ODB_SIZE, DEFAULT_WATCHDOG_TIMEOUT);
16408 0 : if (status == CM_WRONG_PASSWORD)
16409 0 : return 1;
16410 0 : else if (status == DB_INVALID_HANDLE) {
16411 0 : std::string s = cm_get_error(status);
16412 0 : puts(s.c_str());
16413 0 : } else if (status != CM_SUCCESS) {
16414 0 : std::string s = cm_get_error(status);
16415 0 : puts(s.c_str());
16416 0 : return 1;
16417 0 : }
16418 :
16419 : /* mhttpd needs the watchdog thread until we are sure
16420 : * we do not have any long sleeps anywhere in the mhttpd code.
16421 : * this includes reads from the history files or databases,
16422 : * that can take arbitrary long time */
16423 0 : cm_start_watchdog_thread();
16424 :
16425 : /* Get ODB handles */
16426 :
16427 : HNDLE hDB;
16428 :
16429 0 : cm_get_experiment_database(&hDB, NULL);
16430 :
16431 0 : MVOdb *odb = MakeMidasOdb(hDB);
16432 0 : gOdb = odb;
16433 :
16434 : /* do ODB record checking */
16435 0 : if (!check_odb_records(odb)) {
16436 : // check_odb_records() fails with nothing printed to the terminal
16437 : // because mhttpd does not print cm_msg(MERROR, ...) messages to the terminal.
16438 : // At least print something!
16439 0 : printf("check_odb_records() failed, see messages and midas.log, bye!\n");
16440 0 : cm_disconnect_experiment();
16441 0 : return 1;
16442 : }
16443 :
16444 : #ifdef HAVE_MONGOOSE6
16445 0 : if (init_allowed_hosts() != SUCCESS) {
16446 0 : printf("init_allowed_hosts() failed, see messages and midas.log, bye!\n");
16447 0 : cm_disconnect_experiment();
16448 0 : return 1;
16449 : }
16450 :
16451 0 : if (verbose) {
16452 0 : if (gAllowedHosts.size() > 0) {
16453 0 : printf("mhttpd allowed hosts list: ");
16454 0 : for (unsigned int i=0; i<gAllowedHosts.size(); i++) {
16455 0 : if (i>0)
16456 0 : printf(", ");
16457 0 : printf("%s", gAllowedHosts[i].c_str());
16458 : }
16459 0 : printf("\n");
16460 : } else {
16461 0 : printf("mhttpd allowed hosts list is empty\n");
16462 : }
16463 : }
16464 :
16465 : // populate the MIME.types table
16466 0 : SaveMimetypes(odb->Chdir("WebServer/mime.types", true));
16467 : #endif
16468 :
16469 : /* initialize odb entries needed for mhttpd and midas web pages */
16470 0 : init_mhttpd_odb(odb);
16471 :
16472 : /* initialize menu buttons */
16473 0 : init_menu_buttons(odb);
16474 :
16475 : /* initialize elog odb entries */
16476 0 : init_elog_odb();
16477 :
16478 : /* initialize the JSON RPC handlers */
16479 0 : mjsonrpc_init();
16480 0 : mjsonrpc_set_std_mutex(&gMutex);
16481 :
16482 0 : add_rpc_functions();
16483 :
16484 : #ifdef HAVE_MONGOOSE6
16485 0 : status = start_mg(user_http_port, user_https_port, socket_priviledged_port, verbose);
16486 0 : if (status != SUCCESS) {
16487 : // At least print something!
16488 0 : printf("could not start the mongoose web server, see messages and midas.log, bye!\n");
16489 0 : cm_disconnect_experiment();
16490 0 : return 1;
16491 : }
16492 : #endif
16493 :
16494 : #ifdef HAVE_MONGOOSE616
16495 :
16496 : #ifdef SIGPIPE
16497 : #ifdef SIG_IGN
16498 0 : signal(SIGPIPE, SIG_IGN);
16499 : #endif
16500 : #endif
16501 :
16502 0 : if (!gTraceBuf) {
16503 0 : gTraceBuf = new RequestTraceBuf;
16504 : }
16505 :
16506 : //if (!request_mutex) {
16507 : // status = ss_mutex_create(&request_mutex, FALSE);
16508 : // assert(status==SS_SUCCESS || status==SS_CREATED);
16509 : //}
16510 :
16511 : /* establish Ctrl-C handler - will set _abort to TRUE */
16512 0 : ss_ctrlc_handler(ctrlc_handler);
16513 :
16514 0 : MVOdb* o = odb->Chdir("WebServer", true);
16515 0 : status = mongoose_init(o, no_passwords, no_hostlist, user_hostlist);
16516 0 : if (status != SUCCESS) {
16517 : // At least print something!
16518 0 : printf("Error: Could not start the mongoose web server, see messages and midas.log, bye!\n");
16519 0 : cm_disconnect_experiment();
16520 0 : return 1;
16521 : }
16522 :
16523 0 : delete o;
16524 : #endif
16525 :
16526 : #ifdef HAVE_MONGOOSE6
16527 0 : loop_mg();
16528 0 : stop_mg();
16529 : #endif
16530 :
16531 : #ifdef HAVE_MONGOOSE616
16532 0 : while (!_abort) {
16533 :
16534 : /* cm_yield() is not thread safe, need to take a lock */
16535 :
16536 : //status = ss_mutex_wait_for(request_mutex, 0);
16537 0 : gMutex.lock();
16538 :
16539 : /* check for shutdown message */
16540 0 : status = cm_yield(0);
16541 0 : if (status == RPC_SHUTDOWN)
16542 0 : break;
16543 :
16544 0 : gMutex.unlock();
16545 : //status = ss_mutex_release(request_mutex);
16546 :
16547 : //ss_sleep(10);
16548 :
16549 0 : mongoose_poll(10);
16550 : }
16551 :
16552 0 : mongoose_cleanup();
16553 : #endif
16554 :
16555 0 : if (gMh) {
16556 0 : delete gMh;
16557 0 : gMh = NULL;
16558 0 : gMhkey = 0;
16559 : }
16560 :
16561 0 : mjsonrpc_exit();
16562 0 : cm_disconnect_experiment();
16563 0 : return 0;
16564 0 : }
16565 :
16566 : /* emacs
16567 : * Local Variables:
16568 : * tab-width: 8
16569 : * c-basic-offset: 3
16570 : * indent-tabs-mode: nil
16571 : * End:
16572 : */
|