MIDAS
Loading...
Searching...
No Matches
mhttpd.cxx
Go to the documentation of this file.
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
42static MUTEX_T* request_mutex = NULL;
43#endif
44
45static std::mutex gMutex;
46static MVOdb* gOdb = NULL;
47
48/*------------------------------------------------------------------*/
49
50#define MAX_GROUPS 32
51#define MAX_VARS 100
52
53/*------------------------------------------------------------------*/
54
55static std::string toString(int i)
56{
57 char buf[256];
58 sprintf(buf, "%d", i);
59 return buf;
60}
61
62/*------------------------------------------------------------------*/
63
65{
66public:
68 size_t attachment_size[3];
69public:
70 Attachment() // ctor
71 {
72 for (int i=0; i<3; i++) {
74 attachment_size[i] = 0;
75 }
76 }
77 ~Attachment() // dtor
78 {
79 for (int i=0; i<3; i++) {
80 clear(i);
81 }
82 }
83 void clear(int i)
84 {
85 if (attachment_size[i]) {
86 attachment_size[i] = 0;
87 free(attachment_buffer[i]);
89 }
90 }
91};
95
96// month name from midas.c
97extern const char *mname[];
98
99static const char default_type_list[20][NAME_LENGTH] = {
100 "Routine",
101 "Shift summary",
102 "Minor error",
103 "Severe error",
104 "Fix",
105 "Question",
106 "Info",
107 "Modification",
108 "Reply",
109 "Alarm",
110 "Test",
111 "Other"
112};
113
114static const char default_system_list[20][NAME_LENGTH] = {
115 "General",
116 "DAQ",
117 "Detector",
118 "Electronics",
119 "Target",
120 "Beamline"
121};
122
124 std::string ext;
125 std::string mimetype;
126};
127
129 { ".ASC", "text/plain" },
130 { ".CSS", "text/css" },
131 { ".CSV", "text/csv" },
132 { ".HTM", "text/html" },
133 { ".HTML", "text/html" },
134 { ".TXT", "text/plain" },
135
136 { ".BMP", "image/bmp" },
137 { ".GIF", "image/gif" },
138 { ".ICO", "image/x-icon" },
139 { ".JPEG", "image/jpeg" },
140 { ".JPG", "image/jpeg" },
141 { ".PNG", "image/png" },
142 { ".SVG", "image/svg+xml" },
143 { ".TIF", "image/tiff" },
144 { ".TIFF", "image/tiff" },
145
146 { ".MID", "audio/midi" },
147 { ".MP3", "audio/mpeg" },
148 { ".OGA", "audio/ogg" },
149 { ".OGG", "audio/ogg" },
150 { ".WAV", "audio/wav" },
151
152 { ".BIN", "application/octet-stream" },
153 { ".BZ", "application/x-bzip" },
154 { ".BZ2", "application/x-bzip2" },
155 { ".DOC", "application/msword" },
156 { ".EPS", "application/postscript" },
157 { ".GZ", "application/gzip" },
158 { ".JS", "application/javascript" },
159 { ".JSON", "application/json" },
160 { ".MJS", "application/javascript" },
161 { ".PDF", "application/pdf" },
162 { ".PHP", "application/x-httpd-php" },
163 { ".RTF", "application/rtf" },
164 { ".PS", "application/postscript" },
165 { ".ROOT", "application/octet-stream" },
166 { ".XLS", "application/x-msexcel" },
167 { ".XML", "application/xml" },
168 { ".ZIP", "application/zip" },
169
170 { ".ODP", "application/vnd.oasis.opendocument.presentation" },
171 { ".ODS", "application/vnd.oasis.opendocument.spreadsheet" },
172 { ".ODT", "application/vnd.oasis.opendocument.text" },
173
174 { "", "" }
175};
176
178
179static std::string GetMimetype(const std::string& ext)
180{
181 if (gMimeTypesOdb) {
182 std::string mimetype;
183 gMimeTypesOdb->RS(ext.c_str(), &mimetype);
184 if (mimetype.length() > 0) {
185 //printf("GetMimetype: %s -> %s from ODB\n", ext.c_str(), mimetype.c_str());
186 return mimetype;
187 }
188 }
189
190 for (int i=0; gMimetypeTable[i].ext[0]; i++) {
191 if (ext == gMimetypeTable[i].ext) {
192 //printf("GetMimetype: %s -> %s from built-in table\n", ext.c_str(), gMimetypeTable[i].mimetype.c_str());
193 return gMimetypeTable[i].mimetype;
194 }
195 }
196
197 //printf("GetMimetype: %s -> not found\n", ext.c_str());
198 return "";
199}
200
201static void SaveMimetypes(MVOdb* odb)
202{
203 gMimeTypesOdb = odb;
204
205 for (int i=0; gMimetypeTable[i].ext.length() > 0; i++) {
206 std::string tmp = gMimetypeTable[i].mimetype;
207 gMimeTypesOdb->RS(gMimetypeTable[i].ext.c_str(), &tmp, true);
208 }
209}
210
211#define HTTP_ENCODING "UTF-8"
212
213/*------------------------------------------------------------------*/
214
215const unsigned char favicon_png[] = {
216 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
217 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
218 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
219 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x91, 0x68,
220 0x36, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D,
221 0x45, 0x07, 0xD4, 0x0B, 0x1A, 0x08, 0x37, 0x07,
222 0x0D, 0x7F, 0x16, 0x5C, 0x00, 0x00, 0x00, 0x09,
223 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x2E, 0x23,
224 0x00, 0x00, 0x2E, 0x23, 0x01, 0x78, 0xA5, 0x3F,
225 0x76, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D,
226 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61,
227 0x05, 0x00, 0x00, 0x01, 0x7D, 0x49, 0x44, 0x41,
228 0x54, 0x78, 0xDA, 0x63, 0xFC, 0xFF, 0xFF, 0x3F,
229 0x03, 0x29, 0x80, 0x09, 0xAB, 0xE8, 0xD2, 0x65,
230 0x77, 0x36, 0x6F, 0x7E, 0x8A, 0x5D, 0xC7, 0x7F,
231 0x0C, 0x30, 0x67, 0xEE, 0x0D, 0x56, 0xCE, 0xCD,
232 0x5C, 0xBC, 0x3B, 0xB6, 0x6D, 0x7F, 0x81, 0x29,
233 0xCB, 0x88, 0xE6, 0x24, 0x20, 0x57, 0x50, 0x7C,
234 0xDD, 0xCF, 0x1F, 0x6C, 0x40, 0xCB, 0xB5, 0xB5,
235 0x05, 0xCF, 0x1C, 0xB7, 0x42, 0xB3, 0x80, 0x05,
236 0x8D, 0xCF, 0xC8, 0xC8, 0x58, 0x5A, 0x2A, 0xFB,
237 0xF6, 0x4D, 0x37, 0x1B, 0xAB, 0xA0, 0xB4, 0x4C,
238 0x0A, 0x51, 0x4E, 0x02, 0x82, 0x85, 0xCB, 0x12,
239 0x0E, 0x1D, 0xAB, 0xC7, 0x2A, 0xC5, 0x82, 0x69,
240 0xC4, 0xAF, 0x5F, 0x7F, 0x1E, 0x3F, 0xF8, 0xCD,
241 0xCB, 0xF1, 0xF5, 0xEF, 0xDF, 0x7F, 0xCC, 0xCC,
242 0x4C, 0x84, 0x6D, 0x98, 0x59, 0xD5, 0xEB, 0xCF,
243 0xA5, 0x16, 0xC4, 0xAB, 0x71, 0x72, 0xCB, 0x21,
244 0x4C, 0x59, 0x74, 0x03, 0x5E, 0x3F, 0x7F, 0xB3,
245 0x6B, 0xD6, 0x22, 0x46, 0xA6, 0x7F, 0x0C, 0x0C,
246 0x7F, 0xD7, 0x75, 0x4D, 0xFB, 0xF1, 0xFD, 0x27,
247 0x81, 0x78, 0xB8, 0x7D, 0xE9, 0x0A, 0xCB, 0xFF,
248 0xDF, 0x4C, 0x8C, 0x8C, 0x40, 0xF6, 0xAD, 0x4B,
249 0x67, 0x1F, 0xDE, 0xBD, 0x8B, 0x45, 0x03, 0x3C,
250 0x60, 0x8F, 0x9D, 0xD8, 0xB3, 0xEB, 0x74, 0xB5,
251 0x90, 0x26, 0x07, 0x03, 0x48, 0xE4, 0x3F, 0x8F,
252 0xF6, 0xFF, 0x1B, 0x0F, 0x9A, 0x1E, 0x3E, 0x3A,
253 0xFB, 0xF3, 0xDB, 0x8F, 0xB7, 0x0F, 0x9E, 0x43,
254 0x83, 0xF1, 0xCF, 0xDF, 0x3F, 0x8A, 0x29, 0xCE,
255 0x3F, 0x7F, 0xFD, 0xFC, 0xCF, 0xF0, 0xDF, 0x98,
256 0xE9, 0xB5, 0x8F, 0xBD, 0x8A, 0x3C, 0x6F, 0xEC,
257 0xB9, 0x2D, 0x47, 0xFE, 0xFC, 0xFF, 0x6F, 0x16,
258 0x6C, 0xF3, 0xEC, 0xD3, 0x1C, 0x2E, 0x96, 0xEF,
259 0xBF, 0xAB, 0x7E, 0x32, 0x7D, 0xE2, 0x10, 0xCE,
260 0x88, 0xF4, 0x69, 0x2B, 0x60, 0xFC, 0xF4, 0xF5,
261 0x97, 0x78, 0x8A, 0x36, 0xD8, 0x44, 0x86, 0x18,
262 0x0D, 0xD7, 0x29, 0x95, 0x13, 0xD8, 0xD9, 0x58,
263 0xE1, 0x0E, 0xF8, 0xF1, 0xF3, 0xDB, 0xC6, 0xD6,
264 0xEC, 0x5F, 0x53, 0x8E, 0xBF, 0xFE, 0xC3, 0x70,
265 0x93, 0x8D, 0x6D, 0xDA, 0xCB, 0x0B, 0x4C, 0x3F,
266 0xFF, 0xFC, 0xFA, 0xCF, 0x0C, 0xB4, 0x09, 0x84,
267 0x54, 0xD5, 0x74, 0x91, 0x55, 0x03, 0x01, 0x07,
268 0x3B, 0x97, 0x96, 0x6E, 0xC8, 0x17, 0xFE, 0x7F,
269 0x4F, 0xF8, 0xFE, 0xBC, 0x95, 0x16, 0x60, 0x62,
270 0x62, 0x64, 0xE1, 0xE6, 0x60, 0x73, 0xD1, 0xB2,
271 0x7A, 0xFA, 0xE2, 0xF1, 0xDF, 0x3F, 0xFF, 0xC4,
272 0x78, 0x44, 0x31, 0xA3, 0x45, 0x2B, 0xD0, 0xE3,
273 0xF6, 0xD9, 0xE3, 0x2F, 0x2E, 0x9D, 0x29, 0xA9,
274 0xAC, 0x07, 0xA6, 0x03, 0xF4, 0xB4, 0x44, 0x10,
275 0x00, 0x00, 0x75, 0x65, 0x12, 0xB0, 0x49, 0xFF,
276 0x3F, 0x68, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
277 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
278};
279
280const unsigned char favicon_ico[] = {
281 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10,
282 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x28, 0x01,
283 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
284 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00,
285 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x0F,
289 0x0A, 0x00, 0x5C, 0x86, 0x4C, 0x00, 0x2F, 0x5E,
290 0x1A, 0x00, 0xBF, 0xD3, 0xD7, 0x00, 0x29, 0x17,
291 0x8D, 0x00, 0x50, 0xA7, 0xA4, 0x00, 0x59, 0x57,
292 0x7F, 0x00, 0xC6, 0xA3, 0xAC, 0x00, 0xFC, 0xFE,
293 0xFC, 0x00, 0x28, 0x12, 0x53, 0x00, 0x58, 0x7D,
294 0x72, 0x00, 0xC4, 0x3A, 0x34, 0x00, 0x3C, 0x3D,
295 0x69, 0x00, 0xC5, 0xB6, 0xB9, 0x00, 0x94, 0x92,
296 0x87, 0x00, 0x7E, 0x7A, 0xAA, 0x00, 0x88, 0x88,
297 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x81, 0x22,
298 0xD8, 0x88, 0x88, 0x88, 0xF6, 0xD8, 0x82, 0x22,
299 0xE8, 0x88, 0x88, 0x8D, 0x44, 0x98, 0x82, 0x22,
300 0xA8, 0x88, 0x88, 0x8F, 0x44, 0x48, 0x82, 0x22,
301 0x25, 0x76, 0x67, 0x55, 0x44, 0xF8, 0x88, 0x88,
302 0x3A, 0xC9, 0x9C, 0x53, 0x83, 0x88, 0x88, 0x88,
303 0x8D, 0x99, 0x99, 0x38, 0x88, 0x88, 0x88, 0x88,
304 0x88, 0x99, 0x9C, 0x88, 0x88, 0x88, 0x88, 0x88,
305 0x88, 0xF9, 0x9D, 0x88, 0x88, 0x88, 0x88, 0x88,
306 0x88, 0x8A, 0x58, 0x88, 0x88, 0x88, 0x88, 0x88,
307 0x88, 0x85, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
308 0x88, 0xEA, 0xAE, 0x88, 0x88, 0x88, 0x88, 0x88,
309 0x88, 0x00, 0x0B, 0x88, 0x88, 0x88, 0x88, 0x88,
310 0x88, 0x70, 0x0D, 0x88, 0x88, 0x88, 0x88, 0x88,
311 0x88, 0x87, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
312 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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
321};
322
323/*------------------------------------------------------------------*/
324
325class Param;
326class Return;
327void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh);
328int vaxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
329 int minor, int major, int text, int label, int grid, double ymin, double ymax,
330 BOOL logaxis);
331void haxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
332 int minor, int major, int text, int label, int grid, double xmin, double xmax);
333void get_elog_url(char *url, int len);
334void show_header(Return* r, const char *title, const char *method, const char *path, int refresh);
335void show_navigation_bar(Return* r, const char *cur_page);
336
337/*------------------------------------------------------------------*/
338
339char *stristr(const char *str, const char *pattern)
340{
341 char c1, c2, *ps, *pp;
342
343 if (str == NULL || pattern == NULL)
344 return NULL;
345
346 while (*str) {
347 ps = (char *) str;
348 pp = (char *) pattern;
349 c1 = *ps;
350 c2 = *pp;
351 if (toupper(c1) == toupper(c2)) {
352 while (*pp) {
353 c1 = *ps;
354 c2 = *pp;
355
356 if (toupper(c1) != toupper(c2))
357 break;
358
359 ps++;
360 pp++;
361 }
362
363 if (!*pp)
364 return (char *) str;
365 }
366 str++;
367 }
368
369 return NULL;
370}
371
372/*------------------------------------------------------------------*/
373
374static double GetTimeSec()
375{
376 struct timeval tv;
378 return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
379}
380
381/*------------------------------------------------------------------*/
382
384{
385public:
386 double fTimeReceived; // time request received
387 double fTimeLocked; // time lock is taken
388 double fTimeUnlocked; // time lock is released
389 double fTimeProcessed; // time processing of request is done
390 double fTimeSent; // time sending the request is done
391 bool fCompleted; // flag the request completed, it's RequestTrace is safe to delete
392 std::string fMethod; // request HTTP method
393 std::string fUri; // request URL/URI
394 std::string fQuery; // request query string
395 std::string fRPC; // request RPC
396 std::string fResource; // request file resource, with full path
397 bool fAuthOk; // password check passed
398
399public:
400 RequestTrace() // ctor
401 {
402 fTimeReceived = 0;
403 fTimeLocked = 0;
404 fTimeUnlocked = 0;
405 fTimeProcessed = 0;
406 fTimeSent = 0;
407 fCompleted = false;
408 fAuthOk = false;
409 }
410
411 void PrintTrace0() const
412 {
413 printf("%.3f ", fTimeReceived);
418 printf("A ");
419 printf("%d ", fAuthOk);
420 printf("T ");
424 printf("M %s ", fMethod.c_str());
425 printf("URL %s ", fUri.c_str());
426 if (fRPC.length() > 0) {
427 printf("RPC %s ", fRPC.c_str());
428 }
429 printf("\n");
430 };
431};
432
433static int http_trace = 0;
434
436{
437public:
439 std::vector<RequestTrace*> fBuf;
440
441public:
443 {
444 int status;
446 assert(status==SS_SUCCESS || status==SS_CREATED);
447 }
448
449 //RequestTrace* NewTrace() // RequestTrace factory
450 //{
451 // RequestTrace* t = new RequestTrace;
452 // fBuf.push_back(t);
453 // return t;
454 //}
455
457 {
458 fBuf.push_back(t);
459 }
460
462 {
464 if (http_trace) {
465 t->PrintTrace0();
466 }
467 delete t;
468 //AddTrace(t);
470 }
471
472 void Clear() // clear all completed requests
473 {
474 // delete all completed requests
475 for (unsigned i=0; i<fBuf.size(); i++) {
476 if (fBuf[i] && fBuf[i]->fCompleted) {
477 delete fBuf[i];
478 fBuf[i] = NULL;
479 }
480 }
481
482 // compact all non-completed requests
483 unsigned k = 0;
484 for (unsigned i=0; i<fBuf.size(); i++) {
485 if (fBuf[i]) {
486 if (fBuf[k] != NULL) {
487 for (; k<i; k++) {
488 if (fBuf[k] == NULL) {
489 break;
490 }
491 }
492 }
493 // if we found an empty spot between "k" and "i" move "i" there
494 // if there is no empty spot, then "i" does not need to be moved
495 if (fBuf[k] == NULL) {
496 fBuf[k] = fBuf[i];
497 fBuf[i] = NULL;
498 }
499 }
500 }
501 }
502};
503
505
506/*------------------------------------------------------------------*/
507
508/* size of buffer for incoming data, must fit sum of all attachments */
509#define WEB_BUFFER_SIZE (6*1024*1024)
510
512{
513public:
514
517
520
521public:
522 Return() // ctor
523 {
527
528 strlen_retbuf = 0;
529 return_length = 0;
530 }
531
532 ~Return() // dtor
533 {
534 if (return_buffer)
535 free(return_buffer);
537 return_size = 0;
538 strlen_retbuf = 0;
539 return_length = 0;
540 }
541
542 void reset()
543 {
544 strlen_retbuf = 0;
545 }
546
547 void zero()
548 {
550 strlen_retbuf = 0;
551 return_length = 0;
552 }
553
554int return_grow(size_t len)
555{
556 //printf("size %d, grow %d, room %d\n", return_size, len, return_size - strlen_retbuf);
557
558 for (int i=0; i<1000; i++) { // infinite loop with protection against infinite looping
559 if (strlen_retbuf + len < return_size-40)
560 return SUCCESS;
561
562 return_size *= 2;
564
566
567 //printf("new size %d\n", return_size);
568 }
569
570 assert(!"Cannot happen!"); // does not return
571 return 0;
572}
573
574/*------------------------------------------------------------------*/
575
576void rmemcpy(const void *buf, int len)
577{
578 return_grow(len);
580 strlen_retbuf += len;
582}
583
584/*------------------------------------------------------------------*/
585
586void rread(const char* filename, int fh, int len)
587{
588 return_grow(len);
589 int rd = read(fh, return_buffer + strlen_retbuf, len);
590 if (rd != len) {
591 cm_msg(MERROR, "rread", "Cannot read file \'%s\', read of %d returned %d, errno %d (%s)", filename, len, rd, errno, strerror(errno));
593 }
594 strlen_retbuf += len;
596}
597
598/*------------------------------------------------------------------*/
599
600void rsputs(const char *str)
601{
602 size_t len = strlen(str);
603
604 return_grow(len);
605
606 if (strlen_retbuf + len > return_size-40) {
607 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
609 } else {
611 strlen_retbuf += len;
612 }
613
615}
616
617/*------------------------------------------------------------------*/
618
619void rsputs2(const char *str)
620{
621 size_t len = strlen(str);
622
623 return_grow(len);
624
625 if (strlen_retbuf + len > return_size) {
626 mstrlcpy(return_buffer, "<H1>Error: return buffer too small</H1>", return_size);
628 } else {
629 int j = strlen_retbuf;
630 for (size_t i = 0; i < len; i++) {
631 if (strncmp(str + i, "http://", 7) == 0) {
632 int k;
633 char link[256];
634 char* p = (char *) (str + i + 7);
635
636 i += 7;
637 for (k = 0; *p && *p != ' ' && *p != '\n'; k++, i++)
638 link[k] = *p++;
639 link[k] = 0;
640
641 sprintf(return_buffer + j, "<a href=\"http://%s\">http://%s</a>", link, link);
642 j += strlen(return_buffer + j);
643 } else
644 switch (str[i]) {
645 case '<':
647 j += 4;
648 break;
649 case '>':
651 j += 4;
652 break;
653 default:
654 return_buffer[j++] = str[i];
655 }
656 }
657
658 return_buffer[j] = 0;
660 }
661
663}
664
665/*------------------------------------------------------------------*/
666
667void rsprintf(const char *format, ...) MATTRPRINTF(2,3)
668{
670 char str[10000];
671
672 va_start(argptr, format);
673 vsprintf(str, (char *) format, argptr);
675
676 // catch array overrun. better too late than never...
677 assert(strlen(str) < sizeof(str));
678
680
682 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
683 else
685
688}
689};
690
691/*------------------------------------------------------------------*/
692
693/* Parameter handling functions similar to setenv/getenv */
694
695#define MAX_PARAM 500
696#define PARAM_LENGTH 256
697#define TEXT_SIZE 50000
698
699class Param
700{
701public:
705
706public:
707 Param() // ctor
708 {
709 initparam();
710 }
711
712 ~Param() // dtor
713 {
714 freeparam();
715 }
716
718 {
719 memset(_param, 0, sizeof(_param));
720 memset(_value, 0, sizeof(_value));
721 _text[0] = 0;
722 }
723
724 void setparam(const char *param, const char *value)
725 {
726 int i;
727
728 if (equal_ustring(param, "text")) {
729 if (strlen(value) >= TEXT_SIZE)
730 printf("Error: parameter value too big\n");
731
733 _text[TEXT_SIZE - 1] = 0;
734 return;
735 }
736
737 for (i = 0; i < MAX_PARAM; i++)
738 if (_param[i][0] == 0)
739 break;
740
741 if (i < MAX_PARAM) {
743
744 int size = strlen(value)+1;
745 _value[i] = (char*)malloc(size);
746 mstrlcpy(_value[i], value, size);
747 _value[i][strlen(value)] = 0;
748
749 } else {
750 printf("Error: parameter array too small\n");
751 }
752 }
753
755 {
756 int i;
757
758 for (i=0 ; i<MAX_PARAM ; i++)
759 if (_value[i] != NULL) {
760 free(_value[i]);
761 _value[i] = NULL;
762 }
763 }
764
766 {
767 int i;
768
769 for (i = 0; i < MAX_PARAM && _param[i][0]; i++) {
770 printf("param %d name [%s] value [%s]\n", i, _param[i], _value[i]);;
771 }
772 }
773
774 const char *getparam(const char *param)
775 {
776 int i;
777
778 if (equal_ustring(param, "text"))
779 return _text;
780
781 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
783 break;
784
785 if (i == MAX_PARAM)
786 return NULL;
787
788 if (_value[i] == NULL)
789 return "";
790
791 return _value[i];
792 }
793
794 std::string xgetparam(const char *param)
795 {
796 const char* s = getparam(param);
797 if (s)
798 return s;
799 else
800 return "";
801 }
802
803 BOOL isparam(const char *param)
804 {
805 int i;
806
807 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
809 break;
810
811 if (i < MAX_PARAM && _param[i][0])
812 return TRUE;
813
814 return FALSE;
815 }
816
817 void unsetparam(const char *param)
818 {
819 int i;
820
821 for (i = 0; i < MAX_PARAM; i++)
823 break;
824
825 if (i < MAX_PARAM) {
826 _param[i][0] = 0;
827 _value[i][0] = 0;
828 }
829 }
830};
831
832/*------------------------------------------------------------------*/
833
834const char *mhttpd_revision(void)
835{
836 return cm_get_revision();
837}
838
839/*------------------------------------------------------------------*/
840
841static std::string UrlDecode(const char* p)
842/********************************************************************\
843 Decode the given string in-place by expanding %XX escapes
844\********************************************************************/
845{
846 std::string s;
847
848 //printf("URL decode: [%s] --> ", p);
849
850 while (*p) {
851 if (*p == '%') {
852 /* Escape: next 2 chars are hex representation of the actual character */
853 p++;
854 if (isxdigit(p[0]) && isxdigit(p[1])) {
855 int i = 0;
856 char str[3];
857 str[0] = p[0];
858 str[1] = p[1];
859 str[2] = 0;
860 sscanf(str, "%02X", &i);
861
862 s += (char) i;
863 p += 2;
864 } else
865 s += '%';
866 } else if (*p == '+') {
867 /* convert '+' to ' ' */
868 s += ' ';
869 p++;
870 } else {
871 s += *p++;
872 }
873 }
874
875 //printf("[%s]\n", s.c_str());
876
877 return s;
878}
879
880static void urlDecode(char *p)
881/********************************************************************\
882 Decode the given string in-place by expanding %XX escapes
883\********************************************************************/
884{
885 //char *px = p;
886 char *pD, str[3];
887 int i;
888
889 //printf("URL decode: [%s] --> ", p);
890
891 pD = p;
892 while (*p) {
893 if (*p == '%') {
894 /* Escape: next 2 chars are hex representation of the actual character */
895 p++;
896 if (isxdigit(p[0]) && isxdigit(p[1])) {
897 str[0] = p[0];
898 str[1] = p[1];
899 str[2] = 0;
900 sscanf(str, "%02X", &i);
901
902 *pD++ = (char) i;
903 p += 2;
904 } else
905 *pD++ = '%';
906 } else if (*p == '+') {
907 /* convert '+' to ' ' */
908 *pD++ = ' ';
909 p++;
910 } else {
911 *pD++ = *p++;
912 }
913 }
914 *pD = '\0';
915
916 //printf("[%s]\n", px);
917}
918
919static void urlEncode(char *ps, int ps_size)
920/*
921 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
922 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
923*/
924{
925 char *pd, *p;
926 int len = strlen(ps);
927 char *str = (char*)malloc(len*3 + 10); // at worst, each input character is expanded into 3 output characters
928
929 pd = str;
930 p = ps;
931 while (*p) {
932 if (isalnum(*p)) {
933 *pd++ = *p++;
934 } else {
935 sprintf(pd, "%%%02X", (*p)&0xFF);
936 pd += 3;
937 p++;
938 }
939 }
940 *pd = '\0';
941
942 if (/* DISABLES CODE */ (0)) {
943 printf("urlEncode [");
944 for (p=ps; *p!=0; p++)
945 printf("0x%02x ", (*p)&0xFF);
946 printf("]\n");
947
948 printf("urlEncode [%s] -> [%s]\n", ps, str);
949 }
950
952 free(str);
953}
954
955static std::string urlEncode(const char *text)
956/*
957 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
958 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
959*/
960{
961 std::string encoded;
962
963 const char* p = text;
964 while (*p) {
965 if (isalnum(*p)) {
966 encoded += *p++;
967 } else {
968 char buf[16];
969 sprintf(buf, "%%%02X", (*p)&0xFF);
970 encoded += buf;
971 p++;
972 }
973 }
974
975 if (/* DISABLES CODE */ (0)) {
976 printf("urlEncode [");
977 for (p=text; *p!=0; p++)
978 printf("0x%02x ", (*p)&0xFF);
979 printf("]\n");
980
981 printf("urlEncode [%s] -> [%s]\n", text, encoded.c_str());
982 }
983
984 return encoded;
985}
986
987/*------------------------------------------------------------------*/
988
989std::vector<std::string> get_resource_paths()
990{
991 HNDLE hDB;
992 int status;
993
995
996 std::vector<std::string> paths;
997
998 // add /Experiment/Resources
999 std::string buf;
1000 status = db_get_value_string(hDB, 0, "/Experiment/Resources", 0, &buf, TRUE);
1001 if (status == DB_SUCCESS && buf.length() > 0)
1002 paths.push_back(buf);
1003
1004 // add "/Logger/History/IMAGE/History dir"
1005 paths.push_back(cm_get_history_path("IMAGE"));
1006
1007 // add /Logger/Data dir
1008 status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &buf, TRUE);
1009 if (status == DB_SUCCESS && buf.length() > 0)
1010 paths.push_back(buf);
1011
1012 std::string cwd = ss_getcwd();
1013 if (!cwd.empty()) {
1014 paths.push_back(cwd + "/");
1015 paths.push_back(cwd + "/resources/");
1016 }
1017 paths.push_back(cm_get_path());
1018 paths.push_back(cm_get_path() + "resources/");
1019 char *m = getenv("MIDASSYS");
1020 if (m) {
1021 paths.push_back(std::string(m) + "/resources/");
1022 }
1023
1024 return paths;
1025}
1026
1027/*------------------------------------------------------------------*/
1028
1029bool open_resource_file(const char *filename, std::string* ppath, FILE** pfp)
1030{
1031 // resource file names should not start with a directory separator "/"
1032 // or contain ".." as this will allow them to escape the mhttpd filename "jail"
1033 // by asking file files names like "../../etc/passwd", etc.
1034
1035 if (strlen(filename) < 1) {
1036 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' is too short",
1037 filename);
1038 return false;
1039 }
1040
1041 if (filename[0] == DIR_SEPARATOR) {
1042 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' starting with \'%c\' which is not allowed",
1043 filename, DIR_SEPARATOR);
1044 return false;
1045 }
1046
1047 if (strstr(filename, "..") != NULL) {
1048 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' containing \'..\' which is not allowed",
1049 filename);
1050 return false;
1051 }
1052
1053 std::vector<std::string> paths = get_resource_paths();
1054
1055 std::vector<std::string> paths_not_found;
1056
1057 for (unsigned i=0; i<paths.size(); i++) {
1058 std::string path = paths[i];
1059 if (path.length() < 1)
1060 continue;
1061 if (path[0] == '#')
1062 continue;
1063
1064 // expand env.variables before we add the filename.
1065 // the filename comes from the URL and if the URL
1066 // has '$' characters we will try to expand them
1067 // as an env.variable and maybe escape the file jail.
1068
1069 std::string xpath = cm_expand_env(path.c_str());
1070
1071 if (xpath[xpath.length()-1] != DIR_SEPARATOR)
1073 xpath += filename;
1074
1075 //printf("path [%s] [%s] [%s]\n", paths[i].c_str(), path.c_str(), xpath.c_str());
1076
1077 FILE* fp = fopen(xpath.c_str(), "r");
1078 if (fp) {
1079 struct stat statbuf;
1080 int status = fstat(fileno(fp), &statbuf);
1081 if (status != 0) {
1082 cm_msg(MERROR, "open_resource_file", "Cannot fstat() file \'%s\', error %d (%s)", xpath.c_str(), errno, strerror(errno));
1083 fclose(fp);
1084 fp = NULL;
1085 }
1086
1087 if (statbuf.st_mode & S_IFREG) {
1088 // good, normal file
1089 //printf("%s: regular!\n", xpath.c_str());
1090 //} else if (statbuf.st_mode & S_IFLNK) {
1091 // symlink
1092 //printf("%s: symlink!\n", xpath.c_str());
1093 } else if (statbuf.st_mode & S_IFDIR) {
1094 cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is a directory", xpath.c_str(), filename);
1095 fclose(fp);
1096 fp = NULL;
1097 } else {
1098 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);
1099 fclose(fp);
1100 fp = NULL;
1101 }
1102
1103 if (fp) {
1104 if (ppath)
1105 *ppath = xpath;
1106 if (pfp) {
1107 *pfp = fp;
1108 } else {
1109 fclose(fp);
1110 fp = NULL;
1111 }
1112 //cm_msg(MINFO, "open_resource_file", "Resource file \'%s\' is \'%s\'", filename, xpath.c_str());
1113 return true;
1114 }
1115 }
1116
1117 paths_not_found.push_back(xpath);
1118 }
1119
1120 std::string s;
1121 for (unsigned i=0; i<paths_not_found.size(); i++) {
1122 if (i>0)
1123 s += ", ";
1124 s += paths_not_found[i];
1125 }
1126
1127 cm_msg(MERROR, "open_resource_file", "Cannot find resource file \'%s\', tried %s", filename, s.c_str());
1128 return false;
1129}
1130
1131/*------------------------------------------------------------------*/
1132
1133std::string get_content_type(const char* filename)
1134{
1135 std::string ext_upper;
1136 const char* p = filename;
1137 const char* last_dot = NULL;
1138 for (; *p; p++) {
1139 if (*p == '.')
1140 last_dot = p;
1141 if (*p == DIR_SEPARATOR)
1142 last_dot = NULL;
1143 }
1144
1145 if (last_dot) {
1146 p = last_dot;
1147 for (; *p; p++)
1148 ext_upper += toupper(*p);
1149 }
1150
1151 //printf("filename: [%s], ext [%s]\n", filename, ext_upper.c_str());
1152
1153 std::string type = GetMimetype(ext_upper);
1154 if (type.length() > 0)
1155 return type;
1156
1157 cm_msg(MERROR, "get_content_type", "Unknown HTTP Content-Type for resource file \'%s\', file extension \'%s\'", filename, ext_upper.c_str());
1158
1159 return "text/plain";
1160}
1161
1162/*------------------------------------------------------------------*/
1163
1164bool send_fp(Return* r, const std::string& path, FILE* fp)
1165{
1166 assert(fp != NULL);
1167
1168 // send HTTP headers
1169
1170 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1171 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1172 r->rsprintf("Accept-Ranges: bytes\r\n");
1173
1174 // send HTTP cache control headers
1175
1176 time_t now = time(NULL);
1177 now += (int) (3600 * 24);
1178 struct tm gmt_tms;
1179 gmtime_r(&now, &gmt_tms);
1180 const char* format = "%A, %d-%b-%y %H:%M:%S GMT";
1181
1182 char str[256];
1183 strftime(str, sizeof(str), format, &gmt_tms);
1184 r->rsprintf("Expires: %s\r\n", str);
1185
1186 // send Content-Type header
1187
1188 r->rsprintf("Content-Type: %s\r\n", get_content_type(path.c_str()).c_str());
1189
1190 // send Content-Length header
1191
1192 struct stat stat_buf;
1193 fstat(fileno(fp), &stat_buf);
1194 int length = stat_buf.st_size;
1195 r->rsprintf("Content-Length: %d\r\n", length);
1196
1197 // send end of headers
1198
1199 r->rsprintf("\r\n");
1200
1201 // send file data
1202
1203 r->rread(path.c_str(), fileno(fp), length);
1204
1205 fclose(fp);
1206
1207 return true;
1208}
1209
1210bool send_file(Return* r, const std::string& path, bool generate_404 = true)
1211{
1212 FILE *fp = fopen(path.c_str(), "rb");
1213
1214 if (!fp) {
1215 if (generate_404) {
1216 /* header */
1217 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1218 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1219 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1220 r->rsprintf("\r\n");
1221 r->rsprintf("Error: Cannot read \"%s\", fopen() errno %d (%s)\n", path.c_str(), errno, strerror(errno));
1222 }
1223 return false;
1224 }
1225
1226 return send_fp(r, path, fp);
1227}
1228
1229bool send_resource(Return* r, const std::string& name, bool generate_404 = true)
1230{
1231 std::string path;
1232 FILE *fp = NULL;
1233
1234 bool found = open_resource_file(name.c_str(), &path, &fp);
1235
1236 if (!found) {
1237 if (generate_404) {
1238 /* header */
1239 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1240 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1241 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1242 r->rsprintf("\r\n");
1243 r->rsprintf("Error: resource file \"%s\" not found, see messages\n", name.c_str());
1244 }
1245 return false;
1246 }
1247
1248 return send_fp(r, path, fp);
1249}
1250
1251/*------------------------------------------------------------------*/
1252
1253INT sendmail(const char* from_host, const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
1254{
1255 struct sockaddr_in bind_addr;
1256 struct hostent *phe;
1257 int i, s, strsize, offset;
1258 char *str, buf[256];
1259
1260 if (verbose)
1261 printf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
1262
1263 /* create a new socket for connecting to remote server */
1264 s = socket(AF_INET, SOCK_STREAM, 0);
1265 if (s == -1)
1266 return -1;
1267
1268 /* connect to remote node port 25 */
1269 memset(&bind_addr, 0, sizeof(bind_addr));
1270 bind_addr.sin_family = AF_INET;
1271 bind_addr.sin_port = htons((short) 25);
1272
1274 if (phe == NULL)
1275 return -1;
1276 memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
1277
1278 if (connect(s, (const sockaddr*)&bind_addr, sizeof(bind_addr)) < 0) {
1279 closesocket(s);
1280 return -1;
1281 }
1282
1283 strsize = TEXT_SIZE + 1000;
1284 str = (char*)malloc(strsize);
1285
1286 recv_string(s, str, strsize, 3000);
1287 if (verbose)
1288 puts(str);
1289
1290 /* drain server messages */
1291 do {
1292 str[0] = 0;
1293 recv_string(s, str, strsize, 300);
1294 if (verbose)
1295 puts(str);
1296 } while (str[0]);
1297
1298 sprintf(str, "HELO %s\r\n", from_host);
1299 send(s, str, strlen(str), 0);
1300 if (verbose)
1301 puts(str);
1302 recv_string(s, str, strsize, 3000);
1303 if (verbose)
1304 puts(str);
1305
1306 if (strchr(from, '<')) {
1307 mstrlcpy(buf, strchr(from, '<') + 1, sizeof(buf));
1308 if (strchr(buf, '>'))
1309 *strchr(buf, '>') = 0;
1310 } else
1311 mstrlcpy(buf, from, sizeof(buf));
1312
1313 sprintf(str, "MAIL FROM: %s\n", buf);
1314 send(s, str, strlen(str), 0);
1315 if (verbose)
1316 puts(str);
1317 recv_string(s, str, strsize, 3000);
1318 if (verbose)
1319 puts(str);
1320
1321 sprintf(str, "RCPT TO: <%s>\r\n", to);
1322 send(s, str, strlen(str), 0);
1323 if (verbose)
1324 puts(str);
1325 recv_string(s, str, strsize, 3000);
1326 if (verbose)
1327 puts(str);
1328
1329 sprintf(str, "DATA\r\n");
1330 send(s, str, strlen(str), 0);
1331 if (verbose)
1332 puts(str);
1333 recv_string(s, str, strsize, 3000);
1334 if (verbose)
1335 puts(str);
1336
1337 sprintf(str, "To: %s\r\nFrom: %s\r\nSubject: %s\r\n", to, from, subject);
1338 send(s, str, strlen(str), 0);
1339 if (verbose)
1340 puts(str);
1341
1342 sprintf(str, "X-Mailer: mhttpd revision %s\r\n", mhttpd_revision());
1343 send(s, str, strlen(str), 0);
1344 if (verbose)
1345 puts(str);
1346
1347 ss_tzset(); // required for localtime_r()
1348 time_t now;
1349 time(&now);
1350 struct tm tms;
1351 localtime_r(&now, &tms);
1352 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", &tms);
1353 offset = (-(int) timezone);
1354 if (tms.tm_isdst)
1355 offset += 3600;
1356 sprintf(str, "Date: %s %+03d%02d\r\n", buf, (int) (offset / 3600),
1357 (int) ((abs((int) offset) / 60) % 60));
1358 send(s, str, strlen(str), 0);
1359 if (verbose)
1360 puts(str);
1361
1362 sprintf(str, "Content-Type: TEXT/PLAIN; charset=US-ASCII\r\n\r\n");
1363 send(s, str, strlen(str), 0);
1364 if (verbose)
1365 puts(str);
1366
1367 /* analyze text for "." at beginning of line */
1368 const char* p = text;
1369 str[0] = 0;
1370 while (strstr(p, "\r\n.\r\n")) {
1371 i = (POINTER_T) strstr(p, "\r\n.\r\n") - (POINTER_T) p + 1;
1372 mstrlcat(str, p, i);
1373 p += i + 4;
1374 mstrlcat(str, "\r\n..\r\n", strsize);
1375 }
1376 mstrlcat(str, p, strsize);
1377 mstrlcat(str, "\r\n", strsize);
1378 send(s, str, strlen(str), 0);
1379 if (verbose)
1380 puts(str);
1381
1382 /* send ".<CR>" to signal end of message */
1383 sprintf(str, ".\r\n");
1384 send(s, str, strlen(str), 0);
1385 if (verbose)
1386 puts(str);
1387 recv_string(s, str, strsize, 3000);
1388 if (verbose)
1389 puts(str);
1390
1391 sprintf(str, "QUIT\n");
1392 send(s, str, strlen(str), 0);
1393 if (verbose)
1394 puts(str);
1395 recv_string(s, str, strsize, 3000);
1396 if (verbose)
1397 puts(str);
1398
1399 closesocket(s);
1400 free(str);
1401
1402 return 1;
1403}
1404
1405/*------------------------------------------------------------------*/
1406
1407void redirect(Return *r, const char *path)
1408{
1409 char str[256];
1410
1411 //printf("redirect to [%s]\n", path);
1412
1413 mstrlcpy(str, path, sizeof(str));
1414 if (str[0] == 0)
1415 strcpy(str, "./");
1416
1417 /* redirect */
1418 r->rsprintf("HTTP/1.1 302 Found\r\n");
1419 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1420 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1421
1422 if (strncmp(path, "http:", 5) == 0)
1423 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1424 else if (strncmp(path, "https:", 6) == 0)
1425 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1426 else {
1427 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1428 }
1429}
1430
1431void redirect_307(Return *r, const char *path)
1432{
1433 //printf("redirect_307 to [%s]\n", path);
1434
1435 /* redirect */
1436 r->rsprintf("HTTP/1.1 307 Temporary Redirect\r\n");
1437 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1438 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1439 r->rsprintf("Location: %s\r\n", path);
1440 r->rsprintf("\r\n");
1441 r->rsprintf("<html>redirect to %s</html>\r\n", path);
1442}
1443
1444void redirect2(Return* r, const char *path)
1445{
1446 redirect(r, path);
1447}
1448
1449/*------------------------------------------------------------------*/
1450
1452{
1454 const char* search_name;
1455};
1456
1458{
1460 int i;
1461 INT size, status;
1462
1463 Return* r = sinfo->r;
1464 const char* search_name = sinfo->search_name;
1465
1466 /* convert strings to uppercase */
1467
1468 char xstr1[MAX_ODB_PATH];
1469 for (i = 0; key->name[i]; i++)
1470 xstr1[i] = toupper(key->name[i]);
1471 xstr1[i] = 0;
1472
1473 char str2[MAX_ODB_PATH];
1474 for (i = 0; search_name[i] ; i++)
1475 str2[i] = toupper(search_name[i]);
1476 str2[i] = 0;
1477
1478 if (strstr(xstr1, str2) != NULL) {
1479 char data[10000];
1480 std::string path = db_get_path(hDB, hKey).substr(1);
1481 std::string path_encoded = urlEncode(path.c_str());
1482
1483 if (key->type == TID_KEY || key->type == TID_LINK) {
1484 /* for keys, don't display data value */
1485 r->rsprintf("<tr><td class=\"ODBkey\"><a href=\"?cmd=odb&odb_path=/%s\">/%s</a></tr>\n", path_encoded.c_str(), path.c_str());
1486 } else {
1487 /* strip variable name from path */
1488 char* p = const_cast<char *>(path.data() + path.length() - 1);
1489 while (*p && *p != '/')
1490 *p-- = 0;
1491 if (*p == '/')
1492 *p = 0;
1493
1494 /* display single value */
1495 if (key->num_values == 1) {
1496 size = sizeof(data);
1497 status = db_get_data(hDB, hKey, data, &size, key->type);
1498 std::string data_str;
1499 if (status == DB_NO_ACCESS)
1500 data_str = "<no read access>";
1501 else
1503
1504 r->rsprintf("<tr><td class=\"ODBkey\">");
1505 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s</a></td>", path_encoded.c_str(), path.c_str(), key->name);
1506 r->rsprintf("<td class=\"ODBvalue\">%s</td></tr>\n", data_str.c_str());
1507 } else {
1508 /* display first value */
1509 i = key->num_values;
1510 if (i > 10)
1511 i = 11;
1512 r->rsprintf("<tr><td rowspan=%d class=\"ODBkey\">", i);
1513 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s\n", path_encoded.c_str(), path.c_str(), key->name);
1514
1515 for (int i = 0; i < key->num_values; i++) {
1516 size = sizeof(data);
1517 db_get_data_index(hDB, hKey, data, &size, i, key->type);
1518
1519 std::string data_str = db_sprintf(data, key->item_size, 0, key->type);
1520
1521 if (i > 0)
1522 r->rsprintf("<tr>");
1523
1524 r->rsprintf("<td class=\"ODBvalue\">[%d] %s</td></tr>\n", i, data_str.c_str());
1525
1526 if (i > 8) {
1527 r->rsprintf("<tr><td class=\"ODBvalue\">... [%d] values ...</td></tr>\n", key->num_values - i - 1);
1528 break;
1529 }
1530 }
1531 }
1532 }
1533 }
1534
1535 return SUCCESS;
1536}
1537
1538/*------------------------------------------------------------------*/
1539
1540void show_help_page(Return* r, const char* dec_path)
1541{
1542 const char *s;
1543 char str[256];
1544 int status;
1545
1546 show_header(r, "Help", "", "./", 0);
1547 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
1548 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
1549 show_navigation_bar(r, "Help");
1550
1551 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1552 r->rsprintf(" <tr>\n");
1553 r->rsprintf(" <td class=\"mtableheader\">MIDAS Help Page</td>\n");
1554 r->rsprintf(" </tr>\n");
1555 r->rsprintf(" <tr>\n");
1556 r->rsprintf(" <td>\n");
1557 r->rsprintf(" <table>\n");
1558
1559 r->rsprintf(" <tr>\n");
1560 r->rsprintf(" <td style=\"text-align:right;\">Documentation:</td>\n");
1561 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca\">https://midas.triumf.ca</a></td>\n");
1562 r->rsprintf(" </tr>\n");
1563 r->rsprintf(" <tr>\n");
1564 r->rsprintf(" <td style=\"text-align:right;\">Discussion Forum:</td>\n");
1565 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca/forum/\">https://midas.triumf.ca/forum/</a></td>\n");
1566 r->rsprintf(" </tr>\n");
1567 r->rsprintf(" <tr>\n");
1568 r->rsprintf(" <td style=\"text-align:right;\">Code:</td>\n");
1569 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/\">https://bitbucket.org/tmidas/midas/</a></td>\n");
1570 r->rsprintf(" </tr>\n");
1571 r->rsprintf(" <tr>\n");
1572 r->rsprintf(" <td style=\"text-align:right;\">Report a bug:</td>\n");
1573 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/issues/\">https://bitbucket.org/tmidas/midas/issues/</a></td>\n");
1574 r->rsprintf(" </tr>\n");
1575
1576 r->rsprintf(" <tr>\n");
1577 r->rsprintf(" <td style=\"text-align:right;\">Version:</td>\n");
1578 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_version());
1579 r->rsprintf(" </tr>\n");
1580 r->rsprintf(" <tr>\n");
1581 r->rsprintf(" <td style=\"text-align:right;\">Revision:</td>\n");
1582 std::string rev = cm_get_revision();
1583 std::string url = "https://bitbucket.org/tmidas/midas/commits/";
1584 // rev format looks like this:
1585 // Fri Nov 24 10:15:54 2017 -0800 - midas-2017-07-c-171-gb8928d5c-dirty on branch develop
1586 // -gXXX is the commit hash
1587 // -dirty should be removed from the hash url, if present
1588 // " " before "on branch" should be removed from the hash url
1589 std::string::size_type pos = rev.find("-g");
1590 if (pos != std::string::npos) {
1591 std::string hash = rev.substr(pos+2);
1592 pos = hash.find("-dirty");
1593 if (pos != std::string::npos) {
1594 hash = hash.substr(0, pos);
1595 }
1596 pos = hash.find(" ");
1597 if (pos != std::string::npos) {
1598 hash = hash.substr(0, pos);
1599 }
1600 url += hash;
1601 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"%s\">%s</a></td>\n", url.c_str(), rev.c_str());
1602 } else {
1603 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", rev.c_str());
1604 }
1605 r->rsprintf(" </tr>\n");
1606
1607 r->rsprintf(" <tr>\n");
1608 r->rsprintf(" <td style=\"text-align:right;\">MIDASSYS:</td>\n");
1609 s = getenv("MIDASSYS");
1610 if (!s) s = "(unset)";
1611 mstrlcpy(str, s, sizeof(str));
1612 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", str);
1613 r->rsprintf(" </tr>\n");
1614
1615 r->rsprintf(" <tr>\n");
1616 r->rsprintf(" <td style=\"text-align:right;\">mhttpd current directory:</td>\n");
1617 std::string cwd = ss_getcwd();
1618 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cwd.c_str());
1619 r->rsprintf(" </tr>\n");
1620
1621 r->rsprintf(" <tr>\n");
1622 r->rsprintf(" <td style=\"text-align:right;\">Exptab file:</td>\n");
1623 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_exptab_filename().c_str());
1624 r->rsprintf(" </tr>\n");
1625
1626 r->rsprintf(" <tr>\n");
1627 r->rsprintf(" <td style=\"text-align:right;\">Experiment:</td>\n");
1628 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_experiment_name().c_str());
1629 r->rsprintf(" </tr>\n");
1630
1631 r->rsprintf(" <tr>\n");
1632 r->rsprintf(" <td style=\"text-align:right;\">Experiment directory:</td>\n");
1633 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_path().c_str());
1634 r->rsprintf(" </tr>\n");
1635
1638
1639 if (status == CM_SUCCESS) {
1640 if (list.size() == 1) {
1641 r->rsprintf(" <tr>\n");
1642 r->rsprintf(" <td style=\"text-align:right;\">System logfile:</td>\n");
1643 std::string s;
1644 cm_msg_get_logfile("midas", 0, &s, NULL, NULL);
1645 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", s.c_str());
1646 r->rsprintf(" </tr>\n");
1647 } else {
1648 r->rsprintf(" <tr>\n");
1649 r->rsprintf(" <td style=\"text-align:right;\">Logfiles:</td>\n");
1650 r->rsprintf(" <td style=\"text-align:left;\">\n");
1651 for (unsigned i=0 ; i<list.size() ; i++) {
1652 if (i>0)
1653 r->rsputs("<br />\n");
1654 std::string s;
1655 cm_msg_get_logfile(list[i].c_str(), 0, &s, NULL, NULL);
1656 r->rsputs(s.c_str());
1657 }
1658 r->rsprintf("\n </td>\n");
1659 r->rsprintf(" </tr>\n");
1660 }
1661 }
1662
1663 r->rsprintf(" <tr>\n");
1664 r->rsprintf(" <td style=\"text-align:right;\">Image history:</td>\n");
1665 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_history_path("IMAGE").c_str());
1666 r->rsprintf(" </tr>\n");
1667
1668 r->rsprintf(" <tr>\n");
1669 r->rsprintf(" <td style=\"text-align:right;\">Resource paths:</td>\n");
1670 r->rsprintf(" <td style=\"text-align:left;\">");
1671 std::vector<std::string> resource_paths = get_resource_paths();
1672 for (unsigned i=0; i<resource_paths.size(); i++) {
1673 if (i>0)
1674 r->rsputs("<br>");
1676 std::string exp = cm_expand_env(resource_paths[i].c_str());
1677 //printf("%d %d [%s] [%s]\n", resource_paths[i].length(), exp.length(), resource_paths[i].c_str(), exp.c_str());
1678 if (exp != resource_paths[i]) {
1679 r->rsputs(" (");
1680 r->rsputs(exp.c_str());
1681 r->rsputs(")");
1682 }
1683 }
1684 r->rsprintf(" </td>\n");
1685 r->rsprintf(" </tr>\n");
1686
1687 std::string path;
1688
1689 r->rsprintf(" <tr>\n");
1690 r->rsprintf(" <td style=\"text-align:right;\">midas.css:</td>\n");
1691 if (open_resource_file("midas.css", &path, NULL))
1692 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1693 else
1694 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1695 r->rsprintf(" </tr>\n");
1696
1697 r->rsprintf(" <tr>\n");
1698 r->rsprintf(" <td style=\"text-align:right;\">midas.js:</td>\n");
1699 if (open_resource_file("midas.js", &path, NULL))
1700 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1701 else
1702 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1703 r->rsprintf(" </tr>\n");
1704
1705 r->rsprintf(" <tr>\n");
1706 r->rsprintf(" <td style=\"text-align:right;\">controls.js:</td>\n");
1707 if (open_resource_file("controls.js", &path, NULL))
1708 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1709 else
1710 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1711 r->rsprintf(" </tr>\n");
1712
1713 r->rsprintf(" <tr>\n");
1714 r->rsprintf(" <td style=\"text-align:right;\">mhttpd.js:</td>\n");
1715 if (open_resource_file("mhttpd.js", &path, NULL))
1716 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1717 else
1718 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1719 r->rsprintf(" </tr>\n");
1720
1721 r->rsprintf(" <tr>\n");
1722 r->rsprintf(" <td style=\"text-align:right;\">obsolete.js:</td>\n");
1723 if (open_resource_file("obsolete.js", &path, NULL))
1724 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1725 else
1726 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1727 r->rsprintf(" </tr>\n");
1728
1729 r->rsprintf(" <tr>\n");
1730 r->rsprintf(" <td style=\"text-align:right;\">Obsolete mhttpd.css:</td>\n");
1731 if (open_resource_file("mhttpd.css", &path, NULL))
1732 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1733 else
1734 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1735 r->rsprintf(" </tr>\n");
1736
1737 r->rsprintf(" <tr>\n");
1738 r->rsprintf(" <td style=\"text-align:right;\">JSON-RPC schema:</td>\n");
1739 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");
1740 r->rsprintf(" </tr>\n");
1741
1742 r->rsprintf(" <tr>\n");
1743 r->rsprintf(" <td style=\"text-align:right;\">JavaScript examples:</td>\n");
1744 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=example\">example.html</a></td>\n");
1745 r->rsprintf(" </tr>\n");
1746
1747 r->rsprintf(" <tr>\n");
1748 r->rsprintf(" <td style=\"text-align:right;\">Custom page example:</td>\n");
1749 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=custom_example\">custom_example.html</a></td>\n");
1750 r->rsprintf(" </tr>\n");
1751
1752 r->rsprintf(" <tr>\n");
1753 r->rsprintf(" <td style=\"text-align:right;\">MPlot custom plot examples:</td>\n");
1754 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=plot_example\">plot_example.html</a></td>\n");
1755 r->rsprintf(" </tr>\n");
1756
1757 r->rsprintf(" </table>\n");
1758 r->rsprintf(" </td>\n");
1759 r->rsprintf(" </tr>\n");
1760 r->rsprintf("</table>\n");
1761
1762 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1763 r->rsprintf(" <tr>\n");
1764 r->rsprintf(" <td class=\"mtableheader\">Contributions</td>\n");
1765 r->rsprintf(" </tr>\n");
1766 r->rsprintf(" <tr>\n");
1767 r->rsprintf(" <td>\n");
1768 r->rsprintf("Pierre-Andre&nbsp;Amaudruz - Sergio&nbsp;Ballestrero - Suzannah&nbsp;Daviel - Peter&nbsp;Green - Qing&nbsp;Gu - Greg&nbsp;Hackman - Gertjan&nbsp;Hofman - Paul&nbsp;Knowles - Exaos&nbsp;Lee - Thomas&nbsp;Lindner - Shuoyi&nbsp;Ma - Rudi&nbsp;Meier - Bill&nbsp;Mills - Glenn&nbsp;Moloney - Dave&nbsp;Morris - John&nbsp;M&nbsp;O'Donnell - Konstantin&nbsp;Olchanski - Chris&nbsp;Pearson - Renee&nbsp;Poutissou - Stefan&nbsp;Ritt - Zaher&nbsp;Salman - Ryu&nbsp;Sawada - Tamsen&nbsp;Schurman - Ben&nbsp;Smith - Andreas&nbsp;Suter - Jan&nbsp;M.&nbsp;Wouters - Piotr&nbsp;Adam&nbsp;Zolnierczuk\n");
1769 r->rsprintf(" </td>\n");
1770 r->rsprintf(" </tr>\n");
1771 r->rsprintf("</table>\n");
1772
1773 r->rsprintf("</div></form>\n");
1774 r->rsprintf("</body></html>\r\n");
1775}
1776
1777/*------------------------------------------------------------------*/
1778
1779void show_header(Return* r, const char *title, const char *method, const char *path, int refresh)
1780{
1781 HNDLE hDB;
1782 time_t now;
1783 char str[256];
1784
1786
1787 /* header */
1788 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1789 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1790 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1791 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1792 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1793
1794 r->rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
1795 r->rsprintf("<html><head>\n");
1796
1797 /* style sheet */
1798 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
1799 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1800 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
1801
1802 /* auto refresh */
1803 if (refresh > 0)
1804 r->rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
1805
1806 r->rsprintf("<title>%s</title></head>\n", title);
1807
1808 mstrlcpy(str, path, sizeof(str));
1809 urlEncode(str, sizeof(str));
1810
1811 if (equal_ustring(method, "POST"))
1812 r->rsprintf
1813 ("<body><form name=\"form1\" method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n\n",
1814 str);
1815 else if (equal_ustring(method, "GET"))
1816 r->rsprintf("<body><form name=\"form1\" method=\"GET\" action=\"%s\">\n\n", str);
1817
1818 /* title row */
1819
1820 std::string exptname;
1821 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
1822 time(&now);
1823}
1824
1825/*------------------------------------------------------------------*/
1826
1828{
1829 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1830 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1831 r->rsprintf("Access-Control-Allow-Origin: *\r\n");
1832 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1833 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1834 r->rsprintf("Content-Type: text/plain; charset=%s\r\n\r\n", HTTP_ENCODING);
1835}
1836
1837/*------------------------------------------------------------------*/
1838
1839void show_error(Return* r, const char *error)
1840{
1841 /* header */
1842 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1843 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1844 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1845
1846 r->rsprintf("<html><head>\n");
1847 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1848 r->rsprintf("<title>MIDAS error</title></head>\n");
1849 r->rsprintf("<body><H1>%s</H1></body></html>\n", error);
1850}
1851
1852/*------------------------------------------------------------------*/
1853
1854void show_error_404(Return* r, const char *error)
1855{
1856 /* header */
1857 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1858 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1859 r->rsprintf("Content-Type: text/plain\r\n");
1860 r->rsprintf("\r\n");
1861
1862 r->rsprintf("MIDAS error: %s\n", error);
1863}
1864
1865/*------------------------------------------------------------------*/
1866
1868{
1869 r->rsprintf("<script>\n");
1870 r->rsprintf("window.addEventListener(\"load\", function(e) { mhttpd_init('%s', 1000); });\n", cur_page);
1871 r->rsprintf("</script>\n");
1872
1873 r->rsprintf("<!-- header and side navigation will be filled in mhttpd_init -->\n");
1874 r->rsprintf("<div id=\"mheader\"></div>\n");
1875 r->rsprintf("<div id=\"msidenav\"></div>\n");
1876 r->rsprintf("<div id=\"mmain\">\n");
1877}
1878
1879/*------------------------------------------------------------------*/
1880
1881void check_obsolete_odb(HNDLE hDB, const char* odb_path)
1882{
1883 HNDLE hKey;
1884 int status = db_find_key(hDB, 0, odb_path, &hKey);
1885 if (status == DB_SUCCESS) {
1886 cm_msg(MERROR, "check_obsolete_odb", "ODB \"%s\" is obsolete, please delete it.", odb_path);
1887 }
1888}
1889
1891{
1892 HNDLE hDB;
1895 int size = sizeof(true_value);
1897 db_get_value(hDB, 0, "/Experiment/Menu/Status", &true_value, &size, TID_BOOL, TRUE);
1898 db_get_value(hDB, 0, "/Experiment/Menu/Start", &false_value, &size, TID_BOOL, TRUE);
1899 db_get_value(hDB, 0, "/Experiment/Menu/Transition", &true_value, &size, TID_BOOL, TRUE);
1900 db_get_value(hDB, 0, "/Experiment/Menu/ODB", &true_value, &size, TID_BOOL, TRUE);
1901 db_get_value(hDB, 0, "/Experiment/Menu/OldODB", &true_value, &size, TID_BOOL, TRUE);
1902 db_get_value(hDB, 0, "/Experiment/Menu/Messages", &true_value, &size, TID_BOOL, TRUE);
1903 db_get_value(hDB, 0, "/Experiment/Menu/Chat", &true_value, &size, TID_BOOL, TRUE);
1904 db_get_value(hDB, 0, "/Experiment/Menu/Elog", &true_value, &size, TID_BOOL, TRUE);
1905 db_get_value(hDB, 0, "/Experiment/Menu/Alarms", &true_value, &size, TID_BOOL, TRUE);
1906 db_get_value(hDB, 0, "/Experiment/Menu/Programs", &true_value, &size, TID_BOOL, TRUE);
1907 db_get_value(hDB, 0, "/Experiment/Menu/Buffers", &true_value, &size, TID_BOOL, TRUE);
1908 db_get_value(hDB, 0, "/Experiment/Menu/History", &true_value, &size, TID_BOOL, TRUE);
1909 db_get_value(hDB, 0, "/Experiment/Menu/OldHistory", &true_value, &size, TID_BOOL, TRUE);
1910 db_get_value(hDB, 0, "/Experiment/Menu/MSCB", &true_value, &size, TID_BOOL, TRUE);
1911 db_get_value(hDB, 0, "/Experiment/Menu/Sequencer", &true_value, &size, TID_BOOL, TRUE);
1912 db_get_value(hDB, 0, "/Experiment/Menu/Event Dump", &true_value, &size, TID_BOOL, TRUE);
1913 db_get_value(hDB, 0, "/Experiment/Menu/Config", &true_value, &size, TID_BOOL, TRUE);
1914 db_get_value(hDB, 0, "/Experiment/Menu/Example", &false_value, &size, TID_BOOL, TRUE);
1915 db_get_value(hDB, 0, "/Experiment/Menu/Help", &true_value, &size, TID_BOOL, TRUE);
1916
1917 //std::string buf;
1918 //status = db_get_value_string(hDB, 0, "/Experiment/Menu buttons", 0, &buf, FALSE);
1919 //if (status == DB_SUCCESS) {
1920 // cm_msg(MERROR, "init_menu_buttons", "ODB \"/Experiment/Menu buttons\" is obsolete, please delete it.");
1921 //}
1922
1923 check_obsolete_odb(hDB, "/Experiment/Menu buttons");
1924 check_obsolete_odb(hDB, "/Experiment/Menu/OldSequencer");
1925 check_obsolete_odb(hDB, "/Experiment/Menu/NewSequencer");
1926}
1927
1928/*------------------------------------------------------------------*/
1929
1931{
1932 HNDLE hDB;
1933 HNDLE hKey;
1934 int status;
1935 std::string s;
1937
1938 status = db_find_key(hDB, 0, "/Experiment/Base URL", &hKey);
1939 if (status == DB_SUCCESS) {
1940 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Base URL\" is obsolete, please delete it.");
1941 }
1942
1943 status = db_find_key(hDB, 0, "/Experiment/CSS File", &hKey);
1944 if (status == DB_SUCCESS) {
1945 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/CSS File\" is obsolete, please delete it.");
1946 }
1947
1948 status = db_find_key(hDB, 0, "/Experiment/JS File", &hKey);
1949 if (status == DB_SUCCESS) {
1950 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/JS File\" is obsolete, please delete it.");
1951 }
1952
1953 status = db_find_key(hDB, 0, "/Experiment/Start-Stop Buttons", &hKey);
1954 if (status == DB_SUCCESS) {
1955 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Start-Stop Buttons\" is obsolete, please delete it.");
1956 }
1957
1958 bool xdefault = true;
1959 odb->RB("Experiment/Pause-Resume Buttons", &xdefault, true);
1960
1961#ifdef HAVE_MONGOOSE616
1962 check_obsolete_odb(hDB, "/Experiment/midas http port");
1963 check_obsolete_odb(hDB, "/Experiment/midas https port");
1964 check_obsolete_odb(hDB, "/Experiment/http redirect to https");
1965 check_obsolete_odb(hDB, "/Experiment/Security/mhttpd hosts");
1966#endif
1967
1968 status = db_find_key(hDB, 0, "/Logger/Message file", &hKey);
1969 if (status == DB_SUCCESS) {
1970 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.");
1971 }
1972
1973 check_obsolete_odb(hDB, "/Logger/Watchdog timeout");
1974}
1975
1976/*------------------------------------------------------------------*/
1977
1979{
1980 HNDLE hDB;
1981 int size;
1982 HNDLE hkey;
1984
1986 std::string external_elog_url;
1987
1988 size = sizeof(external_elog);
1989 db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
1990 db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
1991
1994 size = sizeof(BOOL);
1995 db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
1996 db_get_value(hDB, 0, "/Elog/Allow edit", &allow_edit, &size, TID_BOOL, TRUE);
1997 //db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL, TRUE);
1998
1999 if (db_find_key(hDB, 0, "/Elog/Buttons", &hkey) != DB_SUCCESS) {
2000 const char def_button[][NAME_LENGTH] = { "8h", "24h", "7d" };
2001 db_set_value(hDB, 0, "/Elog/Buttons", def_button, NAME_LENGTH*3, 3, TID_STRING);
2002 }
2003
2004
2005 /* get type list from ODB */
2006 size = 20 * NAME_LENGTH;
2007 if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS) {
2008 db_set_value(hDB, 0, "/Elog/Types", default_type_list, NAME_LENGTH * 20, 20, TID_STRING);
2009 }
2010
2011 /* get system list from ODB */
2012 size = 20 * NAME_LENGTH;
2013 if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
2014 db_set_value(hDB, 0, "/Elog/Systems", default_system_list, NAME_LENGTH * 20, 20, TID_STRING);
2015}
2016
2017/*------------------------------------------------------------------*/
2018
2019void strencode(Return* r, const char *text)
2020{
2021 size_t len = strlen(text);
2022 for (size_t i = 0; i < len; i++) {
2023 switch (text[i]) {
2024 case '\n':
2025 r->rsprintf("<br>\n");
2026 break;
2027 case '<':
2028 r->rsprintf("&lt;");
2029 break;
2030 case '>':
2031 r->rsprintf("&gt;");
2032 break;
2033 case '&':
2034 r->rsprintf("&amp;");
2035 break;
2036 case '\"':
2037 r->rsprintf("&quot;");
2038 break;
2039 default:
2040 r->rsprintf("%c", text[i]);
2041 }
2042 }
2043}
2044
2045/*------------------------------------------------------------------*/
2046
2047std::string strencode2(const char *text)
2048{
2049 std::string b;
2050 size_t len = strlen(text);
2051 for (size_t i = 0; i < len; i++) {
2052 switch (text[i]) {
2053 case '\n':
2054 b += "<br>\n";
2055 break;
2056 case '<':
2057 b += "&lt;";
2058 break;
2059 case '>':
2060 b += "&gt;";
2061 break;
2062 case '&':
2063 b += "&amp;";
2064 break;
2065 case '\"':
2066 b += "&quot;";
2067 break;
2068 default:
2069 b += text[i];
2070 break;
2071 }
2072 }
2073 return b;
2074}
2075
2076/*------------------------------------------------------------------*/
2077
2078void strencode3(Return* r, const char *text)
2079{
2080 size_t len = strlen(text);
2081 for (size_t i = 0; i < len; i++) {
2082 switch (text[i]) {
2083 case '<':
2084 r->rsprintf("&lt;");
2085 break;
2086 case '>':
2087 r->rsprintf("&gt;");
2088 break;
2089 case '&':
2090 r->rsprintf("&amp;");
2091 break;
2092 case '\"':
2093 r->rsprintf("&quot;");
2094 break;
2095 default:
2096 r->rsprintf("%c", text[i]);
2097 }
2098 }
2099}
2100
2101/*------------------------------------------------------------------*/
2102
2103void strencode4(Return* r, const char *text)
2104{
2105 size_t len = strlen(text);
2106 for (size_t i = 0; i < len; i++) {
2107 switch (text[i]) {
2108 case '\n':
2109 r->rsprintf("<br>\n");
2110 break;
2111 case '<':
2112 r->rsprintf("&lt;");
2113 break;
2114 case '>':
2115 r->rsprintf("&gt;");
2116 break;
2117 case '&':
2118 r->rsprintf("&amp;");
2119 break;
2120 case '\"':
2121 r->rsprintf("&quot;");
2122 break;
2123 case ' ':
2124 r->rsprintf("&nbsp;");
2125 break;
2126 default:
2127 r->rsprintf("%c", text[i]);
2128 }
2129 }
2130}
2131
2132/*------------------------------------------------------------------*/
2133
2134void gen_odb_attachment(Return* r, const char *path, std::string& bout)
2135{
2137 KEY key;
2138 INT i, j, size;
2139 char data[1024];
2140 time_t now;
2141
2143 db_find_key(hDB, 0, path, &hkeyroot);
2144 assert(hkeyroot);
2145
2146 /* title row */
2147 //size = sizeof(str);
2148 //str[0] = 0;
2149 //db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
2150 time(&now);
2151
2152 bout += "<table border=3 cellpadding=1 class=\"dialogTable\">\n";
2153 char ctimebuf[32];
2154 ctime_r(&now, ctimebuf);
2155 bout += msprintf("<tr><th colspan=2>%s</tr>\n", ctimebuf);
2156 bout += msprintf("<tr><th colspan=2>%s</tr>\n", path);
2157
2158 /* enumerate subkeys */
2159 for (i = 0;; i++) {
2161 if (!hkey)
2162 break;
2163 db_get_key(hDB, hkey, &key);
2164
2165 /* resolve links */
2166 if (key.type == TID_LINK) {
2168 db_get_key(hDB, hkey, &key);
2169 }
2170
2171 if (key.type == TID_KEY) {
2172 /* for keys, don't display data value */
2173 bout += msprintf("<tr><td colspan=2>%s</td></tr>\n", key.name);
2174 } else {
2175 /* display single value */
2176 if (key.num_values == 1) {
2177 size = sizeof(data);
2178 db_get_data(hDB, hkey, data, &size, key.type);
2179 //printf("data size %d [%s]\n", size, data);
2180 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2181 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2182
2183 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2184 data_str = "(empty)";
2185 hex_str = "";
2186 }
2187
2188 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2189 //sprintf(b, "<tr><td>%s</td><td>%s (%s)</td></tr>\n", key.name, data_str, hex_str);
2190 bout += "<tr><td>";
2191 bout += key.name;
2192 bout += "</td><td>";
2193 bout += data_str;
2194 bout += " (";
2195 bout += hex_str;
2196 bout += ")</td></tr>\n";
2197 } else {
2198 bout += msprintf("<tr><td>%s</td><td>", key.name);
2199 bout += strencode2(data_str.c_str());
2200 bout += "</td></tr>\n";
2201 }
2202 } else {
2203 /* display first value */
2204 bout += msprintf("<tr><td rowspan=%d>%s</td>\n", key.num_values, key.name);
2205
2206 for (j = 0; j < key.num_values; j++) {
2207 size = sizeof(data);
2208 db_get_data_index(hDB, hkey, data, &size, j, key.type);
2209 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2210 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2211
2212 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2213 data_str = "(empty)";
2214 hex_str = "";
2215 }
2216
2217 if (j > 0) {
2218 bout += "<tr>";
2219 }
2220
2221 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2222 //sprintf(b, "<td>[%d] %s (%s)<br></td></tr>\n", j, data_str, hex_str);
2223 bout += "<td>[";
2224 bout += toString(j);
2225 bout += "] ";
2226 bout += data_str;
2227 bout += " (";
2228 bout += hex_str;
2229 bout += ")<br></td></tr>\n";
2230 } else {
2231 //sprintf(b, "<td>[%d] %s<br></td></tr>\n", j, data_str);
2232 bout += "<td>[";
2233 bout += toString(j);
2234 bout += "] ";
2235 bout += data_str;
2236 bout += "<br></td></tr>\n";
2237 }
2238 }
2239 }
2240 }
2241 }
2242
2243 bout += "</table>\n";
2244}
2245
2246/*------------------------------------------------------------------*/
2247
2249{
2250 char path[256], path1[256];
2251 char mail_to[256], mail_from[256], mail_list[256],
2252 smtp_host[256], tag[80], mail_param[1000];
2253 char *p, *pitem;
2254 HNDLE hDB, hkey;
2255 char att_file[3][256];
2256 int fh, size, n_mail;
2257 char mhttpd_full_url[256];
2258
2260 mstrlcpy(att_file[0], pp->getparam("attachment0"), sizeof(att_file[0]));
2261 mstrlcpy(att_file[1], pp->getparam("attachment1"), sizeof(att_file[1]));
2262 mstrlcpy(att_file[2], pp->getparam("attachment2"), sizeof(att_file[2]));
2263
2264 /* check for valid attachment files */
2265 for (int i = 0; i < 3; i++) {
2266 char str[256];
2267 sprintf(str, "attachment%d", i);
2268 //printf("submit_elog: att %d, [%s] param [%s], size %d\n", i, str, pp->getparam(str), a->_attachment_size[i]);
2269 if (pp->getparam(str) && *pp->getparam(str) && a->attachment_size[i] == 0) {
2270 /* replace '\' by '/' */
2271 mstrlcpy(path, pp->getparam(str), sizeof(path));
2272 mstrlcpy(path1, path, sizeof(path1));
2273 while (strchr(path, '\\'))
2274 *strchr(path, '\\') = '/';
2275
2276 /* check if valid ODB tree */
2277 if (db_find_key(hDB, 0, path, &hkey) == DB_SUCCESS) {
2278 std::string bout;
2279 gen_odb_attachment(r, path, bout);
2280 int bufsize = bout.length()+1;
2281 char* buf = (char*)M_MALLOC(bufsize);
2282 memcpy(buf, bout.c_str(), bufsize);
2283 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2284 mstrlcat(att_file[i], ".html", sizeof(att_file[0]));
2285 a->attachment_buffer[i] = buf;
2287 }
2288 /* check if local file */
2289 else if ((fh = open(path1, O_RDONLY | O_BINARY)) >= 0) {
2290 size = lseek(fh, 0, SEEK_END);
2291 char* buf = (char*)M_MALLOC(size);
2292 lseek(fh, 0, SEEK_SET);
2293 int rd = read(fh, buf, size);
2294 if (rd < 0)
2295 rd = 0;
2296 close(fh);
2297 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2298 a->attachment_buffer[i] = buf;
2299 a->attachment_size[i] = rd;
2300 } else if (strncmp(path, "/HS/", 4) == 0) {
2301 char* buf = (char*)M_MALLOC(100000);
2302 size = 100000;
2303 mstrlcpy(str, path + 4, sizeof(str));
2304 if (strchr(str, '?')) {
2305 p = strchr(str, '?') + 1;
2306 p = strtok(p, "&");
2307 while (p != NULL) {
2308 pitem = p;
2309 p = strchr(p, '=');
2310 if (p != NULL) {
2311 *p++ = 0;
2312 urlDecode(pitem); // parameter name
2313 urlDecode(p); // parameter value
2314
2315 pp->setparam(pitem, p);
2316
2317 p = strtok(NULL, "&");
2318 }
2319 }
2320 *strchr(str, '?') = 0;
2321 }
2322 show_hist_page(odb, pp, r, "image.gif", buf, &size, 0);
2323 mstrlcpy(att_file[i], str, sizeof(att_file[0]));
2324 a->attachment_buffer[i] = buf;
2325 a->attachment_size[i] = size;
2326 pp->unsetparam("scale");
2327 pp->unsetparam("offset");
2328 pp->unsetparam("width");
2329 pp->unsetparam("index");
2330 } else {
2331 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2332 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2333 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
2334
2335 r->rsprintf("<html><head>\n");
2336 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
2337 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
2338 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
2339 r->rsprintf("<title>ELog Error</title></head>\n");
2340 r->rsprintf("<i>Error: Attachment file <i>%s</i> not valid.</i><p>\n", pp->getparam(str));
2341 r->rsprintf("Please go back and enter a proper filename (use the <b>Browse</b> button).\n");
2342 r->rsprintf("<body></body></html>\n");
2343 return;
2344 }
2345 }
2346 }
2347
2348 int edit = atoi(pp->getparam("edit"));
2349 //printf("submit_elog: edit [%s] %d, orig [%s]\n", pp->getparam("edit"), edit, pp->getparam("orig"));
2350
2351 tag[0] = 0;
2352 if (edit) {
2353 mstrlcpy(tag, pp->getparam("orig"), sizeof(tag));
2354 }
2355
2356 int status = el_submit(atoi(pp->getparam("run")),
2357 pp->getparam("author"),
2358 pp->getparam("type"),
2359 pp->getparam("system"),
2360 pp->getparam("subject"),
2361 pp->getparam("text"),
2362 pp->getparam("orig"),
2363 *pp->getparam("html") ? "HTML" : "plain",
2367 tag, sizeof(tag));
2368
2369 //printf("el_submit status %d, tag [%s]\n", status, tag);
2370
2371 if (status != EL_SUCCESS) {
2372 cm_msg(MERROR, "submit_elog", "el_submit() returned status %d", status);
2373 }
2374
2375 /* supersede host name with "/Elog/Host name" */
2376 std::string elog_host_name;
2377 db_get_value_string(hDB, 0, "/Elog/Host name", 0, &elog_host_name, TRUE);
2378
2379 // K.O. FIXME: we cannot guess the Elog URL like this because
2380 // we do not know if access is through a proxy or redirect
2381 // we do not know if it's http: or https:, etc. Better
2382 // to read the whole "mhttpd_full_url" string from ODB.
2383 sprintf(mhttpd_full_url, "http://%s/", elog_host_name.c_str());
2384
2385 /* check for mail submissions */
2386 mail_param[0] = 0;
2387 n_mail = 0;
2388
2389 for (int index = 0; index <= 1; index++) {
2390 std::string str;
2391 str += "/Elog/Email ";
2392 if (index == 0)
2393 str += pp->getparam("type");
2394 else
2395 str += pp->getparam("system");
2396
2397 if (db_find_key(hDB, 0, str.c_str(), &hkey) == DB_SUCCESS) {
2398 size = sizeof(mail_list);
2400
2401 if (db_find_key(hDB, 0, "/Elog/SMTP host", &hkey) != DB_SUCCESS) {
2402 show_error(r, "No SMTP host defined under /Elog/SMTP host");
2403 return;
2404 }
2405 size = sizeof(smtp_host);
2407
2408 p = strtok(mail_list, ",");
2409 while (1) {
2410 mstrlcpy(mail_to, p, sizeof(mail_to));
2411
2412 std::string exptname;
2413 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
2414
2415 sprintf(mail_from, "MIDAS %s <MIDAS@%s>", exptname.c_str(), elog_host_name.c_str());
2416
2417 std::string mail_text;
2418 mail_text += "A new entry has been submitted by ";
2419 mail_text += pp->getparam("author");
2420 mail_text += "\n";
2421 mail_text += "\n";
2422
2423 mail_text += "Experiment : ";
2424 mail_text += exptname.c_str();
2425 mail_text += "\n";
2426
2427 mail_text += "Type : ";
2428 mail_text += pp->getparam("type");
2429 mail_text += "\n";
2430
2431 mail_text += "System : ";
2432 mail_text += pp->getparam("system");
2433 mail_text += "\n";
2434
2435 mail_text += "Subject : ";
2436 mail_text += pp->getparam("subject");
2437 mail_text += "\n";
2438
2439 mail_text += "Link : ";
2441 mail_text += "/EL/";
2442 mail_text += tag;
2443 mail_text += "\n";
2444
2445 mail_text += "\n";
2446
2447 mail_text += pp->getparam("text");
2448 mail_text += "\n";
2449
2450 sendmail(elog_host_name.c_str(), smtp_host, mail_from, mail_to, pp->getparam("type"), mail_text.c_str());
2451
2452 if (mail_param[0] == 0)
2453 mstrlcpy(mail_param, "?", sizeof(mail_param));
2454 else
2455 mstrlcat(mail_param, "&", sizeof(mail_param));
2456 sprintf(mail_param + strlen(mail_param), "mail%d=%s", n_mail++, mail_to);
2457
2458 p = strtok(NULL, ",");
2459 if (!p)
2460 break;
2461 while (*p == ' ')
2462 p++;
2463 }
2464 }
2465 }
2466
2467 r->rsprintf("HTTP/1.1 302 Found\r\n");
2468 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2469
2470 //if (mail_param[0])
2471 // r->rsprintf("Location: ../EL/%s?%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2472 //else
2473 // r->rsprintf("Location: ../EL/%s\n\n<html>redir</html>\r\n", tag);
2474
2475 if (mail_param[0])
2476 r->rsprintf("Location: ?cmd=Show+elog&tag=%s&%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2477 else
2478 r->rsprintf("Location: ?cmd=Show+elog&tag=%s\n\n<html>redir</html>\r\n", tag);
2479}
2480
2481/*------------------------------------------------------------------*/
2482
2483void show_elog_attachment(Param* p, Return* r, const char* path)
2484{
2485 HNDLE hDB;
2486 int size;
2487 int status;
2488 char file_name[256];
2489
2491 file_name[0] = 0;
2492 if (hDB > 0) {
2493 size = sizeof(file_name);
2494 memset(file_name, 0, size);
2495
2496 status = db_get_value(hDB, 0, "/Logger/Elog dir", file_name, &size, TID_STRING, FALSE);
2497 if (status != DB_SUCCESS)
2498 db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
2499
2500 if (file_name[0] != 0)
2503 }
2504 mstrlcat(file_name, path, sizeof(file_name));
2505
2506 int fh = open(file_name, O_RDONLY | O_BINARY);
2507 if (fh > 0) {
2508 lseek(fh, 0, SEEK_END);
2509 int length = TELL(fh);
2510 lseek(fh, 0, SEEK_SET);
2511
2512 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2513 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2514 r->rsprintf("Accept-Ranges: bytes\r\n");
2515 //r->rsprintf("Content-disposition: attachment; filename=%s\r\n", path);
2516
2517 r->rsprintf("Content-Type: %s\r\n", get_content_type(file_name).c_str());
2518
2519 r->rsprintf("Content-Length: %d\r\n\r\n", length);
2520
2521 r->rread(file_name, fh, length);
2522
2523 close(fh);
2524 }
2525
2526 return;
2527}
2528
2529/*------------------------------------------------------------------*/
2530
2532{
2533 HNDLE hDB, hkey;
2534 KEY key;
2535 char str[256];
2536 int i, size;
2537
2539 sprintf(str, "/Equipment/%s/Settings/Editable", eq_name);
2540 db_find_key(hDB, 0, str, &hkey);
2541
2542 /* if no editable entry found, use default */
2543 if (!hkey) {
2544 return (equal_ustring(var_name, "Demand") ||
2545 equal_ustring(var_name, "Output") || strncmp(var_name, "D_", 2) == 0);
2546 }
2547
2548 db_get_key(hDB, hkey, &key);
2549 for (i = 0; i < key.num_values; i++) {
2550 size = sizeof(str);
2553 return TRUE;
2554 }
2555 return FALSE;
2556}
2557
2558void show_eqtable_page(Param* pp, Return* r, int refresh)
2559{
2560 int i, j, k, colspan, size, n_var, i_edit, i_set, line;
2561 char eq_name[32], group[32];
2562 char group_name[MAX_GROUPS][32], data[256], style[80];
2563 HNDLE hDB;
2564 char odb_path[256];
2565
2567
2568 /* check if variable to edit */
2569 i_edit = -1;
2570 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2571 i_edit = atoi(pp->getparam("index"));
2572
2573 /* check if variable to set */
2574 i_set = -1;
2575 if (equal_ustring(pp->getparam("cmd"), "Set"))
2576 i_set = atoi(pp->getparam("index"));
2577
2578 /* get equipment and group */
2579 if (pp->getparam("eq"))
2580 mstrlcpy(eq_name, pp->getparam("eq"), sizeof(eq_name));
2581 mstrlcpy(group, "All", sizeof(group));
2582 if (pp->getparam("group") && *pp->getparam("group"))
2583 mstrlcpy(group, pp->getparam("group"), sizeof(group));
2584
2585#if 0
2586 /* check for "names" in settings */
2587 if (eq_name[0]) {
2588 sprintf(str, "/Equipment/%s/Settings", eq_name);
2589 HNDLE hkeyset;
2590 db_find_key(hDB, 0, str, &hkeyset);
2591 HNDLE hkeynames = 0;
2592 if (hkeyset) {
2593 for (i = 0;; i++) {
2595
2596 if (!hkeynames)
2597 break;
2598
2599 KEY key;
2601
2602 if (strncmp(key.name, "Names", 5) == 0)
2603 break;
2604 }
2605 }
2606
2607 /* redirect if no names found */
2608 if (!hkeyset || !hkeynames) {
2609 /* redirect */
2610 sprintf(str, "?cmd=odb&odb_path=/Equipment/%s/Variables", eq_name);
2611 redirect(r, str);
2612 return;
2613 }
2614 }
2615#endif
2616
2617 show_header(r, "MIDAS slow control", "", group, i_edit == -1 ? refresh : 0);
2618 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
2619 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
2620 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
2621 show_navigation_bar(r, "SC");
2622
2623 /*---- menu buttons ----*/
2624
2625 r->rsprintf("<tr><td colspan=15>\n");
2626
2627 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2628 r->rsprintf("<input type=submit name=cmd value=Set>\n");
2629
2630 r->rsprintf("</tr>\n\n");
2631 r->rsprintf("</table>"); //end header table
2632
2633 r->rsprintf("<table class=\"ODBtable\" style=\"max-width:700px;\">"); //body table
2634
2635 /*---- enumerate SC equipment ----*/
2636
2637 r->rsprintf("<tr><td class=\"subStatusTitle\" colspan=15><i>Equipment:</i> &nbsp;&nbsp;\n");
2638
2640 db_find_key(hDB, 0, "/Equipment", &hkeyeqroot);
2641 if (hkeyeqroot)
2642 for (i = 0;; i++) {
2643 HNDLE hkeyeq;
2645
2646 if (!hkeyeq)
2647 break;
2648
2649 KEY eqkey;
2651
2652 HNDLE hkeyset;
2653 db_find_key(hDB, hkeyeq, "Settings", &hkeyset);
2654 if (hkeyset) {
2655 for (j = 0;; j++) {
2658
2659 if (!hkeynames)
2660 break;
2661
2662 KEY key;
2664
2665 if (strncmp(key.name, "Names", 5) == 0) {
2666 if (equal_ustring(eq_name, eqkey.name))
2667 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", eqkey.name);
2668 else {
2669 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">%s</a> &nbsp;&nbsp;", urlEncode(eqkey.name).c_str(), eqkey.name);
2670 }
2671 break;
2672 }
2673 }
2674 }
2675 }
2676 r->rsprintf("</tr>\n");
2677
2678 if (!eq_name[0]) {
2679 r->rsprintf("</table>");
2680 return;
2681 }
2682
2683 /*---- display SC ----*/
2684
2685 n_var = 0;
2686 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2688 db_find_key(hDB, 0, names_path.c_str(), &hkeyeqnames);
2689
2690 if (hkeyeqnames) {
2691
2692 /*---- single name array ----*/
2693 r->rsprintf("<tr><td colspan=15><i>Groups:</i> &nbsp;&nbsp;");
2694
2695 /* "all" group */
2696 if (equal_ustring(group, "All"))
2697 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2698 else
2699 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2700
2701 /* collect groups */
2702
2703 memset(group_name, 0, sizeof(group_name));
2704 KEY key;
2706
2707 for (int level = 0; ; level++) {
2708 bool next_level = false;
2709 for (i = 0; i < key.num_values; i++) {
2710 char name_str[256];
2711 size = sizeof(name_str);
2713
2714 char *s = strchr(name_str, '%');
2715 for (int k=0; s && k<level; k++)
2716 s = strchr(s+1, '%');
2717
2718 if (s) {
2719 *s = 0;
2720 if (strchr(s+1, '%'))
2721 next_level = true;
2722
2723 //printf("try group [%s] name [%s], level %d, %d\n", name_str, s+1, level, next_level);
2724
2725 for (j = 0; j < MAX_GROUPS; j++) {
2726 if (equal_ustring(group_name[j], name_str) || group_name[j][0] == 0)
2727 break;
2728 }
2729 if (group_name[j][0] == 0)
2730 mstrlcpy(group_name[j], name_str, sizeof(group_name[0]));
2731 }
2732 }
2733
2734 if (!next_level)
2735 break;
2736 }
2737
2738 for (i = 0; i < MAX_GROUPS && group_name[i][0]; i++) {
2740 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", group_name[i]);
2741 else {
2742 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s&group=%s\">%s</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str(), urlEncode(group_name[i]).c_str(), group_name[i]);
2743 }
2744 }
2745
2746 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2747 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2748 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2749 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2750 r->rsprintf("</tr>\n");
2751
2752 /* count variables */
2753 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2754 HNDLE hkeyvar;
2755 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2756 if (!hkeyvar) {
2757 r->rsprintf("</table>");
2758 return;
2759 }
2760 for (i = 0;; i++) {
2761 HNDLE hkey;
2763 if (!hkey)
2764 break;
2765 }
2766
2767 if (i == 0 || i > 15) {
2768 r->rsprintf("</table>");
2769 return;
2770 }
2771
2772 /* title row */
2773 colspan = 15 - i;
2774 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=%d>Names", colspan);
2775
2776 /* display entries for this group */
2777 for (int i = 0;; i++) {
2778 HNDLE hkey;
2780
2781 if (!hkey)
2782 break;
2783
2784 KEY key;
2785 db_get_key(hDB, hkey, &key);
2786 r->rsprintf("<th>%s", key.name);
2787 }
2788
2789 r->rsprintf("</tr>\n");
2790
2791 /* data for current group */
2792 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2793 int num_values = 0;
2795 db_find_key(hDB, 0, names_path.c_str(), &hnames_key);
2796 if (hnames_key) {
2797 KEY names_key;
2799 num_values = names_key.num_values;
2800 }
2801 for (int i = 0; i < num_values; i++) {
2802 char names_str[256];
2803 size = sizeof(names_str);
2805
2806 char name[NAME_LENGTH+32];
2807 mstrlcpy(name, names_str, sizeof(name));
2808
2809 //printf("group [%s], name [%s], str [%s]\n", group, name, names_str);
2810
2811 if (!equal_ustring(group, "All")) {
2812 // check if name starts with the name of the group we want to display
2813 char *s = strstr(name, group);
2814 if (s != name)
2815 continue;
2816 if (name[strlen(group)] != '%')
2817 continue;
2818 }
2819
2820 if (strlen(name) < 1)
2821 sprintf(name, "[%d]", i);
2822
2823 if (i % 2 == 0)
2824 r->rsprintf("<tr class=\"ODBtableEven\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2825 else
2826 r->rsprintf("<tr class=\"ODBtableOdd\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2827
2828 for (int j = 0;; j++) {
2829 HNDLE hkey;
2831 if (!hkey)
2832 break;
2833
2834 KEY varkey;
2836
2837 /* check if "variables" array is shorter than the "names" array */
2838 if (i >= varkey.num_values)
2839 continue;
2840
2841 size = sizeof(data);
2842 db_get_data_index(hDB, hkey, data, &size, i, varkey.type);
2843 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
2844
2845 if (is_editable(eq_name, varkey.name)) {
2846 if (n_var == i_set) {
2847 /* set value */
2848 char str[256];
2849 mstrlcpy(str, pp->getparam("value"), sizeof(str));
2850 db_sscanf(str, data, &size, 0, varkey.type);
2851 db_set_data_index(hDB, hkey, data, size, i, varkey.type);
2852
2853 /* redirect (so that 'reload' does not reset value) */
2854 r->reset();
2855 redirect(r, group);
2856 return;
2857 }
2858 if (n_var == i_edit) {
2859 r->rsprintf("<td align=center>");
2860 r->rsprintf("<input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
2861 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
2862 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
2863 n_var++;
2864 } else {
2865 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, i);
2866 r->rsprintf("<td align=center>");
2867 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
2868 n_var++;
2869 }
2870 } else
2871 r->rsprintf("<td align=center>%s", data_str.c_str());
2872 }
2873
2874 r->rsprintf("</tr>\n");
2875 }
2876 } else {
2877 /*---- multiple name arrays ----*/
2878 r->rsprintf("<tr><td colspan=15><i>Groups:</i> ");
2879
2880 /* "all" group */
2881 if (equal_ustring(group, "All"))
2882 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2883 else
2884 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", eq_name);
2885
2886 /* groups from Variables tree */
2887
2888 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2889 HNDLE hkeyvar;
2890 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2891
2892 if (hkeyvar) {
2893 for (int i = 0;; i++) {
2894 HNDLE hkey;
2896
2897 if (!hkey)
2898 break;
2899
2900 KEY key;
2901 db_get_key(hDB, hkey, &key);
2902
2903 if (equal_ustring(key.name, group)) {
2904 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", key.name);
2905 } else {
2906 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s&group=%s\">%s</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str(), urlEncode(key.name).c_str(), key.name);
2907 }
2908 }
2909 }
2910
2911 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2912 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2913 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2914 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2915 r->rsprintf("</tr>\n");
2916
2917 /* enumerate variable arrays */
2918 line = 0;
2919 for (i = 0;; i++) {
2920 HNDLE hkey;
2922
2923 if (line % 2 == 0)
2924 mstrlcpy(style, "ODBtableEven", sizeof(style));
2925 else
2926 mstrlcpy(style, "ODBtableOdd", sizeof(style));
2927
2928 if (!hkey)
2929 break;
2930
2931 KEY varkey;
2933
2934 if (!equal_ustring(group, "All") && !equal_ustring(varkey.name, group))
2935 continue;
2936
2937 /* title row */
2938 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=9>Names<th>%s</tr>\n", varkey.name);
2939
2940 if (varkey.type == TID_KEY) {
2942
2943 /* enumerate subkeys */
2944 for (j = 0;; j++) {
2946 if (!hkey)
2947 break;
2948
2949 KEY key;
2950 db_get_key(hDB, hkey, &key);
2951
2952 if (key.type == TID_KEY) {
2953 /* for keys, don't display data value */
2954 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<br></tr>\n", style, key.name);
2955 } else {
2956 /* display single value */
2957 if (key.num_values == 1) {
2958 size = sizeof(data);
2959 db_get_data(hDB, hkey, data, &size, key.type);
2960
2961 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2962 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2963
2964 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2965 data_str = "(empty)";
2966 hex_str = "";
2967 }
2968
2969 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
2970 r->rsprintf
2971 ("<tr class=\"%s\" ><td colspan=9>%s<td align=center>%s (%s)<br></tr>\n",
2972 style, key.name, data_str.c_str(), hex_str.c_str());
2973 else
2974 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center>%s<br></tr>\n",
2975 style, key.name, data_str.c_str());
2976 line++;
2977 } else {
2978 /* display first value */
2979 r->rsprintf("<tr class=\"%s\"><td colspan=9 rowspan=%d>%s\n", style, key.num_values,
2980 key.name);
2981
2982 for (k = 0; k < key.num_values; k++) {
2983 size = sizeof(data);
2984 db_get_data_index(hDB, hkey, data, &size, k, key.type);
2985 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2986 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2987
2988 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2989 data_str = "(empty)";
2990 hex_str = "";
2991 }
2992
2993 if (k > 0)
2994 r->rsprintf("<tr>");
2995
2996 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
2997 r->rsprintf("<td>[%d] %s (%s)<br></tr>\n", k, data_str.c_str(), hex_str.c_str());
2998 else
2999 r->rsprintf("<td>[%d] %s<br></tr>\n", k, data_str.c_str());
3000 line++;
3001 }
3002 }
3003 }
3004 }
3005 } else {
3006 /* data for current group */
3007 std::string names_path = msprintf("/Equipment/%s/Settings/Names %s", eq_name, varkey.name);
3008 HNDLE hkeyset;
3009 db_find_key(hDB, 0, names_path.c_str(), &hkeyset);
3010 KEY key;
3011 if (hkeyset)
3013
3014 if (varkey.num_values > 1000)
3015 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center><i>... %d values ...</i>",
3016 style, varkey.name, varkey.num_values);
3017 else {
3018 for (j = 0; j < varkey.num_values; j++) {
3019
3020 if (line % 2 == 0)
3021 mstrlcpy(style, "ODBtableEven", sizeof(style));
3022 else
3023 mstrlcpy(style, "ODBtableOdd", sizeof(style));
3024
3025 char name[NAME_LENGTH+32];
3026 if (hkeyset && j<key.num_values) {
3027 size = sizeof(name);
3029 } else {
3030 sprintf(name, "%s[%d]", varkey.name, j);
3031 }
3032
3033 if (strlen(name) < 1) {
3034 sprintf(name, "%s[%d]", varkey.name, j);
3035 }
3036
3037 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s", style, name);
3038
3039 size = sizeof(data);
3040 db_get_data_index(hDB, hkey, data, &size, j, varkey.type);
3041 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
3042
3043 if (is_editable(eq_name, varkey.name)) {
3044 if (n_var == i_set) {
3045 /* set value */
3046 char str[256];
3047 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3048 db_sscanf(str, data, &size, 0, varkey.type);
3049 db_set_data_index(hDB, hkey, data, size, j, varkey.type);
3050
3051 /* redirect (so that 'reload' does not reset value) */
3052 r->reset();
3053 sprintf(str, "%s", group);
3054 redirect(r, str);
3055 return;
3056 }
3057 if (n_var == i_edit) {
3058 r->rsprintf("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
3059 r->rsprintf("<input type=submit size=20 name=cmd value=Set></tr>\n");
3060 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
3061 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3062 n_var++;
3063 } else {
3064 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, j);
3065
3066 r->rsprintf("<td align=cernter>");
3067 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
3068 n_var++;
3069 }
3070
3071 } else
3072 r->rsprintf("<td align=center>%s\n", data_str.c_str());
3073 r->rsprintf("</tr>\n");
3074 line++;
3075 }
3076 }
3077
3078 r->rsprintf("</tr>\n");
3079 }
3080 }
3081 }
3082
3083 r->rsprintf("</table>\n");
3084 r->rsprintf("</div>\n"); // closing for <div id="mmain">
3085 r->rsprintf("</form>\n");
3086 r->rsprintf("</body></html>\r\n");
3087}
3088
3089/*------------------------------------------------------------------*/
3090
3091char *find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
3092{
3093 char str[256], *ps, *pt;
3095
3096 *edit = 0;
3097 *tail = 0;
3098 *format = 0;
3099 pwd[0] = 0;
3100 in_script = FALSE;
3101 strcpy(type, "text");
3102 do {
3103 while (*p && *p != '<')
3104 p++;
3105
3106 /* return if end of string reached */
3107 if (!*p)
3108 return NULL;
3109
3110 p++;
3111 while (*p && ((*p == ' ') || iscntrl(*p)))
3112 p++;
3113
3114 strncpy(str, p, 6);
3115 str[6] = 0;
3116 if (equal_ustring(str, "script"))
3117 in_script = TRUE;
3118
3119 strncpy(str, p, 7);
3120 str[7] = 0;
3121 if (equal_ustring(str, "/script"))
3122 in_script = FALSE;
3123
3124 strncpy(str, p, 4);
3125 str[4] = 0;
3126 if (equal_ustring(str, "odb ")) {
3127 ps = p - 1;
3128 p += 4;
3129 while (*p && ((*p == ' ') || iscntrl(*p)))
3130 p++;
3131
3132 do {
3133 strncpy(str, p, 7);
3134 str[7] = 0;
3135 if (equal_ustring(str, "format=")) {
3136 p += 7;
3137 if (*p == '\"') {
3138 p++;
3139 while (*p && *p != '\"')
3140 *format++ = *p++;
3141 *format = 0;
3142 if (*p == '\"')
3143 p++;
3144 } else {
3145 while (*p && *p != ' ' && *p != '>')
3146 *format++ = *p++;
3147 *format = 0;
3148 }
3149
3150 } else {
3151
3152 strncpy(str, p, 4);
3153 str[4] = 0;
3154 if (equal_ustring(str, "src=")) {
3155 p += 4;
3156 if (*p == '\"') {
3157 p++;
3158 while (*p && *p != '\"')
3159 *path++ = *p++;
3160 *path = 0;
3161 if (*p == '\"')
3162 p++;
3163 } else {
3164 while (*p && *p != ' ' && *p != '>')
3165 *path++ = *p++;
3166 *path = 0;
3167 }
3168 } else {
3169
3170 if (in_script)
3171 break;
3172
3173 strncpy(str, p, 5);
3174 str[5] = 0;
3175 if (equal_ustring(str, "edit=")) {
3176 p += 5;
3177
3178 if (*p == '\"') {
3179 p++;
3180 *edit = atoi(p);
3181 if (*p == '\"')
3182 p++;
3183 } else {
3184 *edit = atoi(p);
3185 while (*p && *p != ' ' && *p != '>')
3186 p++;
3187 }
3188
3189 } else {
3190
3191 strncpy(str, p, 5);
3192 str[5] = 0;
3193 if (equal_ustring(str, "type=")) {
3194 p += 5;
3195 if (*p == '\"') {
3196 p++;
3197 while (*p && *p != '\"')
3198 *type++ = *p++;
3199 *type = 0;
3200 if (*p == '\"')
3201 p++;
3202 } else {
3203 while (*p && *p != ' ' && *p != '>')
3204 *type++ = *p++;
3205 *type = 0;
3206 }
3207 } else {
3208 strncpy(str, p, 4);
3209 str[4] = 0;
3210 if (equal_ustring(str, "pwd=")) {
3211 p += 4;
3212 if (*p == '\"') {
3213 p++;
3214 while (*p && *p != '\"')
3215 *pwd++ = *p++;
3216 *pwd = 0;
3217 if (*p == '\"')
3218 p++;
3219 } else {
3220 while (*p && *p != ' ' && *p != '>')
3221 *pwd++ = *p++;
3222 *pwd = 0;
3223 }
3224 } else {
3225 if (strchr(p, '=')) {
3226 mstrlcpy(str, p, sizeof(str));
3227 pt = strchr(str, '=')+1;
3228 if (*pt == '\"') {
3229 pt++;
3230 while (*pt && *pt != '\"')
3231 pt++;
3232 if (*pt == '\"')
3233 pt++;
3234 *pt = 0;
3235 } else {
3236 while (*pt && *pt != ' ' && *pt != '>')
3237 pt++;
3238 *pt = 0;
3239 }
3240 if (tail[0]) {
3241 mstrlcat(tail, " ", 256);
3242 mstrlcat(tail, str, 256);
3243 } else {
3244 mstrlcat(tail, str, 256);
3245 }
3246 p += strlen(str);
3247 }
3248 }
3249 }
3250 }
3251 }
3252 }
3253
3254 while (*p && ((*p == ' ') || iscntrl(*p)))
3255 p++;
3256
3257 if (*p == '<') {
3258 cm_msg(MERROR, "find_odb_tag", "Invalid odb tag '%s'", ps);
3259 return NULL;
3260 }
3261 } while (*p != '>');
3262
3263 return ps;
3264 }
3265
3266 while (*p && *p != '>')
3267 p++;
3268
3269 } while (1);
3270
3271}
3272
3273/*------------------------------------------------------------------*/
3274
3275void 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)
3276{
3277 int size, index, i_edit, i_set;
3278 char data[TEXT_SIZE], full_keypath[256], keypath[256], *p;
3279 HNDLE hDB, hkey;
3280 KEY key;
3281
3282 /* check if variable to edit */
3283 i_edit = -1;
3284 if (equal_ustring(pp->getparam("cmd"), "Edit"))
3285 i_edit = atoi(pp->getparam("index"));
3286
3287 /* check if variable to set */
3288 i_set = -1;
3289 if (equal_ustring(pp->getparam("cmd"), "Set"))
3290 i_set = atoi(pp->getparam("index"));
3291
3292 /* check if path contains index */
3294 mstrlcpy(keypath, keypath1, sizeof(keypath));
3295 index = 0;
3296
3297 if (strchr(keypath, '[') && strchr(keypath, ']')) {
3298 for (p = strchr(keypath, '[') + 1; *p && *p != ']'; p++)
3299 if (!isdigit(*p))
3300 break;
3301
3302 if (*p && *p == ']') {
3303 index = atoi(strchr(keypath, '[') + 1);
3304 *strchr(keypath, '[') = 0;
3305 }
3306 }
3307
3309 db_find_key(hDB, 0, keypath, &hkey);
3310 if (!hkey)
3311 r->rsprintf("<b>Key \"%s\" not found in ODB</b>\n", keypath);
3312 else {
3313 db_get_key(hDB, hkey, &key);
3314 size = sizeof(data);
3316
3317 std::string data_str;
3318 if (format && strlen(format)>0)
3319 data_str = db_sprintff(format, data, key.item_size, 0, key.type);
3320 else
3322
3323 if (equal_ustring(type, "checkbox")) {
3324
3325 if (pp->isparam("cbi"))
3326 i_set = atoi(pp->getparam("cbi"));
3327 if (n_var == i_set) {
3328 /* toggle state */
3329 if (key.type == TID_BOOL) {
3330 if (data_str[0] == 'y')
3331 data_str = "n";
3332 else
3333 data_str = "y";
3334 } else {
3335 if (atoi(data_str.c_str()) > 0)
3336 data_str = "0";
3337 else
3338 data_str = "1";
3339 }
3340
3341 db_sscanf(data_str.c_str(), data, &size, 0, key.type);
3343 }
3344
3345 std::string options;
3346 if (data_str[0] == 'y' || atoi(data_str.c_str()) > 0)
3347 options += "checked ";
3348 if (!edit)
3349 options += "disabled ";
3350 else {
3351 if (edit == 1) {
3352 options += "onClick=\"o=document.createElement('input');o.type='hidden';o.name='cbi';o.value='";
3353 options += msprintf("%d", n_var);
3354 options += "';document.form1.appendChild(o);";
3355 options += "document.form1.submit();\" ";
3356 }
3357 }
3358
3359 if (tail[0])
3360 options += tail;
3361
3362 r->rsprintf("<input type=\"checkbox\" %s>\n", options.c_str());
3363
3364 } else { // checkbox
3365
3366 if (edit == 1) {
3367 if (n_var == i_set) {
3368 /* set value */
3369 char str[256];
3370 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3371 db_sscanf(str, data, &size, 0, key.type);
3373
3374 /* read back value */
3375 size = sizeof(data);
3378 }
3379
3380 if (n_var == i_edit) {
3381 r->rsprintf("<input type=text size=10 maxlength=80 name=value value=\"%s\">\n", data_str.c_str());
3382 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
3383 r->rsprintf("<input type=hidden name=index value=%d>\n", n_var);
3384 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3385 } else {
3386 if (edit == 2) {
3387 /* edit handling through user supplied JavaScript */
3388 r->rsprintf("<a href=\"#\" %s>", tail);
3389 } else {
3390 /* edit handling through form submission */
3391 if (pwd[0]) {
3392 r->rsprintf("<a onClick=\"promptpwd('%s?cmd=Edit&index=%d&pnam=%s')\" href=\"#\">", path, n_var, pwd);
3393 } else {
3394 r->rsprintf("<a href=\"%s?cmd=Edit&index=%d\" %s>", path, n_var, tail);
3395 }
3396 }
3397
3398 r->rsputs(data_str.c_str());
3399 r->rsprintf("</a>");
3400 }
3401 } else if (edit == 2) {
3402 r->rsprintf("<a href=\"#\" onclick=\"ODBEdit('%s')\">\n", full_keypath);
3403 r->rsputs(data_str.c_str());
3404 r->rsprintf("</a>");
3405 }
3406 else
3407 r->rsputs(data_str.c_str());
3408 }
3409 }
3410}
3411
3412/*------------------------------------------------------------------*/
3413
3414/* add labels using following syntax under /Custom/Images/<name.gif>/Labels/<name>:
3415
3416 [Name] [Description] [Example]
3417
3418 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3419 Format Formt for float/double %1.2f Deg. C
3420 Font Font to use small | medium | giant
3421 X X-position in pixel 90
3422 Y Y-position from top 67
3423 Align horizontal align left/center/right left
3424 FGColor Foreground color RRGGBB 000000
3425 BGColor Background color RRGGBB FFFFFF
3426*/
3427
3428static const char *cgif_label_str[] = {
3429 "Src = STRING : [256] ",
3430 "Format = STRING : [32] %1.1f",
3431 "Font = STRING : [32] Medium",
3432 "X = INT : 0",
3433 "Y = INT : 0",
3434 "Align = INT : 0",
3435 "FGColor = STRING : [8] 000000",
3436 "BGColor = STRING : [8] FFFFFF",
3437 NULL
3438};
3439
3440typedef struct {
3441 char src[256];
3442 char format[32];
3443 char font[32];
3444 int x, y, align;
3445 char fgcolor[8];
3446 char bgcolor[8];
3447} CGIF_LABEL;
3448
3449/* add labels using following syntax under /Custom/Images/<name.gif>/Bars/<name>:
3450
3451 [Name] [Description] [Example]
3452
3453 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3454 X X-position in pixel 90
3455 Y Y-position from top 67
3456 Width Width in pixel 20
3457 Height Height in pixel 100
3458 Direction 0(vertical)/1(horiz.) 0
3459 Axis Draw axis 0(none)/1(left)/2(right) 1
3460 Logscale Draw logarithmic axis n
3461 Min Min value for axis 0
3462 Max Max value for axis 10
3463 FGColor Foreground color RRGGBB 000000
3464 BGColor Background color RRGGBB FFFFFF
3465 BDColor Border color RRGGBB 808080
3466*/
3467
3468static const char *cgif_bar_str[] = {
3469 "Src = STRING : [256] ",
3470 "X = INT : 0",
3471 "Y = INT : 0",
3472 "Width = INT : 10",
3473 "Height = INT : 100",
3474 "Direction = INT : 0",
3475 "Axis = INT : 1",
3476 "Logscale = BOOL : n",
3477 "Min = DOUBLE : 0",
3478 "Max = DOUBLE : 10",
3479 "FGColor = STRING : [8] 000000",
3480 "BGColor = STRING : [8] FFFFFF",
3481 "BDColor = STRING : [8] 808080",
3482 NULL
3483};
3484
3485typedef struct {
3486 char src[256];
3487 int x, y, width, height, direction, axis;
3489 double min, max;
3490 char fgcolor[8];
3491 char bgcolor[8];
3492 char bdcolor[8];
3493} CGIF_BAR;
3494
3495/*------------------------------------------------------------------*/
3496
3497int evaluate_src(char *key, char *src, double *fvalue)
3498{
3499 HNDLE hDB, hkeyval;
3500 KEY vkey;
3501 int i, n, size, ivalue;
3502 char str[256], data[256];
3503
3505
3506 /* separate source from operators */
3507 for (i=0 ; i<(int)strlen(src) ; i++)
3508 if (src[i] == '>' || src[i] == '&')
3509 break;
3510 strncpy(str, src, i);
3511 str[i] = 0;
3512
3513 /* strip trailing blanks */
3514 while (strlen(str) > 0 && str[strlen(str)-1] == ' ')
3515 str[strlen(str)-1] = 0;
3516
3517 db_find_key(hDB, 0, str, &hkeyval);
3518 if (!hkeyval) {
3519 cm_msg(MERROR, "evaluate_src", "Invalid Src key \"%s\" for Fill \"%s\"",
3520 src, key);
3521 return 0;
3522 }
3523
3525 size = sizeof(data);
3526 db_get_value(hDB, 0, src, data, &size, vkey.type, FALSE);
3527 std::string value = db_sprintf(data, size, 0, vkey.type);
3528 if (equal_ustring(value.c_str(), "NAN"))
3529 return 0;
3530
3531 if (vkey.type == TID_BOOL) {
3532 *fvalue = (value[0] == 'y');
3533 } else
3534 *fvalue = atof(value.c_str());
3535
3536 /* evaluate possible operators */
3537 do {
3538 if (src[i] == '>' && src[i+1] == '>') {
3539 i+=2;
3540 n = atoi(src+i);
3541 while (src[i] == ' ' || isdigit(src[i]))
3542 i++;
3543 ivalue = (int)*fvalue;
3544 ivalue >>= n;
3545 *fvalue = ivalue;
3546 }
3547
3548 if (src[i] == '&') {
3549 i+=1;
3550 while (src[i] == ' ')
3551 i++;
3552 if (src[i] == '0' && src[i+1] == 'x')
3553 sscanf(src+2+i, "%x", &n);
3554 else
3555 n = atoi(src+i);
3556 while (src[i] == ' ' || isxdigit(src[i]) || src[i] == 'x')
3557 i++;
3558 ivalue = (int)*fvalue;
3559 ivalue &= n;
3560 *fvalue = ivalue;
3561 }
3562
3563 } while (src[i]);
3564
3565 return 1;
3566}
3567
3568/*------------------------------------------------------------------*/
3569
3570std::string add_custom_path(const std::string& filename)
3571{
3572 // do not append custom path to absolute filenames
3573
3574 if (filename[0] == '/')
3575 return filename;
3576 if (filename[0] == DIR_SEPARATOR)
3577 return filename;
3578
3579 HNDLE hDB;
3581
3582 std::string custom_path = "";
3583
3584 int status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
3585
3586 if (status != DB_SUCCESS)
3587 return filename;
3588
3589 if (custom_path.length() < 1)
3590 return filename;
3591
3593 cm_msg(MERROR, "add_custom_path", "ODB /Custom/Path has a forbidden value \"%s\", please change it", custom_path.c_str());
3594 return filename;
3595 }
3596
3598
3599 std::string full_filename = custom_path;
3600 if (full_filename[full_filename.length()-1] != DIR_SEPARATOR)
3602 full_filename += filename;
3603
3604 return full_filename;
3605}
3606
3607/*------------------------------------------------------------------*/
3608
3609void show_custom_file(Return* r, const char *name)
3610{
3611 char str[256];
3612 std::string filename;
3613 HNDLE hDB;
3614
3616
3617 HNDLE hkey;
3618 sprintf(str, "/Custom/%s", name);
3619 db_find_key(hDB, 0, str, &hkey);
3620
3621 if (!hkey) {
3622 sprintf(str, "/Custom/%s&", name);
3623 db_find_key(hDB, 0, str, &hkey);
3624 if (!hkey) {
3625 sprintf(str, "/Custom/%s!", name);
3626 db_find_key(hDB, 0, str, &hkey);
3627 }
3628 }
3629
3630 if(!hkey){
3631 sprintf(str,"show_custom_file: Invalid custom page: \"/Custom/%s\" not found in ODB", name);
3632 show_error_404(r, str);
3633 return;
3634 }
3635
3636 int status;
3637 KEY key;
3638
3640
3641 if (status != DB_SUCCESS) {
3642 char errtext[512];
3643 sprintf(errtext, "show_custom_file: Error: db_get_key() for \"%s\" status %d", str, status);
3645 return;
3646 }
3647
3648 int size = key.total_size;
3649 char* ctext = (char*)malloc(size);
3650
3652
3653 if (status != DB_SUCCESS) {
3654 char errtext[512];
3655 sprintf(errtext, "show_custom_file: Error: db_get_data() for \"%s\" status %d", str, status);
3657 free(ctext);
3658 return;
3659 }
3660
3661 filename = add_custom_path(ctext);
3662
3663 free(ctext);
3664
3665 send_file(r, filename, true);
3666
3667 return;
3668}
3669
3670/*------------------------------------------------------------------*/
3671
3672void show_custom_gif(Return* rr, const char *name)
3673{
3674 char str[256], data[256], src[256];
3675 int i, index, length, status, size, width, height, bgcol, fgcol, bdcol, r, g, b, x, y;
3677 double fvalue, ratio;
3678 KEY key, vkey;
3679 gdImagePtr im;
3682 FILE *f;
3683 CGIF_LABEL label;
3684 CGIF_BAR bar;
3685
3687
3688 /* find image description in ODB */
3689 sprintf(str, "/Custom/Images/%s", name);
3690 db_find_key(hDB, 0, str, &hkeygif);
3691 if (!hkeygif) {
3692
3693 // If we don't have Images directory,
3694 // then just treat this like any other custom file.
3696 return;
3697 }
3698
3699 /* load background image */
3700 std::string filename;
3701 db_get_value_string(hDB, hkeygif, "Background", 0, &filename, FALSE);
3702
3703 std::string full_filename = add_custom_path(filename);
3704
3705 f = fopen(full_filename.c_str(), "rb");
3706 if (f == NULL) {
3707 sprintf(str, "show_custom_gif: Cannot open file \"%s\"", full_filename.c_str());
3709 return;
3710 }
3711
3713 fclose(f);
3714
3715 if (im == NULL) {
3716 sprintf(str, "show_custom_gif: File \"%s\" is not a GIF image", filename.c_str());
3718 return;
3719 }
3720
3722
3723 /*---- draw labels ----------------------------------------------*/
3724
3725 db_find_key(hDB, hkeygif, "Labels", &hkeyroot);
3726 if (hkeyroot) {
3727 for (index = 0;; index++) {
3729 if (!hkey)
3730 break;
3731 db_get_key(hDB, hkey, &key);
3732
3733 size = sizeof(label);
3734 status = db_get_record1(hDB, hkey, &label, &size, 0, strcomb1(cgif_label_str).c_str());
3735 if (status != DB_SUCCESS) {
3736 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for label \"%s\"",
3737 key.name);
3738 continue;
3739 }
3740
3741 if (label.src[0] == 0) {
3742 cm_msg(MERROR, "show_custom_gif", "Empty Src key for label \"%s\"", key.name);
3743 continue;
3744 }
3745
3746 db_find_key(hDB, 0, label.src, &hkeyval);
3747 if (!hkeyval) {
3748 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for label \"%s\"",
3749 label.src, key.name);
3750 continue;
3751 }
3752
3754 size = sizeof(data);
3755 status = db_get_value(hDB, 0, label.src, data, &size, vkey.type, FALSE);
3756
3757 std::string value;
3758
3759 if (label.format[0]) {
3760 if (vkey.type == TID_FLOAT)
3761 value = msprintf(label.format, *(((float *) data)));
3762 else if (vkey.type == TID_DOUBLE)
3763 value = msprintf(label.format, *(((double *) data)));
3764 else if (vkey.type == TID_INT)
3765 value = msprintf(label.format, *(((INT *) data)));
3766 else if (vkey.type == TID_BOOL) {
3767 if (strstr(label.format, "%c"))
3768 value = msprintf(label.format, *(((INT *) data)) ? 'y' : 'n');
3769 else
3770 value = msprintf(label.format, *(((INT *) data)));
3771 } else
3772 value = db_sprintf(data, size, 0, vkey.type);
3773 } else
3774 value = db_sprintf(data, size, 0, vkey.type);
3775
3776 sscanf(label.fgcolor, "%02x%02x%02x", &r, &g, &b);
3777 fgcol = gdImageColorAllocate(im, r, g, b);
3778 if (fgcol == -1)
3779 fgcol = gdImageColorClosest(im, r, g, b);
3780
3781 sscanf(label.bgcolor, "%02x%02x%02x", &r, &g, &b);
3782 bgcol = gdImageColorAllocate(im, r, g, b);
3783 if (bgcol == -1)
3784 bgcol = gdImageColorClosest(im, r, g, b);
3785
3786 /* select font */
3787 if (equal_ustring(label.font, "Small"))
3789 else if (equal_ustring(label.font, "Medium"))
3791 else if (equal_ustring(label.font, "Giant"))
3793 else
3795
3796 width = value.length() * pfont->w + 5 + 5;
3797 height = pfont->h + 2 + 2;
3798
3799 if (label.align == 0) {
3800 /* left */
3801 gdImageFilledRectangle(im, label.x, label.y, label.x + width,
3802 label.y + height, bgcol);
3803 gdImageRectangle(im, label.x, label.y, label.x + width, label.y + height,
3804 fgcol);
3805 gdImageString(im, pfont, label.x + 5, label.y + 2, value.c_str(), fgcol);
3806 } else if (label.align == 1) {
3807 /* center */
3808 gdImageFilledRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3809 label.y + height, bgcol);
3810 gdImageRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3811 label.y + height, fgcol);
3812 gdImageString(im, pfont, label.x + 5 - width / 2, label.y + 2, value.c_str(), fgcol);
3813 } else {
3814 /* right */
3815 gdImageFilledRectangle(im, label.x - width, label.y, label.x,
3816 label.y + height, bgcol);
3817 gdImageRectangle(im, label.x - width, label.y, label.x, label.y + height,
3818 fgcol);
3819 gdImageString(im, pfont, label.x - width + 5, label.y + 2, value.c_str(), fgcol);
3820 }
3821 }
3822 }
3823
3824 /*---- draw bars ------------------------------------------------*/
3825
3826 db_find_key(hDB, hkeygif, "Bars", &hkeyroot);
3827 if (hkeyroot) {
3828 for (index = 0;; index++) {
3830 if (!hkey)
3831 break;
3832 db_get_key(hDB, hkey, &key);
3833
3834 size = sizeof(bar);
3836 if (status != DB_SUCCESS) {
3837 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for bar \"%s\"",
3838 key.name);
3839 continue;
3840 }
3841
3842 if (bar.src[0] == 0) {
3843 cm_msg(MERROR, "show_custom_gif", "Empty Src key for bar \"%s\"", key.name);
3844 continue;
3845 }
3846
3847 db_find_key(hDB, 0, bar.src, &hkeyval);
3848 if (!hkeyval) {
3849 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for bar \"%s\"",
3850 bar.src, key.name);
3851 continue;
3852 }
3853
3855 size = sizeof(data);
3856 status = db_get_value(hDB, 0, bar.src, data, &size, vkey.type, FALSE);
3857 std::string value = db_sprintf(data, size, 0, vkey.type);
3858 if (equal_ustring(value.c_str(), "NAN"))
3859 continue;
3860
3861 fvalue = atof(value.c_str());
3862
3863 sscanf(bar.fgcolor, "%02x%02x%02x", &r, &g, &b);
3864 fgcol = gdImageColorAllocate(im, r, g, b);
3865 if (fgcol == -1)
3866 fgcol = gdImageColorClosest(im, r, g, b);
3867
3868 sscanf(bar.bgcolor, "%02x%02x%02x", &r, &g, &b);
3869 bgcol = gdImageColorAllocate(im, r, g, b);
3870 if (bgcol == -1)
3871 bgcol = gdImageColorClosest(im, r, g, b);
3872
3873 sscanf(bar.bdcolor, "%02x%02x%02x", &r, &g, &b);
3874 bdcol = gdImageColorAllocate(im, r, g, b);
3875 if (bdcol == -1)
3876 bdcol = gdImageColorClosest(im, r, g, b);
3877
3878 if (bar.min == bar.max)
3879 bar.max += 1;
3880
3881 if (bar.logscale) {
3882 if (fvalue < 1E-20)
3883 fvalue = 1E-20;
3884 ratio = (log(fvalue) - log(bar.min)) / (log(bar.max) - log(bar.min));
3885 } else
3886 ratio = (fvalue - bar.min) / (bar.max - bar.min);
3887 if (ratio < 0)
3888 ratio = 0;
3889 if (ratio > 1)
3890 ratio = 1;
3891
3892 if (bar.direction == 0) {
3893 /* vertical */
3894 ratio = (bar.height - 2) - ratio * (bar.height - 2);
3895 r = (int) (ratio + 0.5);
3896
3897 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.width,
3898 bar.y + bar.height, bgcol);
3899 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.width, bar.y + bar.height,
3900 bdcol);
3901 gdImageFilledRectangle(im, bar.x + 1, bar.y + r + 1, bar.x + bar.width - 1,
3902 bar.y + bar.height - 1, fgcol);
3903
3904 if (bar.axis == 1)
3905 vaxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.height, bar.height, -3,
3906 -5, -7, -8, 0, bar.min, bar.max, bar.logscale);
3907 else if (bar.axis == 2)
3908 vaxis(im, gdFontSmall, bdcol, 0, bar.x + bar.width, bar.y + bar.height,
3909 bar.height, 3, 5, 7, 10, 0, bar.min, bar.max, bar.logscale);
3910
3911 } else {
3912 /* horizontal */
3913 ratio = ratio * (bar.height - 2);
3914 r = (int) (ratio + 0.5);
3915
3916 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.height,
3917 bar.y + bar.width, bgcol);
3918 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.height, bar.y + bar.width,
3919 bdcol);
3920 gdImageFilledRectangle(im, bar.x + 1, bar.y + 1, bar.x + r,
3921 bar.y + bar.width - 1, fgcol);
3922
3923 if (bar.axis == 1)
3924 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y, bar.height, -3, -5, -7, -18,
3925 0, bar.min, bar.max);
3926 else if (bar.axis == 2)
3927 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.width, bar.height, 3,
3928 5, 7, 8, 0, bar.min, bar.max);
3929 }
3930 }
3931 }
3932
3933 /*---- draw fills -----------------------------------------------*/
3934
3935 db_find_key(hDB, hkeygif, "Fills", &hkeyroot);
3936 if (hkeyroot) {
3937 for (index = 0;; index++) {
3939 if (!hkey)
3940 break;
3941 db_get_key(hDB, hkey, &key);
3942
3943 size = sizeof(src);
3944 src[0] = 0;
3945 db_get_value(hDB, hkey, "Src", src, &size, TID_STRING, TRUE);
3946
3947 if (src[0] == 0) {
3948 cm_msg(MERROR, "show_custom_gif", "Empty Src key for Fill \"%s\"", key.name);
3949 continue;
3950 }
3951
3952 if (!evaluate_src(key.name, src, &fvalue))
3953 continue;
3954
3955 x = y = 0;
3956 size = sizeof(x);
3957 db_get_value(hDB, hkey, "X", &x, &size, TID_INT, TRUE);
3958 db_get_value(hDB, hkey, "Y", &y, &size, TID_INT, TRUE);
3959
3960 size = sizeof(data);
3961 status = db_get_value(hDB, hkey, "Limits", data, &size, TID_DOUBLE, FALSE);
3962 if (status != DB_SUCCESS) {
3963 cm_msg(MERROR, "show_custom_gif", "No \"Limits\" entry for Fill \"%s\"",
3964 key.name);
3965 continue;
3966 }
3967 for (i = 0; i < size / (int) sizeof(double); i++)
3968 if (*((double *) data + i) > fvalue)
3969 break;
3970 if (i > 0)
3971 i--;
3972
3973 db_find_key(hDB, hkey, "Fillcolors", &hkeyval);
3974 if (!hkeyval) {
3975 cm_msg(MERROR, "show_custom_gif", "No \"Fillcolors\" entry for Fill \"%s\"",
3976 key.name);
3977 continue;
3978 }
3979
3980 size = sizeof(data);
3981 strcpy(data, "FFFFFF");
3983 if (status == DB_SUCCESS) {
3984 sscanf(data, "%02x%02x%02x", &r, &g, &b);
3985 fgcol = gdImageColorAllocate(im, r, g, b);
3986 if (fgcol == -1)
3987 fgcol = gdImageColorClosest(im, r, g, b);
3988 gdImageFill(im, x, y, fgcol);
3989 }
3990 }
3991 }
3992
3993 /* generate GIF */
3994 gdImageInterlace(im, 1);
3995 gdImageGif(im, &gb);
3997 length = gb.size;
3998
3999 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
4000 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
4001
4002 rr->rsprintf("Content-Type: image/gif\r\n");
4003 rr->rsprintf("Content-Length: %d\r\n", length);
4004 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
4005 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
4006
4007 rr->rmemcpy(gb.data, length);
4008}
4009
4010
4011
4012/*------------------------------------------------------------------*/
4013
4015{
4016 static RPC_LIST rpc_list[] = {
4017 { 9999, "mhttpd_jrpc_rev0", {
4018 {TID_STRING, RPC_IN}, // arg0
4019 {TID_STRING, RPC_IN}, // arg1
4020 {TID_STRING, RPC_IN}, // arg2
4021 {TID_STRING, RPC_IN}, // arg3
4022 {TID_STRING, RPC_IN}, // arg4
4023 {TID_STRING, RPC_IN}, // arg5
4024 {TID_STRING, RPC_IN}, // arg6
4025 {TID_STRING, RPC_IN}, // arg7
4026 {TID_STRING, RPC_IN}, // arg8
4027 {TID_STRING, RPC_IN}, // arg9
4028 {0}} },
4029 { 0 }
4030 };
4031
4032 int count = 0, substring = 0, rpc;
4033
4034 const char *xname = p->getparam("name");
4035 const char *srpc = p->getparam("rpc");
4036
4037 if (!srpc || !xname) {
4039 r->rsprintf("<INVALID_ARGUMENTS>");
4040 return;
4041 }
4042
4043 char sname[256];
4044 mstrlcpy(sname, xname, sizeof(sname));
4045
4046 if (sname[strlen(sname)-1]=='*') {
4047 sname[strlen(sname)-1] = 0;
4048 substring = 1;
4049 }
4050
4051 rpc = atoi(srpc);
4052
4055 r->rsprintf("<INVALID_RPC_ID>");
4056 return;
4057 }
4058
4059 rpc_list[0].id = rpc;
4061
4063 r->rsprintf("calling rpc %d | ", rpc);
4064
4065 if (1) {
4066 int status, i;
4067 char str[256];
4069
4071
4072 /* find client which exports FCNA function */
4073 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4074 if (status == DB_SUCCESS) {
4075 for (i=0; ; i++) {
4078 break;
4079
4080 sprintf(str, "RPC/%d", rpc);
4082 if (status == DB_SUCCESS) {
4083 char client_name[NAME_LENGTH];
4084 HNDLE hconn;
4085 int size;
4086
4087 size = sizeof(client_name);
4088 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4089 if (status != DB_SUCCESS)
4090 continue;
4091
4092 if (strlen(sname) > 0) {
4093 if (substring) {
4094 if (strstr(client_name, sname) != client_name)
4095 continue;
4096 } else {
4097 if (strcmp(sname, client_name) != 0)
4098 continue;
4099 }
4100 }
4101
4102 count++;
4103
4104 r->rsprintf("client %s", client_name);
4105
4106 status = cm_connect_client(client_name, &hconn);
4107 r->rsprintf(" %d", status);
4108
4109 if (status == RPC_SUCCESS) {
4111 p->getparam("arg0"),
4112 p->getparam("arg1"),
4113 p->getparam("arg2"),
4114 p->getparam("arg3"),
4115 p->getparam("arg4"),
4116 p->getparam("arg5"),
4117 p->getparam("arg6"),
4118 p->getparam("arg7"),
4119 p->getparam("arg8"),
4120 p->getparam("arg9")
4121 );
4122 r->rsprintf(" %d", status);
4123
4124 //status = cm_disconnect_client(hconn, FALSE);
4125 r->rsprintf(" %d", status);
4126 }
4127
4128 r->rsprintf(" | ");
4129 }
4130 }
4131 }
4132 }
4133
4134 r->rsprintf("rpc %d, called %d clients\n", rpc, count);
4135}
4136
4137/*------------------------------------------------------------------*/
4138
4140{
4141 static RPC_LIST rpc_list[] = {
4142 { 9998, "mhttpd_jrpc_rev1", {
4143 {TID_STRING, RPC_OUT}, // return string
4144 {TID_INT, RPC_IN}, // return string max length
4145 {TID_STRING, RPC_IN}, // arg0
4146 {TID_STRING, RPC_IN}, // arg1
4147 {TID_STRING, RPC_IN}, // arg2
4148 {TID_STRING, RPC_IN}, // arg3
4149 {TID_STRING, RPC_IN}, // arg4
4150 {TID_STRING, RPC_IN}, // arg5
4151 {TID_STRING, RPC_IN}, // arg6
4152 {TID_STRING, RPC_IN}, // arg7
4153 {TID_STRING, RPC_IN}, // arg8
4154 {TID_STRING, RPC_IN}, // arg9
4155 {0}} },
4156 { 0 }
4157 };
4158
4159 int status, substring = 0, rpc;
4160
4161 const char *xname = p->getparam("name");
4162 const char *srpc = p->getparam("rpc");
4163
4164 if (!srpc || !xname) {
4166 r->rsprintf("<INVALID_ARGUMENTS>");
4167 return;
4168 }
4169
4170 char sname[256];
4171 mstrlcpy(sname, xname, sizeof(sname));
4172
4173 if (sname[strlen(sname)-1]=='*') {
4174 sname[strlen(sname)-1] = 0;
4175 substring = 1;
4176 }
4177
4178 rpc = atoi(srpc);
4179
4182 r->rsprintf("<INVALID_RPC_ID>");
4183 return;
4184 }
4185
4186 rpc_list[0].id = rpc;
4188
4189 //printf("cm_register_functions() for format \'%s\' status %d\n", sformat, status);
4190
4192
4193 std::string reply_header;
4194 std::string reply_body;
4195
4196 //r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4197 //r->rsprintf("<!-- created by MHTTPD on (timestamp) -->\n");
4198 //r->rsprintf("<jrpc_rev1>\n");
4199 //r->rsprintf(" <rpc>%d</rpc>\n", rpc);
4200
4201 if (1) {
4203
4205
4206 int buf_length = 1024;
4207
4208 int max_reply_length = atoi(p->getparam("max_reply_length"));
4211
4212 char* buf = (char*)malloc(buf_length);
4213
4214 /* find client which exports our RPC function */
4215 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4216 if (status == DB_SUCCESS) {
4217 for (int i=0; ; i++) {
4220 break;
4221
4222 char str[256];
4223 sprintf(str, "RPC/%d", rpc);
4225 if (status == DB_SUCCESS) {
4226 char client_name[NAME_LENGTH];
4227 HNDLE hconn;
4228 int size;
4229
4230 size = sizeof(client_name);
4231 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4232 if (status != DB_SUCCESS)
4233 continue;
4234
4235 if (strlen(sname) > 0) {
4236 if (substring) {
4237 if (strstr(client_name, sname) != client_name)
4238 continue;
4239 } else {
4240 if (strcmp(sname, client_name) != 0)
4241 continue;
4242 }
4243 }
4244
4245 //r->rsprintf(" <client>\n");
4246 //r->rsprintf(" <name>%s</name>\n", client_name);
4247
4248 int connect_status = -1;
4249 int call_status = -1;
4250 int call_length = 0;
4251 int disconnect_status = -1;
4252
4253 connect_status = cm_connect_client(client_name, &hconn);
4254
4255 //r->rsprintf(" <connect_status>%d</connect_status>\n", status);
4256
4257 if (connect_status == RPC_SUCCESS) {
4258 buf[0] = 0;
4259
4261 buf,
4262 buf_length,
4263 p->getparam("arg0"),
4264 p->getparam("arg1"),
4265 p->getparam("arg2"),
4266 p->getparam("arg3"),
4267 p->getparam("arg4"),
4268 p->getparam("arg5"),
4269 p->getparam("arg6"),
4270 p->getparam("arg7"),
4271 p->getparam("arg8"),
4272 p->getparam("arg9")
4273 );
4274
4275 //r->rsprintf(" <rpc_status>%d</rpc_status>\n", status);
4277 //r->rsputs("<data>");
4278 //r->rsputs(buf);
4279 //r->rsputs("</data>\n");
4280
4281 if (call_status == RPC_SUCCESS) {
4282 call_length = strlen(buf);
4283 reply_body += buf;
4284 }
4285
4286 //disconnect_status = cm_disconnect_client(hconn, FALSE);
4287 //r->rsprintf(" <disconnect_status>%d</disconnect_status>\n", status);
4288 }
4289
4290 //r->rsprintf(" </client>\n");
4291
4292 if (reply_header.length() > 0)
4293 reply_header += " | ";
4294
4295 char tmp[256];
4296 sprintf(tmp, "%s %d %d %d %d", client_name, connect_status, call_status, disconnect_status, call_length);
4297 reply_header += tmp;
4298 }
4299 }
4300 }
4301
4302 free(buf);
4303 }
4304
4305 //r->rsprintf(" <called_clients>%d</called_clients>\n", count);
4306 //r->rsprintf("</jrpc_rev1>\n");
4307
4308 if (reply_header.length() > 0) {
4309 r->rsputs(reply_header.c_str());
4310 r->rsputs(" || ");
4311 r->rsputs(reply_body.c_str());
4312 r->rsputs("\n");
4313 }
4314}
4315
4316/*------------------------------------------------------------------*/
4317
4319{
4320 int status;
4321
4322 const char *name = p->getparam("name");
4323 const char *cmd = p->getparam("rcmd");
4324 const char *args = p->getparam("rarg");
4325
4326 if (!name || !cmd || !args) {
4328 r->rsprintf("<INVALID_ARGUMENTS>");
4329 return;
4330 }
4331
4333
4334 int buf_length = 1024;
4335
4336 int max_reply_length = atoi(p->getparam("max_reply_length"));
4339
4340 char* buf = (char*)malloc(buf_length);
4341 buf[0] = 0;
4342
4343 HNDLE hconn;
4344
4346
4347 if (status != RPC_SUCCESS) {
4348 r->rsprintf("<RPC_CONNECT_ERROR>%d</RPC_CONNECT_ERROR>", status);
4349 return;
4350 }
4351
4353
4354 if (status != RPC_SUCCESS) {
4355 r->rsprintf("<RPC_CALL_ERROR>%d</RPC_CALL_ERROR>", status);
4356 return;
4357 }
4358
4359 r->rsprintf("%s", buf);
4360
4361 //status = cm_disconnect_client(hconn, FALSE);
4362
4363 free(buf);
4364}
4365
4366/*------------------------------------------------------------------*/
4367
4368void output_key(Param* p, Return* r, HNDLE hkey, int index, const char *format)
4369{
4370 int size, i;
4371 HNDLE hDB, hsubkey;
4372 KEY key;
4373 char data[TEXT_SIZE];
4374
4376
4377 db_get_key(hDB, hkey, &key);
4378 if (key.type == TID_KEY) {
4379 for (i=0 ; ; i++) {
4381 if (!hsubkey)
4382 break;
4383 output_key(p, r, hsubkey, -1, format);
4384 }
4385 } else {
4386 if (key.item_size <= (int)sizeof(data)) {
4387 size = sizeof(data);
4388 db_get_data(hDB, hkey, data, &size, key.type);
4389 if (index == -1) {
4390 for (i=0 ; i<key.num_values ; i++) {
4391 if (p->isparam("name") && atoi(p->getparam("name")) == 1) {
4392 if (key.num_values == 1)
4393 r->rsprintf("%s:", key.name);
4394 else
4395 r->rsprintf("%s[%d]:", key.name, i);
4396 }
4397 std::string data_str;
4398 if (format && format[0])
4400 else
4402 r->rsputs(data_str.c_str());
4403 if (i<key.num_values-1)
4404 r->rsputs("\n");
4405 }
4406 } else {
4407 if (p->isparam("name") && atoi(p->getparam("name")) == 1)
4408 r->rsprintf("%s[%d]:", key.name, index);
4409 if (index >= key.num_values)
4410 r->rsputs("<DB_OUT_OF_RANGE>");
4411 else {
4412 std::string data_str;
4413 if (p->isparam("format"))
4415 else
4417 r->rsputs(data_str.c_str());
4418 }
4419 }
4420 r->rsputs("\n");
4421 }
4422 }
4423}
4424
4425/*------------------------------------------------------------------*/
4426
4427bool starts_with(const std::string& s1, const char* s2)
4428{
4429 if (s1.length() < strlen(s2))
4430 return false;
4431 return (strncasecmp(s1.c_str(), s2, strlen(s2)) == 0);
4432}
4433
4434//static bool ends_with_char(const std::string& s, char c)
4435//{
4436// if (s.length() < 1)
4437// return false;
4438// return s[s.length()-1] == c;
4439//}
4440
4441/*------------------------------------------------------------------*/
4442
4443void javascript_commands(Param* p, Return* r, const char *cookie_cpwd)
4444{
4445 int status;
4446 int size, i, n, index, type;
4447 unsigned int t;
4448 char str[TEXT_SIZE], format[256], facility[256], user[256];
4449 HNDLE hDB, hkey;
4450 KEY key;
4451 char data[TEXT_SIZE];
4452
4454
4455 // process common parameters
4456
4457 const int ENCODING_NONE = 0;
4458 const int ENCODING_ODB = 1;
4459 const int ENCODING_XML = 2;
4460 const int ENCODING_JSON = 3;
4461
4462 std::string cmd_parameter;
4463 std::string encoding_parameter;
4464 int encoding = ENCODING_NONE; // default encoding
4465 bool jsonp = false; // default is no JSONP wrapper
4466 std::string jsonp_callback; // default is no JSONP
4467 bool single = false; // single encoding
4468 bool multiple = false; // multiple encoding
4469 std::vector<std::string> odb; // multiple odb parameters
4470 //HNDLE hodb; // ODB handle for single odb parameter
4471 //std::vector<HNDLE> hodbm; // ODB handle for multiple odb parameter
4472
4473 if (p->isparam("cmd")) {
4474 cmd_parameter = p->getparam("cmd");
4475 }
4476
4477 if (p->isparam("encoding")) {
4478 encoding_parameter = p->getparam("encoding");
4479 }
4480
4481 if (encoding_parameter.length() > 0) {
4482 if (starts_with(encoding_parameter, "odb"))
4484 else if (starts_with(encoding_parameter, "xml"))
4486 else if (starts_with(encoding_parameter, "json"))
4488 }
4489
4490 if (encoding == ENCODING_JSON) {
4491 if (p->isparam("callback")) {
4492 jsonp = true;
4493 jsonp_callback = p->getparam("callback");
4494 }
4495 }
4496
4497 if (p->isparam("odb")) {
4498 single = true;
4499 odb.push_back(p->getparam("odb"));
4500 }
4501
4502 if (p->isparam("odb0")) {
4503 multiple = true;
4504 for (int i=0 ; ; i++) {
4505 char ppath[256];
4506 sprintf(ppath, "odb%d", i);
4507 if (!p->isparam(ppath))
4508 break;
4509 odb.push_back(p->getparam(ppath));
4510 }
4511 }
4512
4513 if (/* DISABLES CODE */ (0)) {
4514 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());
4515 }
4516
4517 /* process "jset" command */
4518 if (equal_ustring(p->getparam("cmd"), "jset")) {
4519
4520 if (*p->getparam("pnam")) {
4521 std::string ppath;
4522 ppath += "/Custom/Pwd/";
4523 ppath += p->getparam("pnam");
4524 str[0] = 0;
4525 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
4526 if (!equal_ustring(cookie_cpwd, str)) {
4528 r->rsprintf("Invalid password!");
4529 return;
4530 }
4531 }
4532 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4533 if (strchr(str, '[')) {
4534 if (*(strchr(str, '[')+1) == '*')
4535 index = -1;
4536 else
4537 index = atoi(strchr(str, '[')+1);
4538 *strchr(str, '[') = 0;
4539 } else
4540 index = 0;
4541
4542 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS && p->isparam("value")) {
4543 db_get_key(hDB, hkey, &key);
4544 memset(data, 0, sizeof(data));
4545 if (key.item_size <= (int)sizeof(data)) {
4546 if (index == -1) {
4547 const char* ptr = p->getparam("value");
4548 for (i=0 ; ptr != NULL ; i++) {
4549 size = sizeof(data);
4550 db_sscanf(ptr, data, &size, 0, key.type);
4551 if (strchr(data, ','))
4552 *strchr(data, ',') = 0;
4554 ptr = strchr(ptr, ',');
4555 if (ptr != NULL)
4556 ptr++;
4557 }
4558 } else {
4559 size = sizeof(data);
4560 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4561
4562 /* extend data size for single string if necessary */
4563 if ((key.type == TID_STRING || key.type == TID_LINK)
4564 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1) {
4565 key.item_size = strlen(data) + 1;
4567 } else
4569 }
4570 }
4571 } else {
4572 if (p->isparam("value") && p->isparam("type") && p->isparam("len")) {
4573 int type = atoi(p->getparam("type"));
4574 if (type == 0) {
4576 r->rsprintf("Invalid type %d!", type);
4577 return;
4578 }
4579 db_create_key(hDB, 0, str, type);
4580 db_find_key(hDB, 0, str, &hkey);
4581 if (!hkey) {
4583 r->rsprintf("Cannot create \'%s\' type %d", str, type);
4584 return;
4585 }
4586 db_get_key(hDB, hkey, &key);
4587 memset(data, 0, sizeof(data));
4588 size = sizeof(data);
4589 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4590 if (key.type == TID_STRING)
4591 db_set_data(hDB, hkey, data, atoi(p->getparam("len")), 1, TID_STRING);
4592 else {
4593 for (i=0 ; i<atoi(p->getparam("len")) ; i++)
4595 }
4596 }
4597 }
4598
4600 r->rsprintf("OK");
4601 return;
4602 }
4603
4604 /* process "jget" command */
4605 if (equal_ustring(p->getparam("cmd"), "jget")) {
4606
4607 if (p->isparam("odb")) {
4608 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4609 if (strchr(str, '[')) {
4610 if (*(strchr(str, '[')+1) == '*')
4611 index = -1;
4612 else
4613 index = atoi(strchr(str, '[')+1);
4614 *strchr(str, '[') = 0;
4615 } else
4616 index = 0;
4617
4619
4620 status = db_find_key(hDB, 0, str, &hkey);
4621
4622 if (status == DB_SUCCESS)
4623 output_key(p, r, hkey, index, p->getparam("format"));
4624 else
4625 r->rsputs("<DB_NO_KEY>");
4626 }
4627
4628 if (p->isparam("odb0")) {
4630 for (i=0 ; ; i++) {
4631 char ppath[256];
4632 sprintf(ppath, "odb%d", i);
4633 sprintf(format, "format%d", i);
4634 if (p->isparam(ppath)) {
4635 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4636 if (strchr(str, '[')) {
4637 if (*(strchr(str, '[')+1) == '*')
4638 index = -1;
4639 else
4640 index = atoi(strchr(str, '[')+1);
4641 *strchr(str, '[') = 0;
4642 } else
4643 index = 0;
4644 if (i > 0)
4645 r->rsputs("$#----#$\n");
4646 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS)
4647 output_key(p, r, hkey, index, p->getparam(format));
4648 else
4649 r->rsputs("<DB_NO_KEY>");
4650
4651 } else
4652 break;
4653 }
4654 }
4655
4656 return;
4657 }
4658
4659 /* process "jcopy" command */
4660 if (equal_ustring(p->getparam("cmd"), "jcopy")) {
4661
4662 bool fmt_odb = false;
4663 bool fmt_xml = false;
4664 bool fmt_json = true;
4665 bool fmt_jsonp = false;
4666 int follow_links = 1;
4667 int save_keys = 1;
4668 int recurse = 1;
4669 const char* fmt = NULL;
4670 const char* jsonp_callback = "callback";
4671
4672 if (p->isparam("encoding")) {
4673 fmt = p->getparam("encoding");
4674 } else if (p->isparam("format")) {
4675 fmt = p->getparam("format");
4676 }
4677
4678 if (fmt) {
4679 fmt_odb = (equal_ustring(fmt, "odb") > 0);
4680 fmt_xml = (equal_ustring(fmt, "xml") > 0);
4681 fmt_json = (strstr(fmt, "json") != NULL);
4682
4683 if (fmt_odb)
4684 fmt_xml = fmt_json = false;
4685 if (fmt_xml)
4686 fmt_odb = fmt_json = false;
4687 if (fmt_json)
4688 fmt_odb = fmt_xml = false;
4689
4690 if (fmt_json)
4691 fmt_jsonp = (strstr(fmt, "-p") != NULL);
4692 if (fmt_jsonp && p->isparam("callback"))
4693 jsonp_callback = p->getparam("callback");
4694 if (fmt_json && strstr(fmt, "-nofollowlinks"))
4695 follow_links = 0;
4696 if (fmt_json && strstr(fmt, "-nokeys"))
4697 save_keys = 2;
4698 if (fmt_json && strstr(fmt, "-nolastwritten"))
4699 save_keys = 0;
4700 if (fmt_json && strstr(fmt, "-norecurse"))
4701 recurse = 0;
4702 }
4703
4704 if (p->isparam("odb")) {
4705 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4706
4708
4709 if (fmt_json)
4710 status = db_find_link(hDB, 0, str, &hkey);
4711 else
4712 status = db_find_key(hDB, 0, str, &hkey);
4713 if (status == DB_SUCCESS) {
4714
4715 if (fmt_jsonp) {
4717 r->rsputs("(");
4718 }
4719
4720 int end = 0;
4722 char* buf = (char *)malloc(bufsize);
4723
4724 if (fmt_xml)
4725 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4726 else if (fmt_json)
4728 else
4729 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4730
4731 r->rsputs(buf);
4732 free(buf);
4733
4734 if (fmt_jsonp) {
4735 r->rsputs(");\n");
4736 }
4737 } else
4738 r->rsputs("<DB_NO_KEY>");
4739 }
4740
4741 if (p->isparam("odb0")) {
4743 if (fmt_jsonp) {
4745 r->rsputs("(");
4746 }
4747 if (fmt_xml) {
4748 r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4749 r->rsputs("<jcopy>\n");
4750 r->rsputs("<data>\n");
4751 } else if (fmt_json)
4752 r->rsputs("[\n");
4753 else
4754 r->rsputs("");
4755 for (int i=0 ; ; i++) {
4756 char ppath[256];
4757 sprintf(ppath, "odb%d", i);
4758 if (!p->isparam(ppath))
4759 break;
4760 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4761
4762 if (i > 0) {
4763 if (fmt_xml)
4764 r->rsputs("</data>\n<data>\n");
4765 else if (fmt_json)
4766 r->rsputs(",\n");
4767 else
4768 r->rsputs("$#----#$\n");
4769 }
4770
4771 if (fmt_json)
4772 status = db_find_link(hDB, 0, str, &hkey);
4773 else
4774 status = db_find_key(hDB, 0, str, &hkey);
4775 if (status != DB_SUCCESS) {
4776 if (fmt_xml)
4777 r->rsputs("<DB_NO_KEY/>\n");
4778 else if (fmt_json) {
4779 char tmp[256];
4780 sprintf(tmp, "{ \"/error\" : %d }\n", status);
4781 r->rsputs(tmp);
4782 } else
4783 r->rsputs("<DB_NO_KEY>\n");
4784 continue;
4785 }
4786
4787 int end = 0;
4789 char* buf = (char *)malloc(bufsize);
4790
4791 if (fmt_xml) {
4792 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4793 const char* s = strstr(buf, "-->");
4794 if (s)
4795 s+=4;
4796 else
4797 s = buf;
4798 r->rsputs(s);
4799 } else if (fmt_json) {
4801 r->rsputs(buf);
4802 } else {
4803 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4804 r->rsputs(buf);
4805 }
4806
4807 free(buf);
4808 }
4809
4810 if (fmt_xml)
4811 r->rsputs("</data>\n</jcopy>\n");
4812 else if (fmt_json)
4813 r->rsputs("]\n");
4814 else
4815 r->rsputs("");
4816
4817 if (fmt_jsonp) {
4818 r->rsputs(");\n");
4819 }
4820 }
4821 return;
4822 }
4823
4824 /* process "jkey" command */
4825 if (equal_ustring(p->getparam("cmd"), "jkey")) {
4826
4827 // test:
4828 // curl "http://localhost:8080?cmd=jkey&odb0=/runinfo/run+number&odb1=/nonexistant&odb2=/&encoding=json&callback=aaa"
4829
4831
4832 if (jsonp) {
4833 r->rsputs(jsonp_callback.c_str());
4834 r->rsputs("(");
4835 }
4836
4837 if (multiple) {
4838 switch (encoding) {
4839 default:
4840 break;
4841 case ENCODING_JSON:
4842 r->rsprintf("[ ");
4843 break;
4844 }
4845 }
4846
4847 for (unsigned i=0; i<odb.size(); i++) {
4848 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
4849 if (status == DB_SUCCESS)
4851 switch (encoding) {
4852 default:
4853 if (multiple && i>0)
4854 r->rsputs("$#----#$\n");
4855 if (status == DB_SUCCESS) {
4856 r->rsprintf("%s\n", key.name);
4857 r->rsprintf("TID_%s\n", rpc_tid_name(key.type));
4858 r->rsprintf("%d\n", key.num_values);
4859 r->rsprintf("%d\n", key.item_size);
4860 r->rsprintf("%d\n", key.last_written);
4861 } else {
4862 r->rsputs("<DB_NO_KEY>\n");
4863 }
4864 break;
4865 case ENCODING_JSON:
4866 if (multiple && i>0)
4867 r->rsprintf(", ");
4868 if (status == DB_SUCCESS) {
4869 r->rsprintf("{ ");
4870 r->rsprintf("\"name\":\"%s\",", key.name);
4871 r->rsprintf("\"type\":%d,", key.type);
4872 r->rsprintf("\"type_name\":\"TID_%s\",", rpc_tid_name(key.type));
4873 r->rsprintf("\"num_values\":%d,", key.num_values);
4874 r->rsprintf("\"item_size\":%d,", key.item_size);
4875 r->rsprintf("\"last_written\":%d", key.last_written);
4876 r->rsprintf(" }");
4877 } else {
4878 r->rsprintf("{ \"/error\":%d }", status);
4879 }
4880 break;
4881 }
4882 }
4883
4884 if (multiple) {
4885 switch (encoding) {
4886 default:
4887 break;
4888 case ENCODING_JSON:
4889 r->rsprintf(" ]");
4890 break;
4891 }
4892 }
4893
4894 if (jsonp) {
4895 r->rsputs(");\n");
4896 }
4897
4898 return;
4899 }
4900
4901 /* process "jcreate" command */
4902 if (equal_ustring(p->getparam("cmd"), "jcreate")) {
4903
4904 // test:
4905 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
4906 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo&type=7"
4907 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo70&type=7&arraylen=10"
4908 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s&type=12&strlen=32"
4909 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s5&type=12&strlen=32&arraylen=5"
4910 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo12s5x&type0=12&strlen0=32&arraylen0=5"
4911
4912
4914
4915 if (jsonp) {
4916 r->rsputs(jsonp_callback.c_str());
4917 r->rsputs("(");
4918 }
4919
4920 if (multiple) {
4921 switch (encoding) {
4922 default:
4923 case ENCODING_JSON:
4924 r->rsprintf("[ ");
4925 break;
4926 }
4927 }
4928
4929 for (unsigned i=0; i<odb.size(); i++) {
4930 HNDLE hkey = 0;
4931 int type = 0;
4932 int arraylength = 0;
4933 int strlength = 0;
4934
4935 if (single) {
4936 type = atoi(p->getparam("type"));
4937 arraylength = atoi(p->getparam("arraylen"));
4938 strlength = atoi(p->getparam("strlen"));
4939 }
4940 else if (multiple) {
4941 char buf[256];
4942 sprintf(buf, "type%d", i);
4943 type = atoi(p->getparam(buf));
4944 sprintf(buf, "arraylen%d", i);
4945 arraylength = atoi(p->getparam(buf));
4946 sprintf(buf, "strlen%d", i);
4947 strlength = atoi(p->getparam(buf));
4948 }
4949
4950 status = db_create_key(hDB, 0, odb[i].c_str(), type);
4951
4952 if (status == DB_SUCCESS) {
4953 status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
4954 }
4955
4956 if (status == DB_SUCCESS && hkey && type == TID_STRING && strlength > 0) {
4957 char* s = (char*)calloc(strlength, 1); // initialized to zero
4959 free(s);
4960 }
4961
4962 if (status == DB_SUCCESS && hkey && arraylength > 1) {
4964 }
4965
4966 switch (encoding) {
4967 default:
4968 case ENCODING_JSON:
4969 if (multiple && i>0)
4970 r->rsprintf(", ");
4971 r->rsprintf("%d", status);
4972 break;
4973 }
4974 }
4975
4976 if (multiple) {
4977 switch (encoding) {
4978 default:
4979 case ENCODING_JSON:
4980 r->rsprintf(" ]");
4981 break;
4982 }
4983 }
4984
4985 if (jsonp) {
4986 r->rsputs(");\n");
4987 }
4988
4989 return;
4990 }
4991
4992 /* process "jresize" command */
4993 if (equal_ustring(p->getparam("cmd"), "jresize")) {
4994
4995 // test:
4996
4997 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo70&arraylen=5"
4998 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&arraylen=5"
4999 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=16"
5000 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=30&arraylen=10"
5001
5003
5004 if (jsonp) {
5005 r->rsputs(jsonp_callback.c_str());
5006 r->rsputs("(");
5007 }
5008
5009 if (multiple) {
5010 switch (encoding) {
5011 default:
5012 case ENCODING_JSON:
5013 r->rsprintf("[ ");
5014 break;
5015 }
5016 }
5017
5018 for (unsigned i=0; i<odb.size(); i++) {
5019 HNDLE hkey;
5020 KEY key;
5021 int arraylength = 0;
5022 int strlength = 0;
5023
5024 if (single) {
5025 arraylength = atoi(p->getparam("arraylen"));
5026 strlength = atoi(p->getparam("strlen"));
5027 }
5028 else if (multiple) {
5029 char buf[256];
5030 sprintf(buf, "arraylen%d", i);
5031 arraylength = atoi(p->getparam(buf));
5032 sprintf(buf, "strlen%d", i);
5033 strlength = atoi(p->getparam(buf));
5034 }
5035
5036 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5037
5038 if (status == DB_SUCCESS && hkey) {
5040 }
5041
5042 if (status == DB_SUCCESS && hkey && key.type == TID_STRING && strlength > 0) {
5044 char* olddata = (char*)malloc(oldsize);
5045 int size = oldsize;
5047
5048 if (status == DB_SUCCESS) {
5050 char* s = (char*)calloc(newsize, 1); // initialized to zero
5051 for (int k=0; k<key.num_values; k++) {
5053 }
5054
5056 free(s);
5057 }
5058
5059 free(olddata);
5060 }
5061
5062 if (status == DB_SUCCESS && hkey && arraylength > 0) {
5064 }
5065
5066 switch (encoding) {
5067 default:
5068 case ENCODING_JSON:
5069 if (multiple && i>0)
5070 r->rsprintf(", ");
5071 r->rsprintf("%d", status);
5072 break;
5073 }
5074 }
5075
5076 if (multiple) {
5077 switch (encoding) {
5078 default:
5079 case ENCODING_JSON:
5080 r->rsprintf(" ]");
5081 break;
5082 }
5083 }
5084
5085 if (jsonp) {
5086 r->rsputs(");\n");
5087 }
5088
5089 return;
5090 }
5091
5092 /* process "jrename" command */
5093 if (equal_ustring(p->getparam("cmd"), "jrename")) {
5094
5095 // test:
5096 // curl "http://localhost:8080?cmd=jrename&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
5097 // curl "http://localhost:8080?cmd=jrename&odb=/test/foo&name=foofoo"
5098
5100
5101 if (jsonp) {
5102 r->rsputs(jsonp_callback.c_str());
5103 r->rsputs("(");
5104 }
5105
5106 if (multiple) {
5107 switch (encoding) {
5108 default:
5109 case ENCODING_JSON:
5110 r->rsprintf("[ ");
5111 break;
5112 }
5113 }
5114
5115 for (unsigned i=0; i<odb.size(); i++) {
5116 const char* name = NULL;
5117 if (single)
5118 name = p->getparam("name");
5119 else if (multiple) {
5120 char buf[256];
5121 sprintf(buf, "name%d", i);
5122 name = p->getparam(buf);
5123 }
5124 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5125 if (status == DB_SUCCESS) {
5127 }
5128 switch (encoding) {
5129 default:
5130 case ENCODING_JSON:
5131 if (multiple && i>0)
5132 r->rsprintf(", ");
5133 r->rsprintf("%d", status);
5134 break;
5135 }
5136 }
5137
5138 if (multiple) {
5139 switch (encoding) {
5140 default:
5141 case ENCODING_JSON:
5142 r->rsprintf(" ]");
5143 break;
5144 }
5145 }
5146
5147 if (jsonp) {
5148 r->rsputs(");\n");
5149 }
5150
5151 return;
5152 }
5153
5154 /* process "jlink" command */
5155 if (equal_ustring(p->getparam("cmd"), "jlink")) {
5156
5157 // test:
5158 // curl "http://localhost:8080?cmd=jlink&odb=/test/link&dest=/test/foo"
5159 // curl "http://localhost:8080?cmd=jlink&odb0=/test/link0&dest0=/test/foo&odb1=/test/link1&dest1=/test/foo"
5160
5162
5163 if (jsonp) {
5164 r->rsputs(jsonp_callback.c_str());
5165 r->rsputs("(");
5166 }
5167
5168 if (multiple) {
5169 switch (encoding) {
5170 default:
5171 case ENCODING_JSON:
5172 r->rsprintf("[ ");
5173 break;
5174 }
5175 }
5176
5177 for (unsigned i=0; i<odb.size(); i++) {
5178 const char* dest = NULL;
5179 if (single)
5180 dest = p->getparam("dest");
5181 else if (multiple) {
5182 char buf[256];
5183 sprintf(buf, "dest%d", i);
5184 dest = p->getparam(buf);
5185 }
5186
5187 status = db_create_link(hDB, 0, odb[i].c_str(), dest);
5188
5189 switch (encoding) {
5190 default:
5191 case ENCODING_JSON:
5192 if (multiple && i>0)
5193 r->rsprintf(", ");
5194 r->rsprintf("%d", status);
5195 break;
5196 }
5197 }
5198
5199 if (multiple) {
5200 switch (encoding) {
5201 default:
5202 case ENCODING_JSON:
5203 r->rsprintf(" ]");
5204 break;
5205 }
5206 }
5207
5208 if (jsonp) {
5209 r->rsputs(");\n");
5210 }
5211
5212 return;
5213 }
5214
5215 /* process "jreorder" command */
5216 if (equal_ustring(p->getparam("cmd"), "jreorder")) {
5217
5218 // test:
5219 // curl "http://localhost:8080?cmd=jreorder&odb0=/test/foo&index0=0&odb1=/test/bar&index1=1"
5220 // curl "http://localhost:8080?cmd=jreorder&odb=/test/bar&index=0"
5221
5223
5224 if (jsonp) {
5225 r->rsputs(jsonp_callback.c_str());
5226 r->rsputs("(");
5227 }
5228
5229 if (multiple) {
5230 switch (encoding) {
5231 default:
5232 case ENCODING_JSON:
5233 r->rsprintf("[ ");
5234 break;
5235 }
5236 }
5237
5238 for (unsigned i=0; i<odb.size(); i++) {
5239 int index = 0;
5240 if (single)
5241 index = atoi(p->getparam("index"));
5242 else if (multiple) {
5243 char buf[256];
5244 sprintf(buf, "index%d", i);
5245 index = atoi(p->getparam(buf));
5246 }
5247
5248 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5249 if (status == DB_SUCCESS) {
5251 }
5252
5253 switch (encoding) {
5254 default:
5255 case ENCODING_JSON:
5256 if (multiple && i>0)
5257 r->rsprintf(", ");
5258 r->rsprintf("%d", status);
5259 break;
5260 }
5261 }
5262
5263 if (multiple) {
5264 switch (encoding) {
5265 default:
5266 case ENCODING_JSON:
5267 r->rsprintf(" ]");
5268 break;
5269 }
5270 }
5271
5272 if (jsonp) {
5273 r->rsputs(");\n");
5274 }
5275
5276 return;
5277 }
5278
5279 /* process "jdelete" command */
5280 if (equal_ustring(p->getparam("cmd"), "jdelete")) {
5281
5282 // test:
5283 // curl "http://localhost:8080?cmd=jdelete&odb0=/test/foo&odb1=/nonexistant&odb2=/test/bar&encoding=json&callback=aaa"
5284 // curl "http://localhost:8080?cmd=jdelete&odb=/test/foo"
5285
5287
5288 if (jsonp) {
5289 r->rsputs(jsonp_callback.c_str());
5290 r->rsputs("(");
5291 }
5292
5293 if (multiple) {
5294 switch (encoding) {
5295 default:
5296 case ENCODING_JSON:
5297 r->rsprintf("[ ");
5298 break;
5299 }
5300 }
5301
5302 for (unsigned i=0; i<odb.size(); i++) {
5303 BOOL follow_links = 0;
5304 status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
5305 if (status == DB_SUCCESS) {
5307 }
5308 switch (encoding) {
5309 default:
5310 case ENCODING_JSON:
5311 if (multiple && i>0)
5312 r->rsprintf(", ");
5313 r->rsprintf("%d", status);
5314 break;
5315 }
5316 }
5317
5318 if (multiple) {
5319 switch (encoding) {
5320 default:
5321 case ENCODING_JSON:
5322 r->rsprintf(" ]");
5323 break;
5324 }
5325 }
5326
5327 if (jsonp) {
5328 r->rsputs(");\n");
5329 }
5330
5331 return;
5332 }
5333
5334 /* process "jmsg" command */
5335 if (equal_ustring(p->getparam("cmd"), "jmsg")) {
5336
5337 if (p->getparam("f") && *p->getparam("f"))
5338 mstrlcpy(facility, p->getparam("f"), sizeof(facility));
5339 else
5340 mstrlcpy(facility, "midas", sizeof(facility));
5341
5342 n = 1;
5343 if (p->getparam("n") && *p->getparam("n"))
5344 n = atoi(p->getparam("n"));
5345
5346 t = 0;
5347 if (p->getparam("t") && p->getparam("t"))
5348 t = atoi(p->getparam("t"));
5349
5351 char* messages = NULL;
5352 int num_messages = 0;
5354 if (messages) {
5355 r->rsputs(messages);
5356 free(messages);
5357 }
5358 return;
5359 }
5360
5361 /* process "jgenmsg" command */
5362 if (equal_ustring(p->getparam("cmd"), "jgenmsg")) {
5363
5364 if (p->getparam("facility") && *p->getparam("facility"))
5365 mstrlcpy(facility, p->getparam("facility"), sizeof(facility));
5366 else
5367 mstrlcpy(facility, "midas", sizeof(facility));
5368
5369 if (p->getparam("user") && *p->getparam("user"))
5370 mstrlcpy(user, p->getparam("user"), sizeof(user));
5371 else
5372 mstrlcpy(user, "javascript_commands", sizeof(user));
5373
5374 if (p->getparam("type") && *p->getparam("type"))
5375 type = atoi(p->getparam("type"));
5376 else
5377 type = MT_INFO;
5378
5379 if (p->getparam("msg") && *p->getparam("msg")) {
5380 cm_msg1(type, __FILE__, __LINE__, facility, user, "%s", p->getparam("msg"));
5381 }
5382
5384 r->rsputs("Message successfully created\n");
5385 return;
5386 }
5387
5388 /* process "jalm" command */
5389 if (equal_ustring(p->getparam("cmd"), "jalm")) {
5390
5392 std::string alarms;
5394 r->rsputs(alarms.c_str());
5395 return;
5396 }
5397
5398 /* process "jrpc" command */
5399 if (equal_ustring(p->getparam("cmd"), "jrpc_rev0")) {
5400 do_jrpc_rev0(p, r);
5401 return;
5402 }
5403
5404 /* process "jrpc" command */
5405 if (equal_ustring(p->getparam("cmd"), "jrpc_rev1")) {
5406 do_jrpc_rev1(p, r);
5407 return;
5408 }
5409
5410 /* process "jrpc" command */
5411 if (equal_ustring(p->getparam("cmd"), "jrpc")) {
5412 do_jrpc(p, r);
5413 return;
5414 }
5415}
5416
5417/*------------------------------------------------------------------*/
5418
5419void show_custom_page(Param* pp, Return* r, const char *cookie_cpwd)
5420{
5421 int size, n_var, index, edit;
5422 char keypath[256], type[32], *p, *ps;
5423 char pwd[256], tail[256];
5424 HNDLE hDB, hkey;
5425 KEY key;
5426 char data[TEXT_SIZE];
5427
5428 std::string path = pp->getparam("page");
5429
5430 if (path[0] == 0) {
5431 show_error_404(r, "show_custom_page: Invalid custom page: \"page\" parameter is empty");
5432 return;
5433 }
5434
5435 if (strstr(path.c_str(), "..")) {
5436 std::string str;
5437 str += "Invalid custom page name \'";
5438 str += path;
5439 str += "\' contains \'..\'";
5440 show_error_404(r, str.c_str());
5441 return;
5442 }
5443
5444 if (strstr(path.c_str(), ".gif")) {
5445 show_custom_gif(r, path.c_str());
5446 return;
5447 }
5448
5449 if (strchr(path.c_str(), '.')) {
5450 show_custom_file(r, path.c_str());
5451 return;
5452 }
5453
5455
5456 std::string xpath = std::string("/Custom/") + path;
5457 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5458 if (!hkey) {
5459 xpath = std::string("/Custom/") + path + "&";
5460 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5461 if (!hkey) {
5462 xpath = std::string("/Custom/") + path + "!";
5463 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5464 }
5465 }
5466
5467 if (hkey) {
5468 char* ctext;
5469 int status;
5470
5472 assert(status == DB_SUCCESS);
5473 size = key.total_size;
5474 ctext = (char*)malloc(size);
5476 if (status != DB_SUCCESS) {
5477 std::string errtext = msprintf("show_custom_page: Error: db_get_data() for \"%s\" status %d", xpath.c_str(), status);
5478 show_error_404(r, errtext.c_str());
5479 free(ctext);
5480 return;
5481 }
5482
5483 std::string content_type = "text/html";
5484
5485 /* check for link */
5486 if (std::string(ctext).substr(0, 5) == "?cmd=") {
5487 redirect(r, ctext);
5488 free(ctext);
5489 return;
5490 }
5491
5492 /* check if filename */
5493 if (strchr(ctext, '\n') == 0) {
5494 std::string full_filename = add_custom_path(ctext);
5495 int fh = open(full_filename.c_str(), O_RDONLY | O_BINARY);
5496 if (fh < 0) {
5497 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", open() errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5498 show_error_404(r, str.c_str());
5499 free(ctext);
5500 return;
5501 }
5502 free(ctext);
5503 ctext = NULL;
5504 off_t off = lseek(fh, 0, SEEK_END);
5505 if (off < 0) {
5506 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", lseek(SEEK_END) errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5507 show_error_404(r, str.c_str());
5508 free(ctext);
5509 close(fh);
5510 return;
5511 }
5512 size_t size = off;
5513 lseek(fh, 0, SEEK_SET);
5514 ctext = (char*)malloc(size+1);
5515 ssize_t rd = read(fh, ctext, size);
5516 if (rd > 0) {
5517 ctext[rd] = 0; // make sure string is zero-terminated
5518 size = rd;
5519 } else {
5520 ctext[0] = 0;
5521 size = 0;
5522 }
5523 close(fh);
5524
5526 }
5527
5528 /* check for valid password */
5529 if (equal_ustring(pp->getparam("cmd"), "Edit")) {
5530 p = ps = ctext;
5531 n_var = 0;
5532 do {
5533 char format[256];
5534
5535 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5536 if (p == NULL)
5537 break;
5538 ps = strchr(p, '>') + 1;
5539
5540 if (pwd[0] && n_var == atoi(pp->getparam("index"))) {
5541 char str[256];
5542 size = NAME_LENGTH;
5543 mstrlcpy(str, path.c_str(), sizeof(str)); // FIXME: overflows "str"
5544 if (strlen(str)>0 && str[strlen(str)-1] == '&')
5545 str[strlen(str)-1] = 0;
5546 std::string ppath;
5547 ppath += "/Custom/Pwd/";
5548 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5549 ppath += pp->getparam("pnam");
5550 } else {
5551 ppath += str;
5552 }
5553 str[0] = 0;
5554 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
5555 if (!equal_ustring(cookie_cpwd, str)) {
5556 show_error_404(r, "show_custom_page: Invalid password!");
5557 free(ctext);
5558 return;
5559 } else
5560 break;
5561 }
5562
5563 n_var++;
5564 } while (p != NULL);
5565 }
5566
5567 /* process toggle command */
5568 if (equal_ustring(pp->getparam("cmd"), "Toggle")) {
5569
5570 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5571 std::string ppath;
5572 ppath += "/Custom/Pwd/";
5573 ppath += pp->getparam("pnam");
5574 std::string str;
5575 db_get_value_string(hDB, 0, ppath.c_str(), 0, &str, TRUE, 256);
5576 if (!equal_ustring(cookie_cpwd, str.c_str())) {
5577 show_error_404(r, "show_custom_page: Invalid password!");
5578 free(ctext);
5579 return;
5580 }
5581 }
5582 std::string podb = pp->getparam("odb");
5583 std::string::size_type pos = podb.find('[');
5584 if (pos != std::string::npos) {
5585 index = atoi(podb.substr(pos+1).c_str());
5586 podb.resize(pos);
5587 //printf("found index %d in [%s] [%s]\n", index, pp->getparam("odb"), podb.c_str());
5588 } else
5589 index = 0;
5590
5591 if (db_find_key(hDB, 0, podb.c_str(), &hkey)) {
5592 db_get_key(hDB, hkey, &key);
5593 memset(data, 0, sizeof(data));
5594 if (key.item_size <= (int)sizeof(data)) {
5595 size = sizeof(data);
5597 std::string data_str = db_sprintf(data, size, 0, key.type);
5598 if (atoi(data_str.c_str()) == 0)
5599 db_sscanf("1", data, &size, 0, key.type);
5600 else
5601 db_sscanf("0", data, &size, 0, key.type);
5603 }
5604 }
5605
5606 /* redirect (so that 'reload' does not toggle again) */
5607 redirect(r, path.c_str());
5608 free(ctext);
5609 return;
5610 }
5611
5612 /* HTTP header */
5613 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
5614 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5615 r->rsprintf("Content-Type: %s; charset=%s\r\n\r\n", content_type.c_str(), HTTP_ENCODING);
5616
5617 /* interprete text, replace <odb> tags with ODB values */
5618 p = ps = ctext;
5619 n_var = 0;
5620 do {
5621 char format[256];
5622 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5623 if (p != NULL)
5624 *p = 0;
5625 r->rsputs(ps);
5626
5627 if (p == NULL)
5628 break;
5629 ps = strchr(p + 1, '>') + 1;
5630
5631 show_odb_tag(pp, r, path.c_str(), keypath, format, n_var, edit, type, pwd, tail);
5632 n_var++;
5633
5634 } while (p != NULL);
5635
5636 if (equal_ustring(pp->getparam("cmd"), "Set") || pp->isparam("cbi")) {
5637 /* redirect (so that 'reload' does not change value) */
5638 r->reset();
5639 redirect(r, path.c_str());
5640 }
5641
5642 free(ctext);
5643 ctext = NULL;
5644 } else {
5645 std::string str = msprintf("Invalid custom page: Page \"%s\" not found in ODB", path.c_str());
5646 show_error_404(r, str.c_str());
5647 return;
5648 }
5649}
5650
5651/*------------------------------------------------------------------*/
5652
5654{
5655 char str[256];
5656 int c, n, a, f, d, q, x, r, ia, id, w;
5657 int i, size, status;
5659
5660 static char client_name[NAME_LENGTH];
5661 static HNDLE hconn = 0;
5662
5664
5665 /* find FCNA server if not specified */
5666 if (hconn == 0) {
5667 /* find client which exports FCNA function */
5668 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
5669 if (status == DB_SUCCESS) {
5670 for (i = 0;; i++) {
5673 break;
5674
5675 sprintf(str, "RPC/%d", RPC_CNAF16);
5677 if (status == DB_SUCCESS) {
5678 size = sizeof(client_name);
5679 db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
5680 break;
5681 }
5682 }
5683 }
5684
5685 if (client_name[0]) {
5686 status = cm_connect_client(client_name, &hconn);
5687 if (status != RPC_SUCCESS)
5688 hconn = 0;
5689 }
5690 }
5691
5692 /* header */
5693 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
5694 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5695 rr->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
5696
5697 rr->rsprintf("<html><head>\n");
5698 rr->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
5699 rr->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
5700 rr->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
5701 rr->rsprintf("<title>MIDAS CAMAC interface</title></head>\n");
5702 rr->rsprintf("<body><form method=\"GET\" action=\"CNAF\">\n\n");
5703
5704 /* title row */
5705
5706 size = sizeof(str);
5707 str[0] = 0;
5708 db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
5709
5710 rr->rsprintf("<table border=3 cellpadding=1>\n");
5711 rr->rsprintf("<tr><th colspan=3>MIDAS experiment \"%s\"", str);
5712
5713 if (client_name[0] == 0)
5714 rr->rsprintf("<th colspan=3 class=\"redLight\">No CAMAC server running</tr>\n");
5715 else if (hconn == 0)
5716 rr->rsprintf("<th colspan=3 class=\"redLight\">Cannot connect to %s</tr>\n", client_name);
5717 else
5718 rr->rsprintf("<th colspan=3>CAMAC server: %s</tr>\n", client_name);
5719
5720 /* default values */
5721 c = n = 1;
5722 a = f = d = q = x = 0;
5723 r = 1;
5724 ia = id = w = 0;
5725
5726 /*---- menu buttons ----*/
5727
5728 rr->rsprintf("<tr><td colspan=3>\n");
5729 rr->rsprintf("<input type=submit name=cmd value=Execute>\n");
5730
5731 rr->rsprintf("<td colspan=3>\n");
5732 rr->rsprintf("<input type=submit name=cmd value=ODB>\n");
5733 rr->rsprintf("<input type=submit name=cmd value=Status>\n");
5734 rr->rsprintf("<input type=submit name=cmd value=Help>\n");
5735 rr->rsprintf("</tr>\n\n");
5736
5737 /* header */
5738 rr->rsprintf("<tr><th>N");
5739 rr->rsprintf("<th>A");
5740 rr->rsprintf("<th>F");
5741 rr->rsprintf("<th colspan=3>Data");
5742
5743 /* execute commands */
5744 size = sizeof(d);
5745
5746 const char* cmd = p->getparam("cmd");
5747 if (equal_ustring(cmd, "C cycle")) {
5748 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5749 &q);
5750
5751 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">C cycle executed sucessfully</tr>\n");
5752 } else if (equal_ustring(cmd, "Z cycle")) {
5753 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_ZINIT, 0, 0, 0, 0, 0, &d, &size, &x,
5754 &q);
5755
5756 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">Z cycle executed sucessfully</tr>\n");
5757 } else if (equal_ustring(cmd, "Clear inhibit")) {
5758 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5759 &q);
5760
5761 rr->rsprintf
5762 ("<tr><td colspan=6 class=\"greenLight\">Clear inhibit executed sucessfully</tr>\n");
5763 } else if (equal_ustring(cmd, "Set inhibit")) {
5764 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_SET, 0, 0, 0, 0, 0, &d, &size, &x,
5765 &q);
5766
5767 rr->rsprintf
5768 ("<tr><td colspan=6 class=\"greenLight\">Set inhibit executed sucessfully</tr>\n");
5769 } else if (equal_ustring(cmd, "Execute")) {
5770 c = atoi(p->getparam("C"));
5771 n = atoi(p->getparam("N"));
5772 a = atoi(p->getparam("A"));
5773 f = atoi(p->getparam("F"));
5774 r = atoi(p->getparam("R"));
5775 w = atoi(p->getparam("W"));
5776 id = atoi(p->getparam("ID"));
5777 ia = atoi(p->getparam("IA"));
5778
5779 const char* pd = p->getparam("D");
5780 if (strncmp(pd, "0x", 2) == 0)
5781 sscanf(pd + 2, "%x", &d);
5782 else
5783 d = atoi(p->getparam("D"));
5784
5785 /* limit repeat range */
5786 if (r == 0)
5787 r = 1;
5788 if (r > 100)
5789 r = 100;
5790 if (w > 1000)
5791 w = 1000;
5792
5793 for (i = 0; i < r; i++) {
5794 status = SUCCESS;
5795
5796 if (hconn) {
5797 size = sizeof(d);
5798 status =
5799 rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x,
5800 &q);
5801
5802 if (status == RPC_NET_ERROR) {
5803 /* try to reconnect */
5804 //cm_disconnect_client(hconn, FALSE);
5805 status = cm_connect_client(client_name, &hconn);
5806 if (status != RPC_SUCCESS) {
5807 hconn = 0;
5808 client_name[0] = 0;
5809 }
5810
5811 if (hconn) {
5812 status = rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x, &q);
5813 }
5814 }
5815 }
5816
5817 if (status != SUCCESS) {
5818 rr->rsprintf
5819 ("<tr><td colspan=6 class=\"redLight\">Error executing function, code = %d</tr>",
5820 status);
5821 } else {
5822 rr->rsprintf("<tr align=center><td>%d", n);
5823 rr->rsprintf("<td>%d", a);
5824 rr->rsprintf("<td>%d", f);
5825 rr->rsprintf("<td colspan=3>%d / 0x%04X Q%d X%d", d, d, q, x);
5826 }
5827
5828 d += id;
5829 a += ia;
5830
5831 if (w > 0)
5832 ss_sleep(w);
5833 }
5834 }
5835
5836 /* input fields */
5837 rr->rsprintf
5838 ("<tr align=center><td><input type=text size=3 name=N value=%d>\n",
5839 n);
5840 rr->rsprintf("<td><input type=text size=3 name=A value=%d>\n", a);
5841 rr->rsprintf("<td><input type=text size=3 name=F value=%d>\n", f);
5842 rr->rsprintf
5843 ("<td colspan=3><input type=text size=8 name=D value=%d></tr>\n",
5844 d);
5845
5846 /* control fields */
5847 rr->rsprintf("<tr><td colspan=2>Repeat");
5848 rr->rsprintf("<td><input type=text size=3 name=R value=%d>\n", r);
5849
5850 rr->rsprintf
5851 ("<td align=center colspan=3><input type=submit name=cmd value=\"C cycle\">\n");
5852 rr->rsprintf("<input type=submit name=cmd value=\"Z cycle\">\n");
5853
5854 rr->rsprintf("<tr><td colspan=2>Repeat delay [ms]");
5855 rr->rsprintf("<td><input type=text size=3 name=W value=%d>\n", w);
5856
5857 rr->rsprintf
5858 ("<td align=center colspan=3><input type=submit name=cmd value=\"Set inhibit\">\n");
5859 rr->rsprintf("<input type=submit name=cmd value=\"Clear inhibit\">\n");
5860
5861 rr->rsprintf("<tr><td colspan=2>Data increment");
5862 rr->rsprintf("<td><input type=text size=3 name=ID value=%d>\n", id);
5863
5864 rr->rsprintf
5865 ("<td colspan=3 align=center>Branch <input type=text size=3 name=B value=0>\n");
5866
5867 rr->rsprintf("<tr><td colspan=2>A increment");
5868 rr->rsprintf("<td><input type=text size=3 name=IA value=%d>\n", ia);
5869
5870 rr->rsprintf
5871 ("<td colspan=3 align=center>Crate <input type=text size=3 name=C value=%d>\n",
5872 c);
5873
5874 rr->rsprintf("</table></body>\r\n");
5875}
5876
5877/*------------------------------------------------------------------*/
5878
5879#ifdef HAVE_MSCB
5880
5881typedef struct {
5882 signed char id;
5883 char name[32];
5884} NAME_TABLE;
5885
5886static const NAME_TABLE prefix_table[] = {
5887 {PRFX_PICO, "pico",},
5888 {PRFX_NANO, "nano",},
5889 {PRFX_MICRO, "micro",},
5890 {PRFX_MILLI, "milli",},
5891 {PRFX_NONE, "",},
5892 {PRFX_KILO, "kilo",},
5893 {PRFX_MEGA, "mega",},
5894 {PRFX_GIGA, "giga",},
5895 {PRFX_TERA, "tera",},
5896 {99}
5897};
5898
5899static const NAME_TABLE unit_table[] = {
5900
5901 {UNIT_METER, "meter",},
5902 {UNIT_GRAM, "gram",},
5903 {UNIT_SECOND, "second",},
5904 {UNIT_MINUTE, "minute",},
5905 {UNIT_HOUR, "hour",},
5906 {UNIT_AMPERE, "ampere",},
5907 {UNIT_KELVIN, "kelvin",},
5908 {UNIT_CELSIUS, "deg. celsius",},
5909 {UNIT_FARENHEIT, "deg. farenheit",},
5910
5911 {UNIT_HERTZ, "hertz",},
5912 {UNIT_PASCAL, "pascal",},
5913 {UNIT_BAR, "bar",},
5914 {UNIT_WATT, "watt",},
5915 {UNIT_VOLT, "volt",},
5916 {UNIT_OHM, "ohm",},
5917 {UNIT_TESLA, "tesls",},
5918 {UNIT_LITERPERSEC, "liter/sec",},
5919 {UNIT_RPM, "RPM",},
5920 {UNIT_FARAD, "farad",},
5921
5922 {UNIT_BOOLEAN, "boolean",},
5923 {UNIT_BYTE, "byte",},
5924 {UNIT_WORD, "word",},
5925 {UNIT_DWORD, "dword",},
5926 {UNIT_ASCII, "ascii",},
5927 {UNIT_STRING, "string",},
5928 {UNIT_BAUD, "baud",},
5929
5930 {UNIT_PERCENT, "percent",},
5931 {UNIT_PPM, "RPM",},
5932 {UNIT_COUNT, "counts",},
5933 {UNIT_FACTOR, "factor",},
5934 {0}
5935};
5936
5937/*------------------------------------------------------------------*/
5938
5939void print_mscb_var(char *value, char *evalue, char *unit, MSCB_INFO_VAR *info_chn, void *pdata)
5940{
5941 char str[80];
5942 signed short sdata;
5943 unsigned short usdata;
5944 signed int idata;
5945 unsigned int uidata;
5946 float fdata;
5947 int i;
5948
5949 value[0] = 0;
5950 evalue[0] = 0;
5951
5952 if (info_chn->unit == UNIT_STRING) {
5953 memset(str, 0, sizeof(str));
5954 strncpy(str, (char *)pdata, info_chn->width);
5955 for (i = 0; i < (int) strlen(str); i++)
5956 switch (str[i]) {
5957 case 1:
5958 strcat(value, "\\001");
5959 break;
5960 case 2:
5961 strcat(value, "\\002");
5962 break;
5963 case 9:
5964 strcat(value, "\\t");
5965 break;
5966 case 10:
5967 strcat(value, "\\n");
5968 break;
5969 case 13:
5970 strcat(value, "\\r");
5971 break;
5972 default:
5973 value[strlen(value) + 1] = 0;
5974 value[strlen(value)] = str[i];
5975 break;
5976 }
5977 mstrlcpy(evalue, value, 256);
5978 } else {
5979 switch (info_chn->width) {
5980 case 0:
5981 strcpy(value, "0");
5982 strcpy(evalue, "0");
5983 break;
5984
5985 case 1:
5986 if (info_chn->flags & MSCBF_SIGNED) {
5987 sprintf(value, "%d (0x%02X/", *((signed char *)pdata), *((signed char *)pdata));
5988 sprintf(evalue, "%d", *((signed char *)pdata));
5989 } else {
5990 sprintf(value, "%u (0x%02X/", *((unsigned char *)pdata), *((unsigned char *)pdata));
5991 sprintf(evalue, "%u", *((unsigned char *)pdata));
5992 }
5993
5994 for (i = 0; i < 8; i++)
5995 if (*((unsigned char *)pdata) & (0x80 >> i))
5996 sprintf(value + strlen(value), "1");
5997 else
5998 sprintf(value + strlen(value), "0");
5999 sprintf(value + strlen(value), ")");
6000 break;
6001
6002 case 2:
6003 if (info_chn->flags & MSCBF_SIGNED) {
6004 sdata = *((signed short *)pdata);
6005 WORD_SWAP(&sdata);
6006 sprintf(value, "%d (0x%04X)", sdata, sdata);
6007 sprintf(evalue, "%d", sdata);
6008 } else {
6009 usdata = *((unsigned short *)pdata);
6010 WORD_SWAP(&usdata);
6011 sprintf(value, "%u (0x%04X)", usdata, usdata);
6012 sprintf(evalue, "%u", usdata);
6013 }
6014 break;
6015
6016 case 4:
6017 if (info_chn->flags & MSCBF_FLOAT) {
6018 fdata = *((float *)pdata);
6019 DWORD_SWAP(&fdata);
6020 sprintf(value, "%1.6lg", fdata);
6021 sprintf(evalue, "%1.6lg", fdata);
6022 } else {
6023 if (info_chn->flags & MSCBF_SIGNED) {
6024 idata = *((signed int *)pdata);
6025 DWORD_SWAP(&idata);
6026 sprintf(value, "%d (0x%08X)", idata, idata);
6027 sprintf(evalue, "%d", idata);
6028 } else {
6029 uidata = *((unsigned int *)pdata);
6031 sprintf(value, "%u (0x%08X)", uidata, uidata);
6032 sprintf(evalue, "%u", uidata);
6033 }
6034 }
6035 break;
6036 }
6037 }
6038
6039 /* evaluate prefix */
6040 unit[0] = 0;
6041 if (info_chn->prefix) {
6042 for (i = 0; prefix_table[i].id != 99; i++)
6043 if ((unsigned char)prefix_table[i].id == info_chn->prefix)
6044 break;
6045 if (prefix_table[i].id)
6046 strcpy(unit, prefix_table[i].name);
6047 }
6048
6049 /* evaluate unit */
6050 if (info_chn->unit && info_chn->unit != UNIT_STRING) {
6051 for (i = 0; unit_table[i].id; i++)
6052 if ((unsigned char)unit_table[i].id == info_chn->unit)
6053 break;
6054 if (unit_table[i].id)
6056 }
6057}
6058
6059static int cmp_int(const void *a, const void *b)
6060{
6061 return *((int *)a) > *((int *)b);
6062}
6063
6064/*------------------------------------------------------------------*/
6065
6066void create_mscb_tree()
6067{
6069 KEY key;
6070 int i, j, k, l, size, address[1000], dev_badr[1000], dev_adr[1000], dev_chn[1000],
6072 char mscb_dev[256], mscb_pwd[32], eq_name[32];
6073
6075
6076 db_create_key(hDB, 0, "MSCB/Submaster", TID_KEY);
6077 db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6078 assert(hKeySubm);
6079
6080 /*---- go through equipment list ----*/
6081 db_find_key(hDB, 0, "Equipment", &hKeyEq);
6082 if (hKeyEq) {
6083 for (i=0 ; ; i++) {
6085 if (!hKey)
6086 break;
6087 db_get_key(hDB, hKey, &key);
6088 strcpy(eq_name, key.name);
6089 db_find_key(hDB, hKey, "Settings/Devices", &hKeyDev);
6090 if (hKeyDev) {
6091 for (j=0 ;; j++) {
6093 if (!hKey)
6094 break;
6095
6096 if (db_find_key(hDB, hKey, "MSCB Address", &hKeyAdr) == DB_SUCCESS) {
6097 /* mscbdev type of device */
6098 size = sizeof(mscb_dev);
6099 if (db_get_value(hDB, hKey, "Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6100 continue;
6101 size = sizeof(mscb_pwd);
6102 if (db_get_value(hDB, hKey, "Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6103 continue;
6104
6105 size = sizeof(dev_adr);
6107 n_dev_adr = size / sizeof(int);
6108 } else if (db_find_key(hDB, hKey, "Block Address", &hKeyAdr) == DB_SUCCESS) {
6109 /* mscbhvr type of device */
6110 size = sizeof(mscb_dev);
6111 if (db_get_value(hDB, hKey, "MSCB Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6112 continue;
6113 size = sizeof(mscb_pwd);
6114 if (db_get_value(hDB, hKey, "MSCB Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6115 continue;
6116
6117 n_dev_adr = 0;
6118 size = sizeof(dev_badr);
6120 size = sizeof(dev_chn);
6121 if (db_get_value(hDB, hKey, "Block Channels", dev_chn, &size, TID_INT, FALSE) == DB_SUCCESS) {
6122 for (k=0 ; k<size/(int)sizeof(int) && n_dev_adr < (int)(sizeof(dev_adr)/sizeof(int)) ; k++) {
6123 for (l=0 ; l<dev_chn[k] ; l++)
6124 dev_adr[n_dev_adr++] = dev_badr[k]+l;
6125 }
6126 }
6127 } else
6128 continue;
6129
6130 /* create or open submaster entry */
6132 if (!hKey) {
6135 assert(hKey);
6136 }
6137
6138 /* get old address list */
6139 size = sizeof(address);
6140 if (db_get_value(hDB, hKey, "Address", address, &size, TID_INT, FALSE) == DB_SUCCESS)
6141 n_address = size / sizeof(int);
6142 else
6143 n_address = 0;
6144
6145 /* merge with new address list */
6146 for (k=0 ; k<n_dev_adr ; k++) {
6147 for (l=0 ; l<n_address ; l++)
6148 if (address[l] == dev_adr[k])
6149 break;
6150
6151 if (l == n_address)
6152 address[n_address++] = dev_adr[k];
6153 }
6154
6155 /* sort address list */
6156 qsort(address, n_address, sizeof(int), cmp_int);
6157
6158 /* store new address list */
6159 db_set_value(hDB, hKey, "Pwd", mscb_pwd, 32, 1, TID_STRING);
6160 db_set_value(hDB, hKey, "Comment", eq_name, 32, 1, TID_STRING);
6161 db_set_value(hDB, hKey, "Address", address, n_address*sizeof(int), n_address, TID_INT);
6162 }
6163 }
6164 }
6165 }
6166}
6167
6168/*------------------------------------------------------------------*/
6169
6170void show_mscb_page(Param* p, Return* r, int refresh)
6171{
6172 int i, j, n, ind, fi, fd, status, size, n_addr, *addr, cur_node, adr, show_hidden;
6173 unsigned int uptime;
6175 float fvalue;
6176 char *pd;
6177 char dbuf[256], evalue[256], unit[256], cur_subm_name[256];
6179 KEY key;
6182 int ping_addr[0x10000];
6183 char *node_comment;
6184
6186
6187 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6188 if (!hKeySubm)
6190
6191 mstrlcpy(cur_subm_name, p->getparam("subm"), sizeof(cur_subm_name));
6192 if (cur_subm_name[0] == 0) {
6194 if (!hKeyCurSubm) {
6195 char errorstr[256];
6196 sprintf(errorstr, "No submaster defined under /MSCB/Submaster");
6197 show_error(r, errorstr);
6198 return;
6199 }
6201 strcpy(cur_subm_name, key.name);
6202 } else
6204
6205 if (p->isparam("node"))
6206 cur_node = atoi(p->getparam("node"));
6207 else
6208 cur_node = -1;
6209
6210 /* perform MSCB rescan */
6211 if (p->isparam("mcmd") && equal_ustring(p->getparam("mcmd"), "Rescan") && p->isparam("subm")) {
6212 /* create Pwd and Comment if not there */
6213 char tmp[32];
6214 size = 32;
6215 tmp[0] = 0;
6216 db_get_value(hDB, hKeyCurSubm, "Pwd", (void *)tmp, &size, TID_STRING, true);
6217 tmp[0] = 0;
6218 db_get_value(hDB, hKeyCurSubm, "Comment", (void *)tmp, &size, TID_STRING, true);
6219
6220 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6221 if (hKeyAddr) {
6222 /* get current address array */
6225 addr = (int *)malloc(sizeof(int)*n_addr);
6226 size = sizeof(int)*n_addr;
6227 db_get_data(hDB, hKeyAddr, addr, &size, TID_INT);
6228 } else {
6229 /* create new address array */
6230 db_create_key(hDB, hKeyCurSubm, "Address", TID_INT);
6231 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6232 n_addr = 0;
6233 addr = (int *)malloc(sizeof(int));
6234 }
6235
6237 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6238 if (hKeyComm) {
6239 /* get current node comments */
6241 node_comment = (char *)malloc(32*key.num_values);
6242 size = 32*key.num_values;
6244 } else {
6245 /* create new comment array */
6246 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6247 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6248 node_comment = (char *)malloc(32);
6250 }
6251
6252 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6253 if (fd >= 0) {
6254 /* fill table of possible addresses */
6255 for (i=0 ; i<0x10000 ; i++)
6256 ping_addr[i] = 0;
6257 for (i=0 ; i<1000 ; i++) // 0..999
6258 ping_addr[i] = 1;
6259 for (i=0 ; i<0x10000 ; i+=100) // 100, 200, ...
6260 ping_addr[i] = 1;
6261 for (i=0 ; i<0x10000 ; i+= 0x100)
6262 ping_addr[i] = 1; // 256, 512, ...
6263 for (i=0xFF00 ; i<0x10000 ; i++)
6264 ping_addr[i] = 1; // 0xFF00-0xFFFF
6265
6266 for (ind = n = 0; ind < 0x10000; ind++) {
6267 if (!ping_addr[ind])
6268 continue;
6269
6270 status = mscb_ping(fd, (unsigned short) ind, 1, 0);
6271 if (status == MSCB_SUCCESS) {
6272
6273 /* node found, search next 100 as well */
6274 for (j=ind; j<ind+100 && j<0x10000 ; j++)
6275 if (j >= 0)
6276 ping_addr[j] = 1;
6277
6278 status = mscb_info(fd, (unsigned short) ind, &info);
6279
6280 if (status == MSCB_SUCCESS) {
6281 /* check if node already in list */
6282 for (j=0 ; j<n_addr ; j++)
6283 if (addr[j] == ind)
6284 break;
6285 if (j == n_addr) {
6286 addr = (int *)realloc(addr, sizeof(int)*(n_addr+1));
6287 addr[n_addr] = ind;
6288 node_comment = (char *)realloc(node_comment, 32*(n_addr+1));
6289 /* use node name as default comment */
6290 strncpy(node_comment+n_addr*32, info.node_name, 32);
6291 n_addr ++;
6292 } else if (comment_created) {
6293 node_comment = (char *)realloc(node_comment, 32*n_addr);
6294 /* use node name as default comment */
6295 strncpy(node_comment+j*32, info.node_name, 32);
6296 }
6297 }
6298 }
6299 }
6300
6301 db_set_data(hDB, hKeyAddr, addr, n_addr*sizeof(int), n_addr, TID_INT);
6302 free(addr);
6304 free(node_comment);
6305
6306 char redirstr[512];
6307 sprintf(redirstr, "?cmd=mscb&subm=%s", cur_subm_name);
6308 redirect(r, redirstr);
6309 return;
6310
6311 } else {
6312 char errorstr[512];
6313 sprintf(errorstr, "Cannot talk to submaster \"%s\"", cur_subm_name);
6314 show_error(r, errorstr);
6315 return;
6316 }
6317 }
6318
6319 /* write data to node */
6320 if (p->isparam("subm") && p->isparam("node") &&
6321 p->isparam("idx") && p->isparam("value")) {
6322 i = atoi(p->getparam("idx"));
6323 char value[256];
6324 mstrlcpy(value, p->getparam("value"), sizeof(value));
6325
6326 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6327 if (fd >= 0) {
6329 (unsigned short) cur_node, (unsigned char) i, &info_var);
6330 if (status == MSCB_SUCCESS) {
6331 if (info_var.unit == UNIT_STRING) {
6332 char valstr[256];
6333 mstrlcpy(valstr, value, sizeof(valstr));
6334 if (strlen(valstr) > 0 && valstr[strlen(valstr) - 1] == '\n')
6335 valstr[strlen(valstr) - 1] = 0;
6336
6337 status = mscb_write(fd, (unsigned short) cur_node,
6338 (unsigned char) i, valstr, strlen(valstr) + 1);
6339 } else {
6340 if (info_var.flags & MSCBF_FLOAT) {
6341 fvalue = (float) atof(value);
6342 memcpy(&dbuf, &fvalue, sizeof(float));
6343 } else {
6344 if (value[1] == 'x')
6345 sscanf(value + 2, "%x", (int *)&dbuf);
6346 else
6347 *((int *)dbuf) = atoi(value);
6348 }
6349
6350 status = mscb_write(fd, (unsigned short) cur_node,
6351 (unsigned char) i, dbuf, info_var.width);
6352 }
6353 }
6354 }
6355 char redirstr[512];
6356 sprintf(redirstr, "?cmd=mscb&subm=%s&node=%d", cur_subm_name, cur_node);
6357 redirect(r, redirstr);
6358 return;
6359 }
6360
6361 if (p->isparam("hidden"))
6362 show_hidden = atoi(p->getparam("hidden"));
6363 else
6365
6366 show_header(r, "MSCB", "GET", "./", refresh);
6367 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6368 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6369 show_navigation_bar(r, "MSCB");
6370
6371 /* style sheet */
6372 r->rsprintf("<style type=\"text/css\">\r\n");
6373 r->rsprintf("select { width:150px; background-color:#FFFFE0; font-size:12px; }\r\n");
6374 r->rsprintf(".subm {\r\n");
6375 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6376 r->rsprintf(" padding:5px;\r\n");
6377 r->rsprintf(" vertical-align:top;\r\n");
6378 r->rsprintf(" font-size:16px;\r\n");
6379 r->rsprintf(" border-right:1px solid #808080;\r\n");
6380 r->rsprintf("}\r\n");
6381 r->rsprintf(".node {\r\n");
6382 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6383 r->rsprintf(" padding:5px;\r\n");
6384 r->rsprintf(" vertical-align:top;\r\n");
6385 r->rsprintf(" font-size:16px;\r\n");
6386 r->rsprintf(" border-right:1px solid #808080;\r\n");
6387 r->rsprintf("}\r\n");
6388 r->rsprintf(".vars {\r\n");
6389 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6390 r->rsprintf(" padding:5px;\r\n");
6391 r->rsprintf(" vertical-align:top;\r\n");
6392 r->rsprintf(" font-size:10px;\r\n");
6393 r->rsprintf("}\r\n");
6394 r->rsprintf(".v1 {\r\n");
6395 r->rsprintf(" padding:3px;\r\n");
6396 r->rsprintf(" font-weight:bold;\r\n");
6397 r->rsprintf(" font-size:12px;\r\n");
6398 r->rsprintf("}\r\n");
6399 r->rsprintf(".v2 {\r\n");
6400 r->rsprintf(" background-color:#F0F0F0;\r\n");
6401 r->rsprintf(" padding:3px;\r\n");
6402 r->rsprintf(" font-size:12px;\r\n");
6403 r->rsprintf(" border:1px solid #808080;\r\n");
6404 r->rsprintf(" border-right:1px solid #FFFFFF;\r\n");
6405 r->rsprintf(" border-bottom:1px solid #FFFFFF;\r\n");
6406 r->rsprintf("}\r\n");
6407 r->rsprintf(".v3 {\r\n");
6408 r->rsprintf(" padding:3px;\r\n");
6409 r->rsprintf(" font-size:12px;\r\n");
6410 r->rsprintf("}\r\n");
6411 r->rsprintf("</style>\r\n\r\n");
6412
6413 /* javascript */
6414 r->rsprintf("<script type=\"text/javascript\">\r\n");
6415 r->rsprintf("function mscb_edit(index, value)\r\n");
6416 r->rsprintf("{\r\n");
6417 r->rsprintf(" var new_value = prompt('Please enter new value', value);\r\n");
6418 r->rsprintf(" if (new_value != undefined) {\r\n");
6419 r->rsprintf(" window.location.search = '?cmd=mscb&subm=%s&node=%d&idx='+index+'&value='+new_value;\n", cur_subm_name, cur_node);
6420 r->rsprintf(" }\n");
6421 r->rsprintf("}\r\n");
6422 r->rsprintf("</script>\r\n\r\n");
6423
6424 /*---- main content ----*/
6425
6426 r->rsprintf("<table class=\"mtable\">"); //main table
6427 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>MSCB</th><tr>");
6428
6429 /*---- menu buttons ----*/
6430
6431 r->rsprintf("<tr><td colspan=2>\n");
6432 r->rsprintf("<table width=100%%><tr>\n");
6433 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());
6434
6435 r->rsprintf("<tr><td colspan=\"2\" cellpadding=\"0\" cellspacing=\"0\">\r\n");
6436
6437 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6438 if (status != DB_SUCCESS) {
6439 r->rsprintf("<h1>No MSCB Submasters defined in ODB</h1>\r\n");
6440 r->rsprintf("</td></tr>\r\n");
6441 r->rsprintf("</table>\r\n"); //submaster table
6442 r->rsprintf("</td></tr>\r\n");
6443 r->rsprintf("</table>\r\n"); //main table
6444 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6445 r->rsprintf("</form>\n");
6446 r->rsprintf("</body></html>\r\n");
6447 return;
6448 }
6449
6450 r->rsprintf("<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"0\">");
6451
6452 /*---- submaster list ----*/
6453 r->rsprintf("<tr><td class=\"subm\">\r\n");
6454 r->rsprintf("Submaster<hr>\r\n");
6455
6456 /* count submasters */
6457 for (i = 0;;i++) {
6459 if (!hKey)
6460 break;
6461 }
6462 if (i<2)
6463 i = 2;
6464
6465 r->rsprintf("<select name=\"subm\" id=\"subm\" size=%d ", i);
6466 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm='+document.getElementById('subm').value;\">\r\n");
6467 hKeyCurSubm = 0;
6468 for (i = 0;;i++) {
6470 if (!hKey)
6471 break;
6472 db_get_key(hDB, hKey, &key);
6473 char str[NAME_LENGTH+10+256];
6474 mstrlcpy(str, key.name, sizeof(str));
6475 char comment[256];
6476 size = sizeof(comment);
6477 if (db_get_value(hDB, hKey, "Comment", comment, &size, TID_STRING, FALSE) == DB_SUCCESS) {
6478 mstrlcat(str, ": ", sizeof(str));
6479 mstrlcat(str, comment, sizeof(str));
6480 }
6481
6483 (cur_subm_name[0] == 0 && i == 0)) {
6484 r->rsprintf("<option value=\"%s\" selected>%s</option>\r\n", key.name, str);
6485 hKeyCurSubm = hKey;
6486 } else
6487 r->rsprintf("<option value=\"%s\">%s</option>\r\n", key.name, str);
6488 }
6489 r->rsprintf("</select>\r\n");
6490
6491 /*---- node list ----*/
6492 r->rsprintf("<td class=\"node\">\r\n");
6493 r->rsprintf("Node ");
6494
6495 r->rsprintf("<script type=\"text/javascript\">\n");
6496 r->rsprintf("<!--\n");
6497 r->rsprintf("function rescan()\n");
6498 r->rsprintf("{\n");
6499 r->rsprintf(" flag = confirm('Rescan can take up to one minute.');\n");
6500 r->rsprintf(" if (flag == true)\n");
6501 r->rsprintf(" window.location.href = '?cmd=mscb&mcmd=Rescan&subm=%s';\n", cur_subm_name);
6502 r->rsprintf("}\n");
6503 r->rsprintf("//-->\n");
6504 r->rsprintf("</script>\n");
6505
6506 r->rsprintf("<input type=button name=cmd value=\"Rescan\" onClick=\"rescan();\">");
6507 r->rsprintf("<hr>\r\n");
6508
6509 if (!hKeyCurSubm) {
6510 r->rsprintf("No submaster found in ODB\r\n");
6511 r->rsprintf("</td></tr>\r\n");
6512 r->rsprintf("</table>\r\n"); //inner submaster table
6513 r->rsprintf("</td></tr>\r\n");
6514 r->rsprintf("</table>\r\n"); //submaster table
6515 r->rsprintf("</td></tr>\r\n");
6516 r->rsprintf("</table>\r\n"); //main table
6517 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6518 r->rsprintf("</form>\n");
6519 r->rsprintf("</body></html>\r\n");
6520 return;
6521 }
6522
6523 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6524 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6525
6526 i = 10;
6527 if (hKeyAddr) {
6529 i = key.num_values;
6530
6531 if (hKeyComm == 0) {
6532 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6533 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6534 }
6536 if (key.num_values < i) {
6537 char str[32] = "";
6538 for (int j=key.num_values ; j<i ; j++)
6540 }
6541 }
6542 if (i < 2)
6543 i = 2;
6544
6545 r->rsprintf("<select name=\"node\" id=\"node\" size=%d ", i);
6546 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm=%s&node='+document.getElementById('node').value;\">\r\n", cur_subm_name);
6547
6548 if (hKeyAddr) {
6550 size = sizeof(adr);
6551
6552 /* check if current node is in list */
6553 for (i = 0; i<key.num_values ;i++) {
6554 size = sizeof(adr);
6555 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6556 if (adr == cur_node)
6557 break;
6558 }
6559 if (i == key.num_values) // if not found, use first one in list
6561
6562 for (i = 0; i<key.num_values ;i++) {
6563 char str[100+256];
6564 size = sizeof(adr);
6565 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6566 if (hKeyComm) {
6567 char comment[256];
6568 size = sizeof(comment);
6569 db_get_data_index(hDB, hKeyComm, comment, &size, i, TID_STRING);
6570 sprintf(str, "%d: %s", adr, comment);
6571 } else {
6572 sprintf(str, "%d", adr);
6573 }
6574 if (cur_node == 0 && i == 0)
6575 cur_node = adr;
6576 if (adr == cur_node)
6577 r->rsprintf("<option selected>%s</option>\r\n", str);
6578 else
6579 r->rsprintf("<option>%s</option>\r\n", str);
6580 }
6581 }
6582 r->rsprintf("</select>\r\n");
6583
6584 /*---- node contents ----*/
6585 r->rsprintf("<td class=\"vars\">\r\n");
6586 r->rsprintf("<table>\r\n");
6588 if (cur_node != -1)
6589 r->rsprintf("<tr><td colspan=3 align=center><b>%s:%d</b>", key.name, cur_node);
6590 else
6591 r->rsprintf("<tr><td colspan=3 align=center><b>%s</b>", key.name);
6592 r->rsprintf("<hr></td></tr>\r\n");
6593
6594 char passwd[32];
6595 passwd[0] = 0;
6596 size = 32;
6597 db_get_value(hDB, hKeyCurSubm, "Pwd", passwd, &size, TID_STRING, TRUE);
6598
6599 fd = mscb_init(key.name, 0, passwd, FALSE);
6600 if (fd < 0) {
6601 if (fd == EMSCB_WRONG_PASSWORD)
6602 r->rsprintf("<tr><td colspan=3><b>Invalid password</b></td>");
6603 else
6604 r->rsprintf("<tr><td colspan=3><b>Submaster does not respond</b></td>");
6605 goto mscb_error;
6606 }
6609
6610 status = mscb_ping(fd, cur_node, 0, 1);
6611 if (status != MSCB_SUCCESS) {
6612 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6613 goto mscb_error;
6614 }
6615 status = mscb_info(fd, (unsigned short) cur_node, &info);
6616 if (status != MSCB_SUCCESS) {
6617 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6618 goto mscb_error;
6619 }
6620 char tr16[17];
6621 mstrlcpy(tr16, info.node_name, sizeof(tr16));
6622 r->rsprintf("<tr><td class=\"v1\">Node name<td colspan=2 class=\"v2\">%s</tr>\n", tr16);
6623 r->rsprintf("<tr><td class=\"v1\">GIT revision<td colspan=2 class=\"v2\">%d</tr>\n", info.revision);
6624
6625 if (info.rtc[0] && info.rtc[0] != 0xFF) {
6626 for (i=0 ; i<6 ; i++)
6627 info.rtc[i] = (info.rtc[i] / 0x10) * 10 + info.rtc[i] % 0x10;
6628 r->rsprintf("<tr><td class=\"v1\">Real Time Clock<td colspan=2 class=\"v2\">%02d-%02d-%02d %02d:%02d:%02d</td>\n",
6629 info.rtc[0], info.rtc[1], info.rtc[2],
6630 info.rtc[3], info.rtc[4], info.rtc[5]);
6631 }
6632
6633 status = mscb_uptime(fd, (unsigned short) cur_node, &uptime);
6634 if (status == MSCB_SUCCESS)
6635 r->rsprintf("<tr><td class=\"v1\">Uptime<td colspan=2 class=\"v2\">%dd %02dh %02dm %02ds</tr>\n",
6636 uptime / (3600 * 24),
6637 (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
6638 (uptime % 60));
6639
6640 r->rsprintf("<tr><td colspan=3><hr></td></tr>\r\n");
6641
6642 /* check for hidden variables */
6643 for (i=0 ; i < info.n_variables ; i++) {
6645 if (info_var.flags & MSCBF_HIDDEN)
6646 break;
6647 }
6648 if (i < info.n_variables) {
6649 char str[32];
6650 strcpy(str, show_hidden ? " checked" : "");
6651 r->rsprintf("<tr><td colspan=3><input type=checkbox%s name=\"hidden\" value=\"1\"", str);
6652 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);
6653 }
6654
6655 /* read variables in blocks of 100 bytes */
6656 for (fi=0 ; fi < info.n_variables ; ) {
6657 for (i=fi,size=0 ; i < info.n_variables && size < 100; i++) {
6659 size += info_var.width;
6660 }
6661
6662 size = sizeof(dbuf);
6663 status = mscb_read_range(fd, cur_node, fi, i-1, dbuf, &size);
6664 if (status != MSCB_SUCCESS) {
6665 r->rsprintf("<tr><td colspan=3><b>Error reading data from node</b></td>");
6666 goto mscb_error;
6667 }
6668 pd = dbuf;
6669
6670 for (j=fi ; j<i ; j++) {
6672 if ((info_var.flags & MSCBF_HIDDEN) == 0 || show_hidden) {
6673 char tr8[9];
6674 mstrlcpy(tr8, info_var.name, sizeof(tr8));
6675 r->rsprintf("<tr><td class=\"v1\">%s</td>\r\n", tr8);
6676 r->rsprintf("<td class=\"v2\">\r\n");
6677 char value[256];
6679 r->rsprintf("<a href=\"#\" onClick=\"mscb_edit(%d,'%s')\">%s</a>",
6680 j, evalue, value);
6681 r->rsprintf("</td><td class=\"v3\">%s</td>", unit);
6682 r->rsprintf("</tr>\r\n");
6683 }
6684 pd += info_var.width;
6685 }
6686
6687 fi = i;
6688 }
6689
6691 r->rsprintf("</tr></table>\r\n");
6692 r->rsprintf("</td></tr></table>\r\n");
6693 r->rsprintf("</td></tr></table>\r\n");
6694 r->rsprintf("</td></tr></table>\r\n");
6695 r->rsprintf("</div></body></html>\r\n");
6696}
6697
6698#endif // HAVE_MSCB
6699
6700/*------------------------------------------------------------------*/
6701
6702void show_password_page(Return* r, const char* dec_path, const char *password)
6703{
6704 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6705 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6706 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6707
6708 r->rsprintf("<html><head>\n");
6709 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6710 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6711 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6712 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6713
6714 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6715
6716 /*---- page header ----*/
6717 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6718
6719 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6720 if (password[0])
6721 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6722
6723 r->rsprintf("<tr><th>Please enter password</tr>\n");
6724 r->rsprintf("<tr><td align=center><input type=password name=pwd></tr>\n");
6725 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6726
6727 r->rsprintf("</table>\n");
6728
6729 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6730 r->rsprintf("</form>\n");
6731 r->rsprintf("</body></html>\r\n");
6732}
6733
6734/*------------------------------------------------------------------*/
6735
6736BOOL check_web_password(Return* r, HNDLE hDB, const char* dec_path, const char *password, const char *redir)
6737{
6738 HNDLE hkey;
6739 INT size;
6740 char str[256];
6741
6742 /* check for password */
6743 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
6744 if (hkey) {
6745 size = sizeof(str);
6746 db_get_data(hDB, hkey, str, &size, TID_STRING);
6747 if (strcmp(password, str) == 0)
6748 return TRUE;
6749
6750 /* show web password page */
6751 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6752 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6753 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6754
6755 r->rsprintf("<html><head>\n");
6756 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6757 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6758 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6759 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6760
6761 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6762
6763 /* define hidden fields for current experiment and destination */
6764 if (redir[0])
6765 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", redir);
6766
6767 /*---- page header ----*/
6768 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6769
6770 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6771
6772 if (password[0])
6773 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6774
6775 r->rsprintf
6776 ("<tr><th>Please enter password to obtain write access</tr>\n");
6777 r->rsprintf("<tr><td align=center><input type=password name=wpwd></tr>\n");
6778 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6779
6780 r->rsprintf("</table>\n");
6781
6782 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6783 r->rsprintf("</form>\n");
6784 r->rsprintf("</body></html>\r\n");
6785
6786 return FALSE;
6787 } else
6788 return TRUE;
6789}
6790
6791/*------------------------------------------------------------------*/
6792
6793void show_odb_page(Param* pp, Return* r, const char* dec_path, int write_access)
6794{
6795 int keyPresent, size, status, line, link_index;
6796 char colspan;
6797 char style[32];
6799 KEY key;
6800 DWORD delta;
6801
6803
6804 //printf("path [%s]\n", dec_path);
6805
6806 if (strcmp(dec_path, "root") == 0) {
6807 dec_path = "";
6808 }
6809
6810 char xdecpath[256];
6812 if (strrchr(xdecpath, '/'))
6813 mstrlcpy(xdecpath, strrchr(xdecpath, '/')+1, sizeof(xdecpath));
6814 if (xdecpath[0] == 0)
6815 mstrlcpy(xdecpath, "root", sizeof(xdecpath));
6816 show_header(r, "MIDAS online database", "", xdecpath, 0);
6817
6818 /* use javascript file */
6819 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6820 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6821 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
6822 r->rsprintf("<script type=\"text/javascript\" src=\"controls.js\"></script>\n");
6823
6824 /* find key via path */
6826 if (status != DB_SUCCESS) {
6827 r->rsprintf("Error: cannot find key %s<P>\n", dec_path);
6828 r->rsprintf("</body></html>\r\n");
6829 return;
6830 }
6831
6832 char xdec_path[MAX_ODB_PATH];
6833
6834 /* if key is not of type TID_KEY, cut off key name */
6836 if (key.type != TID_KEY) {
6838
6839 /* strip variable name from path */
6840 char* p = xdec_path + strlen(xdec_path) - 1;
6841 while (*p && *p != '/')
6842 *p-- = 0;
6843 if (*p == '/')
6844 *p = 0;
6845
6847 if (status != DB_SUCCESS) {
6848 r->rsprintf("Error: cannot find key %s<P>\n", xdec_path);
6849 r->rsprintf("</body></html>\r\n");
6850 return;
6851 }
6852
6854 }
6855
6856 //mstrlcpy(enc_path, dec_path, enc_path_size);
6857 //urlEncode(enc_path, enc_path_size);
6858
6859 std::string odbpath = db_get_path(hDB, hkeyroot);
6860
6861 /*---- navigation bar ----*/
6862
6863 colspan = 7;
6864
6865 if (elog_mode) {
6866 r->rsprintf("<table class=\"mtableheader\">\n");
6867 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6868 r->rsprintf("<input type=button value=ELog onclick=\"self.location=\'?cmd=Alarms\';\">\n");
6869 r->rsprintf("</td></tr></table>\n\n");
6870 } else
6871 show_navigation_bar(r, "ODB");
6872
6873 /*---- begin ODB directory table ----*/
6874
6875 r->rsprintf("<table class=\"mtable\" style=\"border-spacing:0px;\">\n");
6876 r->rsprintf("<tr><th colspan=%d class=\"mtableheader\">Online Database Browser</tr>\n", colspan);
6877 //buttons:
6878 if(!elog_mode){
6879 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6880 r->rsprintf("<input type=button value=Find onclick=\"self.location=\'?cmd=Find\';\">\n");
6881 r->rsprintf("<input type=button value=Create onclick=\"dlgShow('dlgCreate')\">\n");
6882 r->rsprintf("<input type=button value=Link onclick=\"dlgShow('dlgLink')\">\n");
6883 r->rsprintf("<input type=button value=Delete onclick=\"dlgShow('dlgDelete')\">\n");
6884 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());
6885 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());
6886 r->rsprintf("<input type=button value=\"Show ODB clients\" onclick=\"self.location=\'?cmd=odb_scl\';\">\n");
6887 r->rsprintf("</td></tr>\n");
6888 }
6889
6890 /*---- Build the Delete dialog------------------------------------*/
6891
6892 std::string dd = "";
6893
6894 dd += "<!-- Demo dialog -->\n";
6895 dd += "<div id=\"dlgDelete\" class=\"dlgFrame\">\n";
6896 dd += "<div class=\"dlgTitlebar\">Delete ODB entry</div>\n";
6897 dd += "<div class=\"dlgPanel\">\n";
6898 dd += "<div id=odbpath>";
6899 dd += "\"";
6900 dd += MJsonNode::Encode(odbpath.c_str());
6901 dd += "\"";
6902 dd += "</div>\n";
6903 dd += "<div><br></div>\n";
6904
6905 dd += "<table class=\"dialogTable\">\n";
6906 dd += "<th colspan=2>Delete ODB entries:</th>\n";
6907
6908 std::vector<std::string> delete_list;
6909
6910 int count_delete = 0;
6911
6912 /*---- ODB display -----------------------------------------------*/
6913
6914 /* display root key */
6915 r->rsprintf("<tr><td colspan=%d class='ODBpath'><b>", colspan);
6916 r->rsprintf("<a href=\"?cmd=oldodb\">/</a> \n");
6917
6918 std::string enc_root_path;
6919
6920 /*---- display path ----*/
6921 {
6922 const char* p = dec_path;
6923 while (*p) {
6924 std::string pd;
6925 while (*p && *p != '/')
6926 pd += *p++;
6927
6928 enc_root_path += urlEncode(pd.c_str());
6929
6930 if (pd.length() > 0)
6931 r->rsprintf("<a href=\"?cmd=oldodb&odb_path=%s\">%s</a>\n / ", enc_root_path.c_str(), pd.c_str());
6932
6933 enc_root_path += "/";
6934 if (*p == '/')
6935 p++;
6936 }
6937 }
6938
6939 r->rsprintf("</b></tr>\n");
6940
6941 /* enumerate subkeys */
6942 keyPresent = 0;
6943 for(int scan=0; scan<2; scan++){
6944 if(scan==1 && keyPresent==1) {
6945 r->rsprintf("<tr class=\"titleRow\">\n");
6946 r->rsprintf("<th class=\"ODBkey\">Key</th>\n");
6947 r->rsprintf("<th class=\"ODBvalue\">Value&nbsp;");
6948 r->rsprintf("<script type=\"text/javascript\">\n");
6949 r->rsprintf("function expand()\n");
6950 r->rsprintf("{\n");
6951 r->rsprintf(" var n = document.getElementsByName('ext');\n");
6952 r->rsprintf(" for (i=0 ; i<n.length ; i++) {\n");
6953 r->rsprintf(" if (n[i].style.display == 'none')\n");
6954 r->rsprintf(" n[i].style.display = 'table-cell';\n");
6955 r->rsprintf(" else\n");
6956 r->rsprintf(" n[i].style.display = 'none';\n");
6957 r->rsprintf(" }\n");
6958 r->rsprintf(" if (document.getElementById('expp').expflag === true) {\n");
6959 r->rsprintf(" document.getElementById('expp').expflag = false;\n");
6960 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E5;';\n");
6961 r->rsprintf(" } else {\n");
6962 r->rsprintf(" document.getElementById('expp').expflag = true;\n");
6963 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E4;';\n");
6964 r->rsprintf(" }\n");
6965 r->rsprintf("}\n");
6966 r->rsprintf("</script>");
6967 r->rsprintf("<div style=\"display:inline;float:right\"><a id=\"expp\"href=\"#\" onClick=\"expand();return false;\">&#x21E5;</div>");
6968 r->rsprintf("</th>\n");
6969 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Type</th>\n");
6970 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">#Val</th>\n");
6971 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Size</th>\n");
6972 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Written</th>\n");
6973 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Mode</th>\n");
6974 r->rsprintf("</tr>\n");
6975 }
6976 line = 0;
6977 for (int i = 0;; i++) {
6979 if (!hkey)
6980 break;
6981 db_get_link(hDB, hkey, &key);
6982
6983 if (scan == 0) {
6984 delete_list.push_back(key.name);
6985 }
6986
6987 if (line % 2 == 0)
6988 mstrlcpy(style, "ODBtableEven", sizeof(style));
6989 else
6990 mstrlcpy(style, "ODBtableOdd", sizeof(style));
6991
6992 std::string keyname = key.name;
6993 std::string enc_keyname = urlEncode(key.name);
6994
6995 std::string enc_full_path = enc_root_path + enc_keyname;
6996
6997 std::string odb_path = dec_path;
6998 if (odb_path.length() > 0 && odb_path[odb_path.length() - 1] != '/')
6999 odb_path += "/";
7000 odb_path += key.name;
7001
7002 /* resolve links */
7003 std::string enc_link_ref;
7004 char link_name[MAX_ODB_PATH];
7005 link_name[0] = 0;
7007 if (key.type == TID_LINK) {
7008 size = sizeof(link_name);
7010
7012
7013 if (status == DB_SUCCESS)
7014 db_get_key(hDB, hkey, &key);
7015
7016 //sprintf(link_ref, "?cmd=Set&odb_path=%s", full_path);
7017 enc_link_ref = "?cmd=Set&odb_path=";
7019
7020 if (status == DB_SUCCESS && link_name[0] == 0) {
7021 // fake the case when an empty link somehow resolves
7022 sprintf(link_name, "%s", "(empty)");
7023 }
7024 }
7025
7026 std::string enc_ref;
7027
7028 if (link_name[0]) {
7029 if (enc_root_path.back() == '/' && link_name[0] == '/') {
7030 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name+1);
7031 enc_ref = "";
7032 enc_ref += "?cmd=Set&odb_path=";
7034 enc_ref += urlEncode(link_name + 1);
7035 } else {
7036 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name);
7037 enc_ref = "";
7038 enc_ref += "?cmd=Set&odb_path=";
7041 }
7042 } else {
7043 //sprintf(ref, "?cmd=Set&odb_path=%s", full_path);
7044 enc_ref = "";
7045 enc_ref += "?cmd=Set&odb_path=";
7047 }
7048
7049 if (status != DB_SUCCESS) {
7050 if (scan == 1) {
7051 r->rsprintf("<tr><td class=\"yellowLight\">");
7052 r->rsprintf("%s <i>&rarr; <a href=\"%s\">%s</a></i><td><b><div style=\"color:red\">&lt;cannot resolve link&gt;</div></b></tr>\n", keyname.c_str(), enc_link_ref.c_str(), link_name[0]?link_name:"(empty)");
7053 }
7054 } else {
7055
7056 if (key.type == TID_KEY && scan == 0) {
7057 /* for keys, don't display data value */
7058 r->rsprintf("<tr><td colspan=%d class=\"ODBdirectory\"><a href=\"?cmd=oldodb&odb_path=%s\">&#x25B6 %s</a>\n", colspan, enc_full_path.c_str(), keyname.c_str());
7059 if (link_name[0])
7060 r->rsprintf("<i>&rarr; <a href=\"%s\">%s</a></i>", enc_link_ref.c_str(), link_name);
7061 r->rsprintf("</tr>\n");
7062 } else if(key.type != TID_KEY && scan == 1) {
7063
7064 if (strchr(link_name, '['))
7065 link_index = atoi(strchr(link_name, '[')+1);
7066 else
7067 link_index = -1;
7068
7069 /* display single value */
7070 if (key.num_values == 1 || link_index != -1) {
7071 char data[TEXT_SIZE];
7072 size = sizeof(data);
7073 db_get_data(hDB, hkey, data, &size, key.type);
7074
7075 std::string data_str;
7076
7077 if (link_index != -1)
7079 else
7081
7082 if (key.type == TID_STRING) {
7083 if (size == sizeof(data)) {
7084 data_str += "...(truncated)";
7085 }
7086 }
7087
7088 std::string hex_str;
7089
7090 if (key.type != TID_STRING) {
7091 if (link_index != -1)
7093 else
7095 }
7096
7097 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7098 data_str = "(empty)";
7099 hex_str = "";
7100 }
7101
7102 r->rsprintf("<tr>\n");
7103 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
7104 if (link_name[0]) {
7105 r->rsprintf("<td class=\"ODBkey\">\n");
7106 r->rsprintf("%s <i>&rarr; ", keyname.c_str());
7107 r->rsprintf("<a href=\"%s\">%s</a></i>\n", enc_link_ref.c_str(), link_name);
7108 r->rsprintf("<td class=\"%s\">\n", style);
7109 if (!write_access)
7110 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7111 else {
7112 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7113 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7114 }
7115 } else {
7116 r->rsprintf("<td class=\"ODBkey\">\n");
7117 r->rsprintf("%s<td class=\"%s\">", keyname.c_str(), style);
7118 if (!write_access)
7119 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7120 else {
7121 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7122 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7123 }
7124 }
7125 } else {
7126 if (strchr(data_str.c_str(), '\n')) {
7127 if (link_name[0]) {
7128 r->rsprintf("<td class=\"ODBkey\">");
7129 r->rsprintf("%s <i>&rarr; <a href=\"%s\">%s</a></i><td class=\"ODBvalue\">", keyname.c_str(), enc_link_ref.c_str(), link_name);
7130 } else
7131 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7132 r->rsprintf("\n<pre>");
7133 strencode3(r, data_str.c_str());
7134 r->rsprintf("</pre>");
7135 if (strlen(data) > data_str.length())
7136 r->rsprintf("<i>... (%d bytes total)<p>\n", (int)strlen(data));
7137
7138 r->rsprintf("<a href=\"%s\">Edit</a>\n", enc_ref.c_str());
7139 } else {
7140 if (link_name[0]) {
7141 r->rsprintf("<td class=\"ODBkey\">\n");
7142 r->rsprintf("%s <i>&rarr; <a href=\"%s\">%s</a></i><td class=\"%s\">", keyname.c_str(), enc_link_ref.c_str(), link_name, style);
7143 if (!write_access)
7144 strencode(r, data_str.c_str());
7145 else {
7146 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7147 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7148 strencode(r, data_str.c_str());
7149 r->rsprintf("</a>\n");
7150 }
7151 } else {
7152 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7153 if (!write_access) {
7154 strencode(r, data_str.c_str());
7155 } else {
7156 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7157 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7158 strencode(r, data_str.c_str());
7159 r->rsprintf("</a>\n");
7160 }
7161 }
7162 }
7163 }
7164
7165 /* extended key information */
7166 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7167 r->rsprintf("%s", rpc_tid_name(key.type));
7168 r->rsprintf("</td>\n");
7169
7170 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7171 r->rsprintf("%d", key.num_values);
7172 r->rsprintf("</td>\n");
7173
7174 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7175 r->rsprintf("%d", key.item_size);
7176 r->rsprintf("</td>\n");
7177
7178 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7180 if (delta < 60)
7181 r->rsprintf("%ds", delta);
7182 else if (delta < 3600)
7183 r->rsprintf("%1.0lfm", delta / 60.0);
7184 else if (delta < 86400)
7185 r->rsprintf("%1.0lfh", delta / 3600.0);
7186 else if (delta < 86400 * 99)
7187 r->rsprintf("%1.0lfd", delta / 86400.0);
7188 else
7189 r->rsprintf(">99d");
7190 r->rsprintf("</td>\n");
7191
7192 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7194 r->rsprintf("R");
7196 r->rsprintf("W");
7198 r->rsprintf("D");
7200 r->rsprintf("E");
7201 r->rsprintf("</td>\n");
7202
7203 line++;
7204 r->rsprintf("</tr>\n");
7205 } else { /* display array value */
7206 /* check for exceeding length */
7207 if (key.num_values > 1000 && !pp->isparam("all"))
7208 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);
7209 else {
7210 /* display first value */
7211 if (link_name[0])
7212 r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s<br><i>&rarr; <a href=\"%s\">%s</a></i>\n", key.num_values, keyname.c_str(), enc_link_ref.c_str(), link_name);
7213 else
7214 r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s\n", key.num_values, keyname.c_str());
7215
7216 for (int j = 0; j < key.num_values; j++) {
7217 if (line % 2 == 0)
7218 mstrlcpy(style, "ODBtableEven", sizeof(style));
7219 else
7220 mstrlcpy(style, "ODBtableOdd", sizeof(style));
7221
7222 char data[TEXT_SIZE];
7223 size = sizeof(data);
7224 db_get_data_index(hDB, hkey, data, &size, j, key.type);
7225 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
7226
7227 std::string hex_str;
7228 if (key.type == TID_STRING || key.type == TID_LINK) {
7229 hex_str = "";
7230 } else {
7232 }
7233
7234 if (key.type == TID_STRING) {
7235 if (size == sizeof(data)) {
7236 data_str += "...(truncated)";
7237 }
7238 }
7239
7240 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7241 data_str = "(empty)";
7242 hex_str = "";
7243 }
7244
7245 //sprintf(ref, "?cmd=Set&odb_path=%s&index=%d", full_path, j);
7246 enc_ref = "";
7247 enc_ref += "?cmd=Set&odb_path=";
7249 enc_ref += "&index=";
7250 enc_ref += toString(j);
7251
7252 std::string tmpstr;
7253 //sprintf(str, "%s[%d]", odb_path, j);
7254 tmpstr += odb_path;
7255 tmpstr += "[";
7256 tmpstr += toString(j);
7257 tmpstr += "]";
7258
7259 if (j > 0)
7260 r->rsprintf("<tr>");
7261
7262 r->rsprintf("<td class=\"%s\">[%d]&nbsp;", style, j);
7263 if (!write_access)
7264 r->rsprintf("<a href=\"%s\">", enc_ref.c_str());
7265 else {
7266 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), tmpstr.c_str());
7267 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", tmpstr.c_str());
7268 }
7269 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
7270 r->rsprintf("%s (%s)</a>\n", data_str.c_str(), hex_str.c_str());
7271 else
7272 r->rsprintf("%s</a>\n", data_str.c_str());
7273
7274 if (j == 0) {
7275 /* extended key information */
7276 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7277 r->rsprintf("%s", rpc_tid_name(key.type));
7278 r->rsprintf("</td>\n");
7279
7280 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7281 r->rsprintf("%d", key.num_values);
7282 r->rsprintf("</td>\n");
7283
7284 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7285 r->rsprintf("%d", key.item_size);
7286 r->rsprintf("</td>\n");
7287
7288 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7290 if (delta < 60)
7291 r->rsprintf("%ds", delta);
7292 else if (delta < 3600)
7293 r->rsprintf("%1.0lfm", delta / 60.0);
7294 else if (delta < 86400)
7295 r->rsprintf("%1.0lfh", delta / 3600.0);
7296 else if (delta < 86400 * 99)
7297 r->rsprintf("%1.0lfh", delta / 86400.0);
7298 else
7299 r->rsprintf(">99d");
7300 r->rsprintf("</td>\n");
7301
7302 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7304 r->rsprintf("R");
7306 r->rsprintf("W");
7308 r->rsprintf("D");
7310 r->rsprintf("E");
7311 r->rsprintf("</td>\n");
7312 }
7313 line++;
7314 }
7315
7316 r->rsprintf("</tr>\n");
7317 }
7318 }
7319 } else if(key.type != TID_KEY){
7320 keyPresent = 1; //flag that we've seen a key on the first pass, and should therefore write the Key / Value headline
7321 }
7322 }
7323 }
7324 }
7325 r->rsprintf("</table>\n");
7326 r->rsprintf("</div>\n"); // <div id="mmain">
7327
7328 /*---- Build the Delete dialog------------------------------------*/
7329
7330 std::sort(delete_list.begin(), delete_list.end());
7331
7332 for (unsigned i=0; i<delete_list.size(); i++) {
7333 std::string name = delete_list[i];
7334
7335 dd += "<tr><td style=\"text-align:left;\" align=left><input align=left type=checkbox id=delete";
7336 dd += toString(count_delete++);
7337 dd += " value=\'";
7338 dd += "\"";
7339 dd += MJsonNode::Encode(name.c_str());
7340 dd += "\"";
7341 dd += "\'>";
7342 dd += name;
7343 dd += "</input></td></tr>\n";
7344 }
7345
7346 dd += "</table>\n";
7347 dd += "<input type=button value=Delete onClick='mhttpd_delete_page_handle_delete(event);'>\n";
7348 dd += "<input type=button value=Cancel onClick='mhttpd_delete_page_handle_cancel(event);'>\n";
7349 dd += "</div>\n";
7350 dd += "</div>\n";
7351
7352 r->rsputs(dd.c_str());
7353
7354 /*---- Build the Create dialog------------------------------------*/
7355
7356 std::string cd = "";
7357
7358 cd += "<!-- Demo dialog -->\n";
7359 cd += "<div id=\"dlgCreate\" class=\"dlgFrame\">\n";
7360 cd += "<div class=\"dlgTitlebar\">Create ODB entry</div>\n";
7361 cd += "<div class=\"dlgPanel\">\n";
7362 cd += "<br />\n";
7363 cd += "<div id=odbpath>";
7364 cd += "\"";
7365 cd += MJsonNode::Encode(odbpath.c_str());
7366 cd += "\"";
7367 cd += "</div>\n";
7368 cd += "<div><br></div>\n";
7369
7370 cd += "<table class=\"dialogTable\">\n";
7371 cd += "<th colspan=2>Create ODB entry:</th>\n";
7372 cd += "<tr>";
7373 cd += "<td>Type";
7374 cd += "<td>";
7375 cd += "<select type=text size=1 id=create_tid name=type>";
7376 cd += "<option value=7>Integer (32-bit)";
7377 cd += "<option value=9>Float (4 Bytes)";
7378 cd += "<option value=12>String";
7379 cd += "<option selected value=15>Subdirectory";
7380 cd += "<option value=1>Byte";
7381 cd += "<option value=2>Signed byte";
7382 cd += "<option value=3>Character (8-bit)";
7383 cd += "<option value=4>Word (16-bit)";
7384 cd += "<option value=5>Short integer (16-bit)";
7385 cd += "<option value=6>Double Word (32-bit)";
7386 cd += "<option value=8>Boolean";
7387 cd += "<option value=10>Double float (8 Bytes)";
7388 //cd += "<option value=16>Symbolic link";
7389 cd += "</select>";
7390 cd += "</tr>\n";
7391 cd += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=create_name name=value></tr>\n";
7392 cd += "<tr><td>Array size<td><input type=text size=31 maxlength=31 id=create_array_length name=index value=1></tr>\n";
7393 cd += "<tr><td>String length<td><input type=text size=31 maxlength=31 id=create_strlen name=strlen value=32></tr>\n";
7394 cd += "</table>\n";
7395 cd += "<input type=button value=Create onClick='mhttpd_create_page_handle_create(event);'>\n";
7396 cd += "<input type=button value=Cancel onClick='mhttpd_create_page_handle_cancel(event);'>\n";
7397 cd += "</div>\n";
7398 cd += "</div>\n";
7399
7400 r->rsputs(cd.c_str());
7401
7402 /*---- Build the Link dialog------------------------------------*/
7403
7404 std::string ld = "";
7405
7406 ld += "<!-- Demo dialog -->\n";
7407 ld += "<div id=\"dlgLink\" class=\"dlgFrame\">\n";
7408 ld += "<div class=\"dlgTitlebar\">Create a link to an ODB entry</div>\n";
7409 ld += "<div class=\"dlgPanel\">\n";
7410 ld += "<br />\n";
7411 ld += "<div id=link_odbpath>";
7412 ld += "\"";
7413 ld += MJsonNode::Encode(odbpath.c_str());
7414 ld += "\"";
7415 ld += "</div>\n";
7416 ld += "<div><br></div>\n";
7417
7418 ld += "<table class=\"dialogTable\">\n";
7419 ld += "<th colspan=2>Create a link to an ODB entry:</th>\n";
7420 ld += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=link_name name=value></tr>\n";
7421 ld += "<tr><td>Link target<td><input type=text size=31 maxlength=256 id=link_target name=target></tr>\n";
7422 ld += "</table>\n";
7423 ld += "<input type=button value=Link onClick='mhttpd_link_page_handle_link(event);'>\n";
7424 ld += "<input type=button value=Cancel onClick='mhttpd_link_page_handle_cancel(event);'>\n";
7425 ld += "</div>\n";
7426 ld += "</div>\n";
7427
7428 r->rsputs(ld.c_str());
7429}
7430
7431/*------------------------------------------------------------------*/
7432
7434 const char *group,
7435 int index, const char *value)
7436{
7437 int status, size;
7438 HNDLE hDB, hkey;
7439 KEY key;
7440 char data[TEXT_SIZE];
7441
7442 std::string odb_path = pp->getparam("odb_path");
7443
7444 //printf("show_set_page: odb_path [%s] group [%s] index %d value [%s]\n", odb_path.c_str(), group, index, value);
7445
7447
7448 /* show set page if no value is given */
7449 if (!pp->isparam("value") && !*pp->getparam("text")) {
7450 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7451 if (status != DB_SUCCESS) {
7452 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7453 return;
7454 }
7455 db_get_link(hDB, hkey, &key);
7456
7457 show_header(r, "Set value", "POST", "", 0);
7458 //close header:
7459 r->rsprintf("</table>");
7460
7461 //main table:
7462 r->rsprintf("<table class=\"dialogTable\">");
7463
7464 if (index > 0)
7465 r->rsprintf("<input type=hidden name=index value=\"%d\">\n", index);
7466 else
7467 index = 0;
7468
7469 if (group[0])
7470 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", group);
7471
7472 r->rsprintf("<input type=hidden name=odb_path value=\"%s\">\n", odb_path.c_str());
7473
7474 std::string data_str1 = rpc_tid_name(key.type);
7475 std::string str1;
7476 if (key.num_values > 1) {
7477 data_str1 += msprintf("[%d]", key.num_values);
7478 str1 = msprintf("%s[%d]", odb_path.c_str(), index);
7479 } else
7480 str1 = odb_path.c_str();
7481
7482 r->rsprintf("<tr><th colspan=2>Set new value - type = %s</tr>\n", data_str1.c_str());
7483 r->rsprintf("<tr><td>%s<td>\n", str1.c_str());
7484
7485 /* set current value as default */
7486 size = sizeof(data);
7487 db_get_link_data(hDB, hkey, data, &size, key.type);
7488 std::string data_str = db_sprintf(data, key.item_size, index, key.type);
7489
7490 if (equal_ustring(data_str.c_str(), "<NULL>"))
7491 data_str = "";
7492
7493 if (strchr(data_str.c_str(), '\n') != NULL) {
7494 r->rsprintf("<textarea rows=20 cols=80 name=\"text\">\n");
7495 strencode3(r, data);
7496 r->rsprintf("</textarea>\n");
7497 } else {
7498 size = 20;
7499 if ((int) data_str.length() > size)
7500 size = data_str.length() + 3;
7501 if (size > 80)
7502 size = 80;
7503
7504 r->rsprintf("<input type=\"text\" size=%d maxlength=256 name=\"value\" value=\"", size);
7505 strencode(r, data_str.c_str());
7506 r->rsprintf("\">\n");
7507 }
7508
7509 r->rsprintf("</tr>\n");
7510
7511 r->rsprintf("<tr><td align=center colspan=2>");
7512 r->rsprintf("<input type=submit name=cmd value=Set>");
7513 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7514 r->rsprintf("</tr>");
7515 r->rsprintf("</table>");
7516
7517 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
7518
7519 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7520 r->rsprintf("</form>\n");
7521 r->rsprintf("</body></html>\r\n");
7522 return;
7523 } else {
7524 /* set value */
7525
7526 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7527 if (status != DB_SUCCESS) {
7528 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7529 return;
7530 }
7531 db_get_link(hDB, hkey, &key);
7532
7533 memset(data, 0, sizeof(data));
7534
7535 if (pp->getparam("text") && *pp->getparam("text"))
7536 mstrlcpy(data, pp->getparam("text"), sizeof(data));
7537 else
7538 db_sscanf(value, data, &size, 0, key.type);
7539
7540 if (index < 0)
7541 index = 0;
7542
7543 /* extend data size for single string if necessary */
7544 if ((key.type == TID_STRING || key.type == TID_LINK)
7545 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
7546 key.item_size = strlen(data) + 1;
7547
7548 if (key.item_size == 0)
7550
7551 if (key.num_values > 1)
7553 else
7555
7556 if (status == DB_NO_ACCESS)
7557 r->rsprintf("<h2>Write access not allowed</h2>\n");
7558
7559 redirect(r, "");
7560
7561 return;
7562 }
7563}
7564
7565/*------------------------------------------------------------------*/
7566
7567void show_find_page(Return* r, const char *value)
7568{
7569 HNDLE hDB, hkey;
7570
7572
7573 if (value[0] == 0) {
7574 /* without value, show find dialog */
7575 show_header(r, "Find value", "GET", "", 0);
7576
7577 //end header:
7578 r->rsprintf("</table>");
7579
7580 //find dialog:
7581 r->rsprintf("<table class=\"dialogTable\">");
7582
7583 r->rsprintf("<tr><th colspan=2>Find string in Online Database</tr>\n");
7584 r->rsprintf("<tr><td>Enter substring (case insensitive)\n");
7585
7586 r->rsprintf("<td><input type=\"text\" size=\"20\" maxlength=\"80\" name=\"value\">\n");
7587 r->rsprintf("</tr>");
7588
7589 r->rsprintf("<tr><td align=center colspan=2>");
7590 r->rsprintf("<input type=submit name=cmd value=Find>");
7591 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7592 r->rsprintf("</tr>");
7593 r->rsprintf("</table>");
7594
7595 r->rsprintf("<input type=hidden name=cmd value=Find>");
7596
7597 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7598 r->rsprintf("</form>\n");
7599 r->rsprintf("</body></html>\r\n");
7600 } else {
7601 show_header(r, "Search results", "GET", "", 0);
7602
7603 r->rsprintf("<table class=\"mtable\">\n");
7604 r->rsprintf("<tr><th colspan=2 class=\"mtableheader\">");
7605 r->rsprintf("Results of search for substring \"%s\"</tr>\n", value);
7606 r->rsprintf("<tr><th class=\"titlerow\">Key<th>Value</tr>\n");
7607
7608 /* start from root */
7609 db_find_key(hDB, 0, "", &hkey);
7610 assert(hkey);
7611
7612 /* scan tree, call "search_callback" for each key */
7614 data.r = r;
7615 data.search_name = value;
7616
7617 db_scan_tree(hDB, hkey, 0, search_callback, (void *)&data);
7618
7619 r->rsprintf("</table>");
7620 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7621 r->rsprintf("</form>\n");
7622 r->rsprintf("</body></html>\r\n");
7623 }
7624}
7625
7626/*------------------------------------------------------------------*/
7627
7628#define LN10 2.302585094
7629#define LOG2 0.301029996
7630#define LOG5 0.698970005
7631
7632void haxis(gdImagePtr im, gdFont * font, int col, int gcol,
7633 int x1, int y1, int width,
7634 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7635{
7638 char str[80];
7639 double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7640
7641 if (xmax <= xmin || width <= 0)
7642 return;
7643
7644 /* use 5 as min tick distance */
7645 dx = (xmax - xmin) / (double) (width / 5);
7646
7647 frac_dx = modf(log(dx) / LN10, &int_dx);
7648 if (frac_dx < 0) {
7649 frac_dx += 1;
7650 int_dx -= 1;
7651 }
7652
7653 tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
7655
7656 /* rounding up of dx, label_dx */
7657 dx = pow(10, int_dx) * base[tick_base];
7658 major_dx = pow(10, int_dx) * base[major_base];
7660
7661 /* number of significant digits */
7662 if (xmin == 0)
7663 n_sig1 = 0;
7664 else
7665 n_sig1 = (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7666
7667 if (xmax == 0)
7668 n_sig2 = 0;
7669 else
7670 n_sig2 =
7671 (int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7672
7673 n_sig1 = MAX(n_sig1, n_sig2);
7674 n_sig1 = MAX(n_sig1, 4);
7675
7676 /* determination of maximal width of labels */
7677 sprintf(str, "%1.*lG", n_sig1, floor(xmin / dx) * dx);
7678 maxwidth = font->h / 2 * strlen(str);
7679 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx);
7680 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7681 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx + label_dx);
7682 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7683
7684 /* increasing label_dx, if labels would overlap */
7685 while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7686 label_base++;
7687 label_dx = pow(10, int_dx) * base[label_base];
7688 if (label_base % 3 == 2 && major_base % 3 == 1) {
7689 major_base++;
7690 major_dx = pow(10, int_dx) * base[major_base];
7691 }
7692 }
7693
7694 x_act = floor(xmin / dx) * dx;
7695
7696 gdImageLine(im, x1, y1, x1 + width, y1, col);
7697
7698 do {
7699 x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
7700 xs = (int) (x_screen + 0.5);
7701
7702 if (x_screen > x1 + width + 0.001)
7703 break;
7704
7705 if (x_screen >= x1) {
7706 if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
7707 dx / major_dx / 10.0) {
7708
7709 if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
7710 dx / label_dx / 10.0) {
7711 /* label tick mark */
7712 gdImageLine(im, xs, y1, xs, y1 + text, col);
7713
7714 /* grid line */
7715 if (grid != 0 && xs > x1 && xs < x1 + width)
7716 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7717
7718 /* label */
7719 if (label != 0) {
7720 sprintf(str, "%1.*lG", n_sig1, x_act);
7721 gdImageString(im, font, (int) xs - font->w * strlen(str) / 2,
7722 y1 + label, str, col);
7723 }
7724 } else {
7725 /* major tick mark */
7726 gdImageLine(im, xs, y1, xs, y1 + major, col);
7727
7728 /* grid line */
7729 if (grid != 0 && xs > x1 && xs < x1 + width)
7730 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7731 }
7732
7733 } else
7734 /* minor tick mark */
7735 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7736
7737 }
7738
7739 x_act += dx;
7740
7741 /* supress 1.23E-17 ... */
7742 if (fabs(x_act) < dx / 100)
7743 x_act = 0;
7744
7745 } while (1);
7746}
7747
7748/*------------------------------------------------------------------*/
7749
7750void sec_to_label(char *result, int sec, int base, int force_date)
7751{
7752 char mon[80];
7753 time_t t_sec;
7754
7755 t_sec = (time_t) sec;
7756
7757 struct tm tms;
7758 localtime_r(&t_sec, &tms);
7759 strcpy(mon, mname[tms.tm_mon]);
7760 mon[3] = 0;
7761
7762 if (force_date) {
7763 if (base < 600)
7764 sprintf(result, "%02d %s %02d %02d:%02d:%02d",
7765 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min,
7766 tms.tm_sec);
7767 else if (base < 3600 * 24)
7768 sprintf(result, "%02d %s %02d %02d:%02d",
7769 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7770 else
7771 sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7772 } else {
7773 if (base < 600)
7774 sprintf(result, "%02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec);
7775 else if (base < 3600 * 3)
7776 sprintf(result, "%02d:%02d", tms.tm_hour, tms.tm_min);
7777 else if (base < 3600 * 24)
7778 sprintf(result, "%02d %s %02d %02d:%02d",
7779 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7780 else
7781 sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7782 }
7783}
7784
7785void taxis(gdImagePtr im, gdFont * font, int col, int gcol,
7786 int x1, int y1, int width, int xr,
7787 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7788{
7791 char str[80];
7792 const int base[] = { 1, 5, 10, 60, 300, 600, 1800, 3600, 3600 * 6, 3600 * 12, 3600 * 24, 0 };
7793 time_t ltime;
7794 int force_date, d1, d2;
7795 struct tm tms;
7796
7797 if (xmax <= xmin || width <= 0)
7798 return;
7799
7800 /* force date display if xmax not today */
7801 ltime = ss_time();
7802 localtime_r(&ltime, &tms);
7803 d1 = tms.tm_mday;
7804 ltime = (time_t) xmax;
7805 localtime_r(&ltime, &tms);
7806 d2 = tms.tm_mday;
7807 force_date = (d1 != d2);
7808
7809 /* use 5 pixel as min tick distance */
7810 dx = (int) ((xmax - xmin) / (double) (width / 5) + 0.5);
7811
7812 for (tick_base = 0; base[tick_base]; tick_base++) {
7813 if (base[tick_base] > dx)
7814 break;
7815 }
7816 if (!base[tick_base])
7817 tick_base--;
7818 dx = base[tick_base];
7819
7820 if (base[tick_base + 1])
7821 major_base = tick_base + 1;
7822 else
7825
7826 if (base[major_base + 1])
7827 label_base = major_base + 1;
7828 else
7831
7832 do {
7833 sec_to_label(str, (int) (xmin + 0.5), label_dx, force_date);
7834 maxwidth = font->h / 2 * strlen(str);
7835
7836 /* increasing label_dx, if labels would overlap */
7837 if (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7838 if (base[label_base + 1])
7840 else
7841 label_dx += 3600 * 24;
7842 } else
7843 break;
7844 } while (1);
7845
7846 x_act =
7847 (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
7848
7849 gdImageLine(im, x1, y1, x1 + width, y1, col);
7850
7851 do {
7852 x_screen = (int) ((x_act - xmin) / (xmax - xmin) * width + x1 + 0.5);
7853 xs = (int) (x_screen + 0.5);
7854
7855 if (x_screen > x1 + width + 0.001)
7856 break;
7857
7858 if (x_screen >= x1) {
7859 if ((x_act - ss_timezone()) % major_dx == 0) {
7860 if ((x_act - ss_timezone()) % label_dx == 0) {
7861 /* label tick mark */
7862 gdImageLine(im, xs, y1, xs, y1 + text, col);
7863
7864 /* grid line */
7865 if (grid != 0 && xs > x1 && xs < x1 + width)
7866 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7867
7868 /* label */
7869 if (label != 0) {
7871
7872 /* if labels at edge, shift them in */
7873 xl = (int) xs - font->w * strlen(str) / 2;
7874 if (xl < 0)
7875 xl = 0;
7876 if (xl + font->w * (int) strlen(str) > xr)
7877 xl = xr - font->w * strlen(str);
7878 gdImageString(im, font, xl, y1 + label, str, col);
7879 }
7880 } else {
7881 /* major tick mark */
7882 gdImageLine(im, xs, y1, xs, y1 + major, col);
7883
7884 /* grid line */
7885 if (grid != 0 && xs > x1 && xs < x1 + width)
7886 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7887 }
7888
7889 } else
7890 /* minor tick mark */
7891 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7892
7893 }
7894
7895 x_act += dx;
7896
7897 /* supress 1.23E-17 ... */
7898 if (fabs((double)x_act) < dx / 100)
7899 x_act = 0;
7900
7901 } while (1);
7902}
7903
7904/*------------------------------------------------------------------*/
7905
7906int vaxis(gdImagePtr im, gdFont * font, int col, int gcol,
7907 int x1, int y1, int width,
7908 int minor, int major, int text, int label, int grid, double ymin, double ymax,
7909 BOOL logaxis)
7910{
7913 int last_label_y;
7914 char str[80];
7915 const double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7916
7917 if (ymax <= ymin || width <= 0)
7918 return 0;
7919
7920 // 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
7921 if (fabs(ymax - ymin) <= 1e-10)
7922 return 0;
7923
7924 if (logaxis) {
7925 dy = pow(10, floor(log(ymin) / LN10));
7926 label_dy = dy;
7927 major_dy = dy * 10;
7928 n_sig1 = 4;
7929 } else {
7930 dy = (ymax - ymin) / (double) (width / 5);
7931
7932 frac_dy = modf(log(dy) / LN10, &int_dy);
7933 if (frac_dy < 0) {
7934 frac_dy += 1;
7935 int_dy -= 1;
7936 }
7937
7938 tick_base = frac_dy < LOG2 ? 1 : frac_dy < LOG5 ? 2 : 3;
7940
7941 /* rounding up of dy, label_dy */
7942 dy = pow(10, int_dy) * base[tick_base];
7943 major_dy = pow(10, int_dy) * base[major_base];
7945
7946 /* number of significant digits */
7947 if (ymin == 0)
7948 n_sig1 = 0;
7949 else
7950 n_sig1 =
7951 (int) floor(log(fabs(ymin)) / LN10) -
7952 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7953
7954 if (ymax == 0)
7955 n_sig2 = 0;
7956 else
7957 n_sig2 =
7958 (int) floor(log(fabs(ymax)) / LN10) -
7959 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7960
7961 n_sig1 = MAX(n_sig1, n_sig2);
7962 n_sig1 = MAX(n_sig1, 4);
7963
7964 /* increasing label_dy, if labels would overlap */
7965 while (label_dy / (ymax - ymin) * width < 1.5 * font->h) {
7966 label_base++;
7967 label_dy = pow(10, int_dy) * base[label_base];
7968 if (label_base % 3 == 2 && major_base % 3 == 1) {
7969 major_base++;
7970 major_dy = pow(10, int_dy) * base[major_base];
7971 }
7972 }
7973 }
7974
7975 max_width = 0;
7976 y_act = floor(ymin / dy) * dy;
7977
7978 if (x1 != 0 || y1 != 0)
7979 gdImageLine(im, x1, y1, x1, y1 - width, col);
7980
7981 last_label_y = y1 + 2 * font->h;
7982
7983 do {
7984 if (logaxis)
7985 y_screen = y1 - (log(y_act) - log(ymin)) / (log(ymax) - log(ymin)) * width;
7986 else
7987 y_screen = y1 - (y_act - ymin) / (ymax - ymin) * width;
7988 ys = (int) (y_screen + 0.5);
7989
7990 if (y_screen < y1 - width - 0.001)
7991 break;
7992
7993 if (y_screen <= y1 + 0.001) {
7994 if (fabs(floor(y_act / major_dy + 0.5) - y_act / major_dy) <
7995 dy / major_dy / 10.0) {
7996 if (fabs(floor(y_act / label_dy + 0.5) - y_act / label_dy) <
7997 dy / label_dy / 10.0) {
7998 if (x1 != 0 || y1 != 0) {
7999 /* label tick mark */
8000 gdImageLine(im, x1, ys, x1 + text, ys, col);
8001
8002 /* grid line */
8003 if (grid != 0 && y_screen < y1 && y_screen > y1 - width) {
8004 if (grid > 0)
8005 gdImageLine(im, x1 + 1, ys, x1 + grid, ys, gcol);
8006 else
8007 gdImageLine(im, x1 - 1, ys, x1 + grid, ys, gcol);
8008 }
8009
8010 /* label */
8011 if (label != 0) {
8012 sprintf(str, "%1.*lG", n_sig1, y_act);
8013 if (label < 0)
8014 gdImageString(im, font, x1 + label - font->w * strlen(str),
8015 ys - font->h / 2, str, col);
8016 else
8017 gdImageString(im, font, x1 + label, ys - font->h / 2, str, col);
8018
8019 last_label_y = ys - font->h / 2;
8020 }
8021 } else {
8022 sprintf(str, "%1.*lG", n_sig1, y_act);
8023 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8024 }
8025 } else {
8026 if (x1 != 0 || y1 != 0) {
8027 /* major tick mark */
8028 gdImageLine(im, x1, ys, x1 + major, ys, col);
8029
8030 /* grid line */
8031 if (grid != 0 && y_screen < y1 && y_screen > y1 - width)
8032 gdImageLine(im, x1, ys, x1 + grid, ys, col);
8033 }
8034 }
8035 if (logaxis) {
8036 dy *= 10;
8037 major_dy *= 10;
8038 label_dy *= 10;
8039 }
8040
8041 } else {
8042 if (x1 != 0 || y1 != 0) {
8043 /* minor tick mark */
8044 gdImageLine(im, x1, ys, x1 + minor, ys, col);
8045 }
8046
8047 /* for logaxis, also put labes on minor tick marks */
8048 if (logaxis) {
8049 if (label != 0) {
8050 if (x1 != 0 || y1 != 0) {
8051 /* calculate position of next major label */
8052 y_next = pow(10, floor(log(y_act) / LN10) + 1);
8053 y_screen =
8054 (int) (y1 -
8055 (log(y_next) - log(ymin)) / (log(ymax) -
8056 log(ymin)) * width + 0.5);
8057
8058 if (ys + font->h / 2 < last_label_y
8059 && ys - font->h / 2 > y_screen + font->h / 2) {
8060 sprintf(str, "%1.*lG", n_sig1, y_act);
8061 if (label < 0)
8062 gdImageString(im, font, x1 + label - font->w * strlen(str),
8063 ys - font->h / 2, str, col);
8064 else
8065 gdImageString(im, font, x1 + label, ys - font->h / 2, str,
8066 col);
8067 }
8068
8069 last_label_y = ys - font->h / 2;
8070 } else {
8071 sprintf(str, "%1.*lG", n_sig1, y_act);
8072 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8073 }
8074 }
8075 }
8076 }
8077 }
8078
8079 y_act += dy;
8080
8081 /* supress 1.23E-17 ... */
8082 if (fabs(y_act) < dy / 100)
8083 y_act = 0;
8084
8085 } while (1);
8086
8087 return max_width + abs(label);
8088}
8089
8090/*------------------------------------------------------------------*/
8091
8092int time_to_sec(const char *str)
8093{
8094 double s;
8095
8096 s = atof(str);
8097 switch (str[strlen(str) - 1]) {
8098 case 'm':
8099 case 'M':
8100 s *= 60;
8101 break;
8102 case 'h':
8103 case 'H':
8104 s *= 3600;
8105 break;
8106 case 'd':
8107 case 'D':
8108 s *= 3600 * 24;
8109 break;
8110 }
8111
8112 return (int) s;
8113}
8114
8115/*------------------------------------------------------------------*/
8116
8118{
8119 time_t t = 0;
8120 for (; *str != 0; str++) {
8121 if (*str < '0')
8122 break;
8123 if (*str > '9')
8124 break;
8125 t *= 10;
8126 t += *str - '0';
8127 }
8128 return t;
8129}
8130
8131/*------------------------------------------------------------------*/
8132
8134{
8135 char buf[256];
8136 sprintf(buf, "%.0f", (double)t);
8137 return buf;
8138}
8139
8140/*------------------------------------------------------------------*/
8141
8142static bool gDoSetupHistoryWatch = true;
8143static bool gDoReloadHistory = false;
8144
8146{
8147 //printf("history_watch_callback %d %d %d\n", hDB, hKey, index);
8148 gDoReloadHistory = true;
8149 cm_msg(MINFO, "history_watch_callback", "History configuration may have changed, will reconnect");
8150}
8151
8153static HNDLE gMhkey = 0;
8154
8155/*------------------------------------------------------------------*/
8156
8157static MidasHistoryInterface* get_history(bool reset = false)
8158{
8159 int status;
8160 HNDLE hDB;
8161
8162 // history reconnect requested by watch callback?
8163
8164 if (gDoReloadHistory) {
8165 gDoReloadHistory = false;
8166 reset = true;
8167 }
8168
8169 // disconnect from previous history
8170
8171 if (reset && gMh) {
8172 gMh->hs_disconnect();
8173 delete gMh;
8174 gMh = NULL;
8175 gMhkey = 0;
8176 }
8177
8179 assert(status == CM_SUCCESS);
8180
8181 // setup a watch on history configuration
8182
8184 HNDLE hKey;
8185 gDoSetupHistoryWatch = false;
8186
8187 status = db_find_key(hDB, 0, "/Logger/History", &hKey);
8188 if (status == DB_SUCCESS)
8190
8191 status = db_find_key(hDB, 0, "/History/LoggerHistoryChannel", &hKey);
8192 if (status == DB_SUCCESS)
8194 }
8195
8196 // find out if ODB settings have changed and we need to connect to a different history channel
8197
8198 HNDLE hKey = 0;
8200 if (status != HS_SUCCESS)
8201 return gMh;
8202
8203 //printf("mh %p, hKey %d, mhkey %d\n", mh, hKey, mhkey);
8204
8205 if (gMh && hKey == gMhkey) // same channel as before
8206 return gMh;
8207
8208 if (gMh) {
8209 delete gMh;
8210 gMh = NULL;
8211 gMhkey = 0;
8212 }
8213
8215 if (status != HS_SUCCESS || gMh==NULL) {
8216 cm_msg(MERROR, "get_history", "Cannot configure history, hs_get_history() status %d", status);
8217 gMh = NULL;
8218 return NULL;
8219 }
8220
8221 gMhkey = hKey;
8222
8223 // cm_msg(MINFO, "get_history", "Reading history from channel \'%s\' type \'%s\'", mh->name, mh->type);
8224
8225 return gMh;
8226}
8227
8228/*------------------------------------------------------------------*/
8229
8230#ifdef OS_WINNT
8231#undef DELETE
8232#endif
8233
8234#define ALLOC(t,n) (t*)calloc(sizeof(t),(n))
8235#define DELETE(x) if (x) { free(x); (x)=NULL; }
8236#define DELETEA(x, n) if (x) { for (int i=0; i<(n); i++) { free((x)[i]); (x)[i]=NULL; }; DELETE(x); }
8237#define STRDUP(x) strdup(x)
8238
8240{
8250 double** v;
8251
8254
8258
8259 void Allocate(int xnvars) {
8260 if (alloc_nvars > 0)
8261 Free();
8262 nvars = 0;
8264 event_names = ALLOC(char*, alloc_nvars);
8265 var_names = ALLOC(char*, alloc_nvars);
8266 var_index = ALLOC(int, alloc_nvars);
8267 odb_index = ALLOC(int, alloc_nvars);
8268 status = ALLOC(int, alloc_nvars);
8271 v = ALLOC(double*, alloc_nvars);
8272
8273 have_last_written = false;
8275 }
8276
8277 void Free() {
8282 DELETE(status);
8287 nvars = 0;
8288 alloc_nvars = 0;
8289 have_last_written = false;
8290 }
8291
8292 void Print() const {
8293 printf("this %p, nvars %d. tstart %d, tend %d, scale %d\n", this, nvars, (int)tstart, (int)tend, (int)scale);
8294 for (int i=0; i<nvars; i++) {
8295 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]);
8296 if (status[i]==HS_SUCCESS && num_entries[i]>0 && t[i] && v[i])
8297 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]);
8298 printf(" last_written %d", (int)last_written[i]);
8299 printf("\n");
8300 }
8301 }
8302
8303 HistoryData() // ctor
8304 {
8305 nvars = 0;
8306 alloc_nvars = 0;
8307 have_last_written = false;
8308 tstart = 0;
8309 tend = 0;
8310 scale = 0;
8311 }
8312
8314 {
8315 if (alloc_nvars > 0)
8316 Free();
8317 }
8318};
8319
8320#define READ_HISTORY_DATA 0x1
8321#define READ_HISTORY_RUNMARKER 0x2
8322#define READ_HISTORY_LAST_WRITTEN 0x4
8323
8325{
8326 std::string event_name;
8327 std::string tag_name;
8328 std::string formula;
8329 std::string colour;
8330 std::string label;
8331 bool show_raw_value = false;
8332 int order = -1;
8333 double factor = 1.0;
8334 double offset = 0;
8335 double voffset = 0;
8336};
8337
8339{
8340 std::string timescale = "1h";
8341 double minimum = 0;
8342 double maximum = 0;
8343 bool zero_ylow = false;
8344 bool log_axis = false;
8345 bool show_run_markers = true;
8346 bool show_values = true;
8347 bool show_fill = true;
8348 bool show_factor = false;
8349 bool enable_factor = true;
8350
8351 std::vector<HistVar> vars;
8352};
8353
8354static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel);
8355
8356int 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)
8357{
8358 //HNDLE hkeypanel, hkeydvar, hkey;
8359 //KEY key;
8360 //char path[256];
8361 //int n_vars;
8362 int status;
8363 int debug = 1;
8364
8365 //mstrlcpy(path, group, sizeof(path));
8366 //mstrlcat(path, "/", sizeof(path));
8367 //mstrlcat(path, panel, sizeof(path));
8368
8369 //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);
8370
8371 /* connect to history */
8373 if (mh == NULL) {
8374 //r->rsprintf(str, "History is not configured\n");
8375 return HS_FILE_ERROR;
8376 }
8377
8378#if 0
8379 /* check panel name in ODB */
8380 status = db_find_key(hDB, 0, "/History/Display", &hkey);
8381 if (!hkey) {
8382 cm_msg(MERROR, "read_history", "Cannot find \'/History/Display\' in ODB, status %d", status);
8383 return HS_FILE_ERROR;
8384 }
8385
8386 /* check panel name in ODB */
8387 status = db_find_key(hDB, hkey, path, &hkeypanel);
8388 if (!hkeypanel) {
8389 cm_msg(MERROR, "read_history", "Cannot find \'%s\' in ODB, status %d", path, status);
8390 return HS_FILE_ERROR;
8391 }
8392
8393 status = db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8394 if (!hkeydvar) {
8395 cm_msg(MERROR, "read_history", "Cannot find \'%s/Variables\' in ODB, status %d", path, status);
8396 return HS_FILE_ERROR;
8397 }
8398
8401#endif
8402
8403 data->Allocate(hp.vars.size()+2);
8404
8405 data->tstart = tstart;
8406 data->tend = tend;
8407 data->scale = scale;
8408
8409 for (size_t i=0; i<hp.vars.size(); i++) {
8410 if (index != -1 && (size_t)index != i)
8411 continue;
8412
8413 //char str[256];
8414 //int size = sizeof(str);
8415 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8416 //if (status != DB_SUCCESS) {
8417 // cm_msg(MERROR, "read_history", "Cannot read tag %d in panel %s, status %d", i, path, status);
8418 // continue;
8419 //}
8420
8421 /* split varname in event, variable and index: "event/tag[index]" */
8422
8423 //char *p = strchr(str, ':');
8424 //if (!p)
8425 // p = strchr(str, '/');
8426 //
8427 //if (!p) {
8428 // cm_msg(MERROR, "read_history", "Tag \"%s\" has wrong format in panel \"%s\"", str, path);
8429 // continue;
8430 //}
8431
8432 //*p = 0;
8433
8434 data->odb_index[data->nvars] = i;
8435 data->event_names[data->nvars] = STRDUP(hp.vars[i].event_name.c_str());
8436 data->var_names[data->nvars] = STRDUP(hp.vars[i].tag_name.c_str());
8437 data->var_index[data->nvars] = 0;
8438
8439 char *q = strchr(data->var_names[data->nvars], '[');
8440 if (q) {
8441 data->var_index[data->nvars] = atoi(q+1);
8442 *q = 0;
8443 }
8444
8445 data->nvars++;
8446 } // loop over variables
8447
8448 /* write run markes if selected */
8449 if (flags & READ_HISTORY_RUNMARKER) {
8450
8451 data->event_names[data->nvars+0] = STRDUP("Run transitions");
8452 data->event_names[data->nvars+1] = STRDUP("Run transitions");
8453
8454 data->var_names[data->nvars+0] = STRDUP("State");
8455 data->var_names[data->nvars+1] = STRDUP("Run number");
8456
8457 data->var_index[data->nvars+0] = 0;
8458 data->var_index[data->nvars+1] = 0;
8459
8460 data->odb_index[data->nvars+0] = -1;
8461 data->odb_index[data->nvars+1] = -2;
8462
8463 data->nvars += 2;
8464 }
8465
8466 bool get_last_written = false;
8467
8468 if (flags & READ_HISTORY_DATA) {
8469 status = mh->hs_read(tstart, tend, scale,
8470 data->nvars,
8471 data->event_names,
8472 data->var_names,
8473 data->var_index,
8474 data->num_entries,
8475 data->t,
8476 data->v,
8477 data->status);
8478
8479 if (debug) {
8480 printf("read_history: nvars %d, hs_read() status %d\n", data->nvars, status);
8481 for (int i=0; i<data->nvars; i++) {
8482 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]);
8483 }
8484 }
8485
8486 if (status != HS_SUCCESS) {
8487 cm_msg(MERROR, "read_history", "Complete history failure, hs_read() status %d, see messages", status);
8488 return HS_FILE_ERROR;
8489 }
8490
8491 for (int i=0; i<data->nvars; i++) {
8492 if (data->status[i] != HS_SUCCESS || data->num_entries[i] < 1) {
8493 get_last_written = true;
8494 break;
8495 }
8496 }
8497 }
8498
8499 if (flags & READ_HISTORY_LAST_WRITTEN)
8500 get_last_written = true;
8501
8502 if (get_last_written) {
8503 data->have_last_written = true;
8504
8506 tstart,
8507 data->nvars,
8508 data->event_names,
8509 data->var_names,
8510 data->var_index,
8511 data->last_written);
8512
8513 if (status != HS_SUCCESS) {
8514 data->have_last_written = false;
8515 }
8516 }
8517
8518 return SUCCESS;
8519}
8520
8521int get_hist_last_written(MVOdb* odb, const char *group, const char *panel, time_t endtime, int index, int want_all, time_t *plastwritten)
8522{
8523 //HNDLE hDB;
8524 int status;
8525
8526 time_t now = ss_time();
8527
8528 if (endtime == 0)
8529 endtime = now;
8530
8533
8534 //cm_get_experiment_database(&hDB, NULL);
8535
8536 HistPlot hp;
8538
8539 double tstart = ss_millitime();
8540
8541 int flags = READ_HISTORY_LAST_WRITTEN;
8542
8543 status = read_history(hp, /*hDB, group, panel,*/ index, flags, endtime, endtime, 0, hsdata);
8544
8545 if (status != HS_SUCCESS) {
8546 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8547 return status;
8548 }
8549
8550 if (!hsdata->have_last_written) {
8551 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8552 return HS_FILE_ERROR;
8553 }
8554
8555 int count = 0;
8557 time_t tmax = 0;
8558
8559 for (int k=0; k<hsdata->nvars; k++) {
8560 int i = hsdata->odb_index[k];
8561
8562 if (i<0)
8563 continue;
8564 if (index != -1 && index != i)
8565 continue;
8566
8567 time_t lw = hsdata->last_written[k];
8568
8569 if (lw==0) // no last_written for this variable, skip it.
8570 continue;
8571
8572 if (lw > endtime)
8573 lw = endtime; // just in case hs_get_last_written() returns dates in the "future" for this plot
8574
8575 if (lw > tmax)
8576 tmax = lw;
8577
8578 if (lw < tmin)
8579 tmin = lw;
8580
8581 count++;
8582
8583 //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);
8584 }
8585
8586 if (count == 0) // all variables have no last_written
8587 return HS_FILE_ERROR;
8588
8589 if (want_all)
8590 *plastwritten = tmin; // all variables have data
8591 else
8592 *plastwritten = tmax; // at least one variable has data
8593
8594 //printf("tmin %.0f, tmax %.0f, endtime %.0f, last written %.0f\n", (double)tmin, (double)tmax, (double)endtime, (double)*plastwritten);
8595
8596 double tend = ss_millitime();
8597
8598 if (/* DISABLES CODE */ (0))
8599 printf("get_hist_last_written: elapsed time %f ms\n", tend-tstart);
8600
8601 return HS_SUCCESS;
8602}
8603
8604void generate_hist_graph(MVOdb* odb, Return* rr, const char *hgroup, const char *hpanel, char *buffer, int *buffer_size,
8605 int width, int height,
8607 int scale,
8608 int index,
8609 int labels, const char *bgcolor, const char *fgcolor, const char *gridcolor)
8610{
8611 HNDLE hDB;
8612 //KEY key;
8613 gdImagePtr im;
8615 int i, j, k, l;
8616 //int n_vars;
8617 int size, status, r, g, b;
8618 //int x_marker;
8619 int length;
8620 int white, grey, red;
8621 //int black, ltgrey, green, blue;
8622 int fgcol, bgcol, gridcol;
8623 int curve_col[MAX_VARS];
8624 int state_col[3];
8625 char str[256], *p;
8626 //INT var_index[MAX_VARS];
8627 //char event_name[MAX_VARS][NAME_LENGTH];
8628 //char tag_name[MAX_VARS][64];
8629 //char var_name[MAX_VARS][NAME_LENGTH];
8630 //char varname[64];
8631 //char key_name[256];
8632 //float factor[MAX_VARS], offset[MAX_VARS];
8633 //BOOL logaxis, runmarker;
8634 //double xmin, xrange;
8635 double ymin, ymax;
8637 //float minvalue = (float) -HUGE_VAL;
8638 //float maxvalue = (float) +HUGE_VAL;
8639 //int show_values = 0;
8640 //int sort_vars = 0;
8641 //int old_vars = 0;
8643 int flags;
8644
8645 time_t now = ss_time();
8646
8647 if (xendtime == 0)
8648 xendtime = now;
8649
8650 HistPlot hp;
8652
8653 std::vector<int> var_index; var_index.resize(hp.vars.size());
8654
8655 for (size_t i=0; i<hp.vars.size(); i++) {
8656 var_index[i] = 0;
8657 const char *vp = strchr(hp.vars[i].tag_name.c_str(), '[');
8658 if (vp) {
8659 var_index[i] = atoi(vp + 1);
8660 }
8661 }
8662
8663 int logaxis = hp.log_axis;
8664 double minvalue = hp.minimum;
8665 double maxvalue = hp.maximum;
8666
8667 if ((minvalue == 0) && (maxvalue == 0)) {
8668 minvalue = -HUGE_VAL;
8669 maxvalue = +HUGE_VAL;
8670 }
8671
8672 std::vector<int> x[MAX_VARS];
8673 std::vector<double> y[MAX_VARS];
8674
8677
8679
8680 /* generate image */
8681 im = gdImageCreate(width, height);
8682
8683 /* allocate standard colors */
8684 sscanf(bgcolor, "%02x%02x%02x", &r, &g, &b);
8685 bgcol = gdImageColorAllocate(im, r, g, b);
8686 sscanf(fgcolor, "%02x%02x%02x", &r, &g, &b);
8687 fgcol = gdImageColorAllocate(im, r, g, b);
8688 sscanf(gridcolor, "%02x%02x%02x", &r, &g, &b);
8689 gridcol = gdImageColorAllocate(im, r, g, b);
8690
8691 grey = gdImageColorAllocate(im, 192, 192, 192);
8692 //ltgrey = gdImageColorAllocate(im, 208, 208, 208);
8693 white = gdImageColorAllocate(im, 255, 255, 255);
8694 //black = gdImageColorAllocate(im, 0, 0, 0);
8695 red = gdImageColorAllocate(im, 255, 0, 0);
8696 //green = gdImageColorAllocate(im, 0, 255, 0);
8697 //blue = gdImageColorAllocate(im, 0, 0, 255);
8698
8699 curve_col[0] = gdImageColorAllocate(im, 0, 0, 255);
8700 curve_col[1] = gdImageColorAllocate(im, 0, 192, 0);
8701 curve_col[2] = gdImageColorAllocate(im, 255, 0, 0);
8702 curve_col[3] = gdImageColorAllocate(im, 0, 192, 192);
8703 curve_col[4] = gdImageColorAllocate(im, 255, 0, 255);
8704 curve_col[5] = gdImageColorAllocate(im, 192, 192, 0);
8705 curve_col[6] = gdImageColorAllocate(im, 128, 128, 128);
8706 curve_col[7] = gdImageColorAllocate(im, 128, 255, 128);
8707 curve_col[8] = gdImageColorAllocate(im, 255, 128, 128);
8708 curve_col[9] = gdImageColorAllocate(im, 128, 128, 255);
8709 for (i=10; i<MAX_VARS; i++)
8710 curve_col[i] = gdImageColorAllocate(im, 128, 128, 128);
8711
8712 state_col[0] = gdImageColorAllocate(im, 255, 0, 0);
8713 state_col[1] = gdImageColorAllocate(im, 255, 255, 0);
8714 state_col[2] = gdImageColorAllocate(im, 0, 255, 0);
8715
8716 /* Set transparent color. */
8718
8719 /* Title */
8720 gdImageString(im, gdFontGiant, width / 2 - (strlen(hpanel) * gdFontGiant->w) / 2, 2, (char*)hpanel, fgcol);
8721
8722 /* connect to history */
8724 if (mh == NULL) {
8725 sprintf(str, "History is not configured, see messages");
8726 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8727 goto error;
8728 }
8729
8731 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
8732 //db_find_key(hDB, 0, str, &hkeypanel);
8733 //if (!hkeypanel) {
8734 // sprintf(str, "Cannot find /History/Display/%s/%s in ODB", hgroup, hpanel);
8735 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8736 // goto error;
8737 //}
8738
8739 //db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8740 //if (!hkeydvar) {
8741 // sprintf(str, "Cannot find /History/Display/%s/%s/Variables in ODB", hgroup, hpanel);
8742 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8743 // goto error;
8744 //}
8745
8746 //db_get_key(hDB, hkeydvar, &key);
8747 //n_vars = key.num_values;
8748
8749 if (hp.vars.empty()) {
8750 sprintf(str, "No variables in panel %s/%s", hgroup, hpanel);
8751 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8752 goto error;
8753 }
8754
8755 if (hp.vars.size() > MAX_VARS) {
8756 sprintf(str, "Too many variables in panel %s/%s", hgroup, hpanel);
8757 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8758 goto error;
8759 }
8760
8761 ymin = ymax = 0;
8762 //logaxis = runmarker = 0;
8763
8764 for (i = 0; i < (int)hp.vars.size(); i++) {
8765 if (index != -1 && index != i)
8766 continue;
8767
8768 //size = sizeof(str);
8769 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8770 //if (status != DB_SUCCESS) {
8771 // sprintf(str, "Cannot read tag %d in panel %s/%s, status %d", i, hgroup, hpanel, status);
8772 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8773 // goto error;
8774 //}
8775 //
8776 //mstrlcpy(tag_name[i], str, sizeof(tag_name[0]));
8777
8779 //char *tp = strchr(tag_name[i], ':');
8780 //if (tp) {
8781 // mstrlcpy(event_name[i], tag_name[i], sizeof(event_name[0]));
8782 // char *ep = strchr(event_name[i], ':');
8783 // if (ep)
8784 // *ep = 0;
8785 // mstrlcpy(var_name[i], tp+1, sizeof(var_name[0]));
8786 // var_index[i] = 0;
8787 // char *vp = strchr(var_name[i], '[');
8788 // if (vp) {
8789 // var_index[i] = atoi(vp + 1);
8790 // *vp = 0;
8791 // }
8792 //} else {
8793 // sprintf(str, "Tag \"%s\" has wrong format in panel \"%s/%s\"", tag_name[i], hgroup, hpanel);
8794 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8795 // goto error;
8796 //}
8797 //
8798 //db_find_key(hDB, hkeypanel, "Colour", &hkey);
8799 //if (hkey) {
8800 // size = sizeof(str);
8801 // status = db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
8802 // if (status == DB_SUCCESS) {
8803 // if (str[0] == '#') {
8804 // char sss[3];
8805 // int r, g, b;
8806 //
8807 // sss[0] = str[1];
8808 // sss[1] = str[2];
8809 // sss[2] = 0;
8810 // r = strtoul(sss, NULL, 16);
8811 // sss[0] = str[3];
8812 // sss[1] = str[4];
8813 // sss[2] = 0;
8814 // g = strtoul(sss, NULL, 16);
8815 // sss[0] = str[5];
8816 // sss[1] = str[6];
8817 // sss[2] = 0;
8818 // b = strtoul(sss, NULL, 16);
8819 //
8820 // curve_col[i] = gdImageColorAllocate(im, r, g, b);
8821 // }
8822 // }
8823 //}
8824
8825 if (hp.vars[i].colour[0] == '#') {
8826 const char* str = hp.vars[i].colour.c_str();
8827 char sss[3];
8828 int r, g, b;
8829
8830 sss[0] = str[1];
8831 sss[1] = str[2];
8832 sss[2] = 0;
8833 r = strtoul(sss, NULL, 16);
8834 sss[0] = str[3];
8835 sss[1] = str[4];
8836 sss[2] = 0;
8837 g = strtoul(sss, NULL, 16);
8838 sss[0] = str[5];
8839 sss[1] = str[6];
8840 sss[2] = 0;
8841 b = strtoul(sss, NULL, 16);
8842
8843 curve_col[i] = gdImageColorAllocate(im, r, g, b);
8844 }
8845
8846 /* get timescale */
8847 if (scale == 0) {
8848 //std::string ts = "1h";
8849 //status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8850 //if (status != DB_SUCCESS) {
8851 // /* delete old integer key */
8852 // db_find_key(hDB, hkeypanel, "Timescale", &hkey);
8853 // if (hkey)
8854 // db_delete_key(hDB, hkey, FALSE);
8855 //
8856 // ts = "1h";
8857 // status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8858 //}
8859
8860 scale = time_to_sec(hp.timescale.c_str());
8861 }
8862
8863 //for (j = 0; j < MAX_VARS; j++) {
8864 // factor[j] = 1;
8865 // offset[j] = 0;
8866 //}
8867
8869 //size = sizeof(float) * n_vars;
8870 //db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
8871
8873 //size = sizeof(float) * n_vars;
8874 //db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
8875
8877 //size = sizeof(logaxis);
8878 //logaxis = 0;
8879 //db_get_value(hDB, hkeypanel, "Log axis", &logaxis, &size, TID_BOOL, TRUE);
8880
8882 //size = sizeof(show_values);
8883 //show_values = 0;
8884 //db_get_value(hDB, hkeypanel, "Show values", &show_values, &size, TID_BOOL, TRUE);
8885
8887 //size = sizeof(sort_vars);
8888 //sort_vars = 0;
8889 //db_get_value(hDB, hkeypanel, "Sort vars", &sort_vars, &size, TID_BOOL, TRUE);
8890
8892 //size = sizeof(old_vars);
8893 //old_vars = 0;
8894 //db_get_value(hDB, hkeypanel, "Show old vars", &old_vars, &size, TID_BOOL, TRUE);
8895
8897 //size = sizeof(minvalue);
8898 //minvalue = (float) -HUGE_VAL;
8899 //db_get_value(hDB, hkeypanel, "Minimum", &minvalue, &size, TID_FLOAT, TRUE);
8900
8902 //size = sizeof(maxvalue);
8903 //maxvalue = (float) +HUGE_VAL;
8904 //db_get_value(hDB, hkeypanel, "Maximum", &maxvalue, &size, TID_FLOAT, TRUE);
8905
8906 //if ((minvalue == 0) && (maxvalue == 0)) {
8907 // minvalue = (float) -HUGE_VAL;
8908 // maxvalue = (float) +HUGE_VAL;
8909 //}
8910
8912 //size = sizeof(runmarker);
8913 //runmarker = 1;
8914 //db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
8915
8916 /* make ODB path from tag name */
8917 std::string odbpath;
8918 HNDLE hkeyeq = 0;
8920 db_find_key(hDB, 0, "/Equipment", &hkeyroot);
8921 if (hkeyroot) {
8922 for (j = 0;; j++) {
8923 HNDLE hkeyeq;
8925
8926 if (!hkeyeq)
8927 break;
8928
8929 KEY key;
8931 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
8932 /* check if variable is individual key under variables/ */
8933 sprintf(str, "Variables/%s", hp.vars[i].tag_name.c_str());
8934 HNDLE hkey;
8936 if (hkey) {
8937 //sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[i], var_name[i]);
8938 odbpath = "";
8939 odbpath += "/Equipment/";
8940 odbpath += hp.vars[i].event_name;
8941 odbpath += "/Variables/";
8942 odbpath += hp.vars[i].tag_name;
8943 break;
8944 }
8945
8946 /* check if variable is in setttins/names array */
8948 db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
8949 if (hkeynames) {
8950 /* extract variable name and Variables/<key> */
8951 mstrlcpy(str, hp.vars[i].tag_name.c_str(), sizeof(str));
8952 p = str + strlen(str) - 1;
8953 while (p > str && *p != ' ')
8954 p--;
8955 std::string key_name = p + 1;
8956 *p = 0;
8957
8958 std::string varname = str;
8959
8960 /* find key in single name array */
8962 for (k = 0; k < key.num_values; k++) {
8963 size = sizeof(str);
8965 if (equal_ustring(str, varname.c_str())) {
8966 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, k);
8967 odbpath = "";
8968 odbpath += "/Equipment/";
8969 odbpath += hp.vars[i].event_name;
8970 odbpath += "/Variables/";
8971 odbpath += key_name;
8972 odbpath += "[";
8973 odbpath += toString(k);
8974 odbpath += "]";
8975 break;
8976 }
8977 }
8978 } else {
8979 /* go through /variables/<name> entries */
8981 db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
8982 if (hkeyvars) {
8983 for (k = 0;; k++) {
8985
8986 if (!hkey)
8987 break;
8988
8989 /* find "settins/names <key>" for this key */
8990 db_get_key(hDB, hkey, &key);
8991
8992 /* find key in key_name array */
8993 std::string key_name = key.name;
8994
8995 std::string path;
8996 //sprintf(str, "Settings/Names %s", key_name);
8997 path += "Settings/Names ";
8998 path += key_name;
8999
9001 db_find_key(hDB, hkeyeq, path.c_str(), &hkeynames);
9002 if (hkeynames) {
9004 for (l = 0; l < key.num_values; l++) {
9005 size = sizeof(str);
9007 if (equal_ustring(str, hp.vars[i].tag_name.c_str())) {
9008 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, l);
9009 odbpath = "";
9010 odbpath += "/Equipment/";
9011 odbpath += hp.vars[i].event_name;
9012 odbpath += "/Variables/";
9013 odbpath += key_name;
9014 odbpath += "[";
9015 odbpath += toString(l);
9016 odbpath += "]";
9017 break;
9018 }
9019 }
9020 }
9021 }
9022 }
9023 }
9024
9025 break;
9026 }
9027 }
9028
9029 if (!hkeyeq) {
9030 db_find_key(hDB, 0, "/History/Links", &hkeyroot);
9031 if (hkeyroot) {
9032 for (j = 0;; j++) {
9033 HNDLE hkey;
9035
9036 if (!hkey)
9037 break;
9038
9039 KEY key;
9040 db_get_key(hDB, hkey, &key);
9041 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
9043 db_find_key(hDB, hkey, hp.vars[i].tag_name.c_str(), &hkey);
9044 if (hkey) {
9045 db_get_key(hDB, hkey, &key);
9047 if (key.num_values > 1) {
9048 odbpath += "[";
9049 odbpath += toString(var_index[i]);
9050 odbpath += "]";
9051 }
9052 break;
9053 }
9054 }
9055 }
9056 }
9057 }
9058 }
9059
9060 /* search alarm limits */
9061 upper_limit[i] = lower_limit[i] = -12345;
9062 db_find_key(hDB, 0, "Alarms/Alarms", &hkeyroot);
9063 if (odbpath.length() > 0 && hkeyroot) {
9064 for (j = 0;; j++) {
9065 HNDLE hkey;
9067
9068 if (!hkey)
9069 break;
9070
9071 size = sizeof(str);
9072 db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
9073
9074 if (strstr(str, odbpath.c_str())) {
9075 if (strchr(str, '<')) {
9076 p = strchr(str, '<') + 1;
9077 if (*p == '=')
9078 p++;
9079 if (hp.enable_factor) {
9080 lower_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9081 } else {
9082 lower_limit[i] = atof(p);
9083 }
9084 }
9085 if (strchr(str, '>')) {
9086 p = strchr(str, '>') + 1;
9087 if (*p == '=')
9088 p++;
9089 if (hp.enable_factor) {
9090 upper_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9091 } else {
9092 upper_limit[i] = atof(p);
9093 }
9094 }
9095 }
9096 }
9097 }
9098 } // loop over variables
9099
9100 //starttime = now - scale + toffset;
9101 //endtime = now + toffset;
9102
9103 starttime = xendtime - scale;
9104 endtime = xendtime;
9105
9106 //printf("now %d, scale %d, xendtime %d, starttime %d, endtime %d\n", now, scale, xendtime, starttime, endtime);
9107
9108 flags = READ_HISTORY_DATA;
9109 if (hp.show_run_markers)
9110 flags |= READ_HISTORY_RUNMARKER;
9111
9112 status = read_history(hp, /*hDB, hgroup, hpanel,*/ index, flags, starttime, endtime, scale/1000+1, hsdata);
9113
9114 if (status != HS_SUCCESS) {
9115 sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
9116 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
9117 goto error;
9118 }
9119
9121 char var_status[MAX_VARS][256];
9122
9123 for (int k=0; k<hsdata->nvars; k++) {
9124 int i = hsdata->odb_index[k];
9125
9126 if (i<0)
9127 continue;
9128
9129 if (index != -1 && index != i)
9130 continue;
9131
9132 n_point[i] = 0;
9133
9134 var_status[i][0] = 0;
9135 if (hsdata->status[k] == HS_UNDEFINED_VAR) {
9136 sprintf(var_status[i], "not found in history");
9137 continue;
9138 } else if (hsdata->status[k] != HS_SUCCESS) {
9139 sprintf(var_status[i], "hs_read() error %d, see messages", hsdata->status[k]);
9140 continue;
9141 }
9142
9143 int n_vp = 0;
9144 for (int j=0; j<hsdata->num_entries[k]; j++) {
9145 int xx = (int)(hsdata->t[k][j]);
9146 double yy = hsdata->v[k][j];
9147
9148 /* skip NaNs */
9149 if (ss_isnan(yy))
9150 continue;
9151
9152 /* skip INFs */
9153 if (!ss_isfin(yy))
9154 continue;
9155
9156 /* avoid overflow */
9157 if (yy > 1E30)
9158 yy = 1E30f;
9159
9160 /* apply factor and offset */
9161 if (hp.enable_factor) {
9162 yy = hp.vars[i].factor * (yy - hp.vars[i].voffset) + hp.vars[i].offset;
9163 }
9164
9165 /* calculate ymin and ymax */
9166 if ((i == 0 || index != -1) && n_vp == 0)
9167 ymin = ymax = yy;
9168 else {
9169 if (yy > ymax)
9170 ymax = yy;
9171 if (yy < ymin)
9172 ymin = yy;
9173 }
9174
9175 /* increment number of valid points */
9176
9177 x[i].push_back(xx);
9178 y[i].push_back(yy);
9179
9180 n_vp++;
9181
9182 } // loop over data
9183
9184 n_point[i] = n_vp;
9185
9186 assert(x[i].size() == y[i].size());
9187 }
9188
9189 //int flag;
9190 int xmaxm;
9191 int row;
9192 int xold;
9193 int yold;
9194 int aoffset;
9195 double yb1, yb2, yf1, yf2;
9196 int xs, ys;
9197 int x1, x2;
9198 int y1, y2;
9199 int xs_old;
9200 double ybase;
9201
9202 gdPoint poly[3];
9203
9204 if (ymin < minvalue)
9205 ymin = minvalue;
9206
9207 if (ymax > maxvalue)
9208 ymax = maxvalue;
9209
9210 /* check if ylow = 0 */
9211 if (index == -1) {
9212 //flag = 0;
9213 //size = sizeof(flag);
9214 //db_get_value(hDB, hkeypanel, "Zero ylow", &flag, &size, TID_BOOL, TRUE);
9215 if (hp.zero_ylow && ymin > 0)
9216 ymin = 0;
9217 }
9218
9219 /* if min and max too close together, switch to linear axis */
9220 if (logaxis && ymin > 0 && ymax > 0) {
9221 yb1 = pow(10, floor(log(ymin) / LN10));
9222 yf1 = floor(ymin / yb1);
9223 yb2 = pow(10, floor(log(ymax) / LN10));
9224 yf2 = floor(ymax / yb2);
9225
9226 if (yb1 == yb2 && yf1 == yf2)
9227 logaxis = 0;
9228 else {
9229 /* round down and up ymin and ymax */
9230 ybase = pow(10, floor(log(ymin) / LN10));
9231 ymin = (floor(ymin / ybase) * ybase);
9232 ybase = pow(10, floor(log(ymax) / LN10));
9233 ymax = ((floor(ymax / ybase) + 1) * ybase);
9234 }
9235 }
9236
9237 /* avoid negative limits for log axis */
9238 if (logaxis) {
9239 if (ymax <= 0)
9240 ymax = 1;
9241 if (ymin <= 0)
9242 ymin = 1E-12f;
9243 }
9244
9245 /* increase limits by 5% */
9246 if (ymin == 0 && ymax == 0) {
9247 ymin = -1;
9248 ymax = 1;
9249 } else {
9250 if (!logaxis) {
9251 ymax += (ymax - ymin) / 20.f;
9252
9253 if (ymin != 0)
9254 ymin -= (ymax - ymin) / 20.f;
9255 }
9256 }
9257
9258 /* avoid ymin == ymax */
9259 if (ymax == ymin) {
9260 if (logaxis) {
9261 ymax *= 2;
9262 ymin /= 2;
9263 } else {
9264 ymax += 10;
9265 ymin -= 10;
9266 }
9267 }
9268
9269 /* calculate X limits */
9270 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9271 //xmax = (double) (toffset / 3600.0);
9272 //xrange = xmax - xmin;
9273 //xrange = scale/3600.0;
9274
9275 /* caluclate required space for Y-axis */
9276 aoffset = vaxis(im, gdFontSmall, fgcol, gridcol, 0, 0, height, -3, -5, -7, -8, 0, ymin, ymax, logaxis);
9277 aoffset += 2;
9278
9279 x1 = aoffset;
9280 y1 = height - 20;
9281 x2 = width - 20;
9282 y2 = 20;
9283
9285
9286 /* draw axis frame */
9287 taxis(im, gdFontSmall, fgcol, gridcol, x1, y1, x2 - x1, width, 3, 5, 9, 10, 0, (double)starttime, (double)endtime);
9288
9289 vaxis(im, gdFontSmall, fgcol, gridcol, x1, y1, y1 - y2, -3, -5, -7, -8, x2 - x1, ymin, ymax, logaxis);
9290 gdImageLine(im, x1, y2, x2, y2, fgcol);
9291 gdImageLine(im, x2, y2, x2, y1, fgcol);
9292
9293 xs = ys = xold = yold = 0;
9294
9295 /* old code for run markers, new code is below */
9296
9297 /* write run markes if selected */
9298 if (/* DISABLES CODE */ (0) && hp.show_run_markers) {
9299
9300 const char* event_names[] = {
9301 "Run transitions",
9302 "Run transitions",
9303 0 };
9304
9305 const char* tag_names[] = {
9306 "State",
9307 "Run number",
9308 0 };
9309
9310 const int tag_indexes[] = {
9311 0,
9312 0,
9313 0 };
9314
9315 int num_entries[3];
9316 time_t *tbuf[3];
9317 double *dbuf[3];
9318 int st[3];
9319
9320 num_entries[0] = 0;
9321 num_entries[1] = 0;
9322
9323 status = mh->hs_read(starttime - scale, endtime, 0,
9324 2, event_names, tag_names, tag_indexes,
9325 num_entries, tbuf, dbuf, st);
9326
9327 //printf("read run info: status %d, entries %d %d\n", status, num_entries[0], num_entries[1]);
9328
9329 int n_marker = num_entries[0];
9330
9331 if (status == HS_SUCCESS && n_marker > 0 && n_marker < 100) {
9332 xs_old = -1;
9333 xmaxm = x1;
9334 for (j = 0; j < (int) n_marker; j++) {
9335 int col;
9336
9337 // explicit algebra manipulation to clarify computations:
9338
9339 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9340 //xrange = scale/3600.0;
9341 //time_t starttime = now - scale + toffset;
9342
9343 //x_marker = (int)(tbuf[1][j] - now);
9344 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9345 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9346 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9347 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9348 xs = (int) ((tbuf[1][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9349
9350 if (xs < x1)
9351 continue;
9352 if (xs >= x2)
9353 continue;
9354
9355 double run_number = dbuf[1][j];
9356
9357 if (xs <= xs_old)
9358 xs = xs_old + 1;
9359 xs_old = xs;
9360
9361 if (dbuf[0][j] == 1)
9362 col = state_col[0];
9363 else if (dbuf[0][j] == 2)
9364 col = state_col[1];
9365 else if (dbuf[0][j] == 3)
9366 col = state_col[2];
9367 else
9368 col = state_col[0];
9369
9371
9372 sprintf(str, "%.0f", run_number);
9373
9374 if (dbuf[0][j] == STATE_RUNNING) {
9375 if (xs > xmaxm) {
9377 xmaxm = xs - 2 + gdFontSmall->h;
9378 }
9379 } else if (dbuf[0][j] == STATE_STOPPED) {
9380 if (xs + 2 - gdFontSmall->h > xmaxm) {
9382 xmaxm = xs - 1;
9383 }
9384 }
9385 }
9386 }
9387
9388 if (num_entries[0]) {
9389 free(tbuf[0]);
9390 free(dbuf[0]);
9391 tbuf[0] = NULL;
9392 dbuf[0] = NULL;
9393 }
9394
9395 if (num_entries[1]) {
9396 free(tbuf[1]);
9397 free(dbuf[1]);
9398 tbuf[1] = NULL;
9399 dbuf[1] = NULL;
9400 }
9401 }
9402
9403 /* write run markes if selected */
9404 if (hp.show_run_markers) {
9405
9406 int index_state = -1;
9407 int index_run_number = -1;
9408
9409 for (int k=0; k<hsdata->nvars; k++) {
9410 if (hsdata->odb_index[k] == -1)
9411 index_state = k;
9412
9413 if (hsdata->odb_index[k] == -2)
9415 }
9416
9417 bool ok = true;
9418
9419 if (ok)
9420 ok = (index_state >= 0) && (index_run_number >= 0);
9421
9422 if (ok)
9423 ok = (hsdata->status[index_state] == HS_SUCCESS);
9424
9425 if (ok)
9426 ok = (hsdata->status[index_run_number] == HS_SUCCESS);
9427
9428 if (/* DISABLES CODE */ (0) && ok)
9429 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]);
9430
9431 if (ok)
9432 ok = (hsdata->num_entries[index_state] == hsdata->num_entries[index_run_number]);
9433
9434 int n_marker = hsdata->num_entries[index_state];
9435
9436 if (ok && n_marker > 0 && n_marker < 100) {
9437 xs_old = -1;
9438 xmaxm = x1;
9439 for (j = 0; j < (int) n_marker; j++) {
9440 int col;
9441
9442 // explicit algebra manipulation to clarify computations:
9443
9444 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9445 //xrange = scale/3600.0;
9446 //time_t starttime = now - scale + toffset;
9447
9448 //x_marker = (int)(tbuf[1][j] - now);
9449 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9450 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9451 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9452 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9453 xs = (int) ((hsdata->t[index_state][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9454
9455 if (xs < x1)
9456 continue;
9457 if (xs >= x2)
9458 continue;
9459
9460 double run_number = hsdata->v[index_run_number][j];
9461
9462 if (xs <= xs_old)
9463 xs = xs_old + 1;
9464 xs_old = xs;
9465
9466 int state = (int)hsdata->v[index_state][j];
9467
9468 if (state == 1)
9469 col = state_col[0];
9470 else if (state == 2)
9471 col = state_col[1];
9472 else if (state == 3)
9473 col = state_col[2];
9474 else
9475 col = state_col[0];
9476
9478
9479 sprintf(str, "%.0f", run_number);
9480
9481 if (state == STATE_RUNNING) {
9482 if (xs > xmaxm) {
9484 xmaxm = xs - 2 + gdFontSmall->h;
9485 }
9486 } else if (state == STATE_STOPPED) {
9487 if (xs + 2 - gdFontSmall->h > xmaxm) {
9489 xmaxm = xs - 1;
9490 }
9491 }
9492 }
9493 }
9494 }
9495
9496 for (i = 0; i < (int)hp.vars.size(); i++) {
9497 if (index != -1 && index != i)
9498 continue;
9499
9500 /* draw alarm limits */
9501 if (lower_limit[i] != -12345) {
9502 if (logaxis) {
9503 if (lower_limit[i] <= 0)
9504 ys = y1;
9505 else
9506 ys = (int) (y1 - (log(lower_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9507 } else {
9508 ys = (int) (y1 - (lower_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9509 }
9510
9511 if (xs < 0)
9512 xs = 0;
9513 if (xs >= width)
9514 xs = width-1;
9515 if (ys < 0)
9516 ys = 0;
9517 if (ys >= height)
9518 ys = height-1;
9519
9520 if (ys > y2 && ys < y1) {
9522
9523 poly[0].x = x1;
9524 poly[0].y = ys;
9525 poly[1].x = x1 + 5;
9526 poly[1].y = ys;
9527 poly[2].x = x1;
9528 poly[2].y = ys - 5;
9529
9531 }
9532 }
9533 if (upper_limit[i] != -12345) {
9534 if (logaxis) {
9535 if (upper_limit[i] <= 0)
9536 ys = y1;
9537 else
9538 ys = (int) (y1 - (log(upper_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9539 } else {
9540 ys = (int) (y1 - (upper_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9541 }
9542
9543 if (xs < 0)
9544 xs = 0;
9545 if (xs >= width)
9546 xs = width-1;
9547 if (ys < 0)
9548 ys = 0;
9549 if (ys >= height)
9550 ys = height-1;
9551
9552 if (ys > y2 && ys < y1) {
9554
9555 poly[0].x = x1;
9556 poly[0].y = ys;
9557 poly[1].x = x1 + 5;
9558 poly[1].y = ys;
9559 poly[2].x = x1;
9560 poly[2].y = ys + 5;
9561
9563 }
9564 }
9565
9566 for (j = 0; j < (int) n_point[i]; j++) {
9567 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9568 //xrange = scale/3600.0;
9569 //xs = (int) (((x[i][j]-now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9570 //xs = (int) (((x[i][j] - now + scale - toffset) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9571 //xs = (int) (((x[i][j] - starttime) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9572 xs = (int) (((x[i][j] - starttime)/1.0) / (1.0*scale) * (x2 - x1) + x1 + 0.5);
9573
9574 if (logaxis) {
9575 if (y[i][j] <= 0)
9576 ys = y1;
9577 else
9578 ys = (int) (y1 - (log(y[i][j]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9579 } else {
9580 ys = (int) (y1 - (y[i][j] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9581 }
9582
9583 if (xs < 0)
9584 xs = 0;
9585 if (xs >= width)
9586 xs = width-1;
9587 if (ys < 0)
9588 ys = 0;
9589 if (ys >= height)
9590 ys = height-1;
9591
9592 if (j > 0)
9594 xold = xs;
9595 yold = ys;
9596 }
9597
9598 if (n_point[i] > 0) {
9599 poly[0].x = xs;
9600 poly[0].y = ys;
9601 poly[1].x = xs + 12;
9602 poly[1].y = ys - 6;
9603 poly[2].x = xs + 12;
9604 poly[2].y = ys + 6;
9605
9607 }
9608 }
9609
9610 if (labels) {
9611 for (i = 0; i < (int)hp.vars.size(); i++) {
9612 if (index != -1 && index != i)
9613 continue;
9614
9615 //str[0] = 0;
9616 //status = db_find_key(hDB, hkeypanel, "Label", &hkeydvar);
9617 //if (status == DB_SUCCESS) {
9618 // size = sizeof(str);
9619 // status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
9620 //}
9621
9622 std::string str = hp.vars[i].label.c_str();
9623
9624 if (str.empty()) {
9625 if (hp.enable_factor) {
9626 str = hp.vars[i].tag_name;
9627
9628 if (hp.vars[i].voffset > 0)
9629 str += msprintf(" - %G", hp.vars[i].voffset);
9630 else if (hp.vars[i].voffset < 0)
9631 str += msprintf(" + %G", -hp.vars[i].voffset);
9632
9633 if (hp.vars[i].factor != 1) {
9634 if (hp.vars[i].voffset == 0)
9635 str += msprintf(" * %+G", hp.vars[i].factor);
9636 else {
9637 str = msprintf("(%s) * %+G", str.c_str(), hp.vars[i].factor);
9638 }
9639 }
9640
9641 if (hp.vars[i].offset > 0)
9642 str += msprintf(" + %G", hp.vars[i].offset);
9643 else if (hp.vars[i].offset < 0)
9644 str += msprintf(" - %G", -hp.vars[i].offset);
9645
9646 } else {
9647 str = hp.vars[i].tag_name;
9648 }
9649 }
9650
9651 int k=0;
9652 for (int j=0; j<hsdata->nvars; j++)
9653 if (hsdata->odb_index[j] == i) {
9654 k = j;
9655 break;
9656 }
9657
9658 if (/* DISABLES CODE */ (0)) {
9659 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]);
9660 }
9661
9662 if (hp.show_values) {
9663 char xstr[256];
9664 if (n_point[i] > 0) {
9665 sprintf(xstr," = %g", y[i][n_point[i]-1]);
9666 } else if (hsdata->num_entries[k] > 0) {
9667 sprintf(xstr," = all data is NaN or INF");
9668 } else if (hsdata->have_last_written) {
9669 if (hsdata->last_written[k]) {
9670 char ctimebuf[32];
9671 ctime_r(&hsdata->last_written[k], ctimebuf);
9672 sprintf(xstr," = last data %s", ctimebuf);
9673 // kill trailing '\n'
9674 char*s = strchr(xstr, '\n');
9675 if (s) *s=0;
9676 // clear the unnecessary error status report
9677 if (hsdata->status[k] == HS_UNDEFINED_VAR)
9678 var_status[i][0] = 0;
9679 } else {
9680 sprintf(xstr," = no data ever");
9681 }
9682 } else {
9683 sprintf(xstr," = no data");
9684 }
9685 str += xstr;
9686 }
9687
9688 if (strlen(var_status[i]) > 1) {
9689 str += msprintf(" (%s)", var_status[i]);
9690 }
9691
9692 row = index == -1 ? i : 0;
9693
9695 x1 + 10,
9696 y2 + 10 + row * (gdFontMediumBold->h + 10),
9697 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9698 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9699 gdFontMediumBold->h + 2 + 2, white);
9700 gdImageRectangle(im, x1 + 10, y2 + 10 + row * (gdFontMediumBold->h + 10),
9701 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9702 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9703 gdFontMediumBold->h + 2 + 2, curve_col[i]);
9704
9706 x1 + 10 + 5, y2 + 10 + 2 + row * (gdFontMediumBold->h + 10),
9707 (char*)str.c_str(),
9708 curve_col[i]);
9709 }
9710 }
9711
9713
9714 error:
9715
9716 /* generate GIF */
9717 gdImageInterlace(im, 1);
9718 gdImageGif(im, &gb);
9720 length = gb.size;
9721
9722 if (buffer == NULL) {
9723 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
9724 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
9725
9726 rr->rsprintf("Content-Type: image/gif\r\n");
9727 rr->rsprintf("Content-Length: %d\r\n", length);
9728 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
9729 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
9730
9731 rr->rmemcpy(gb.data, length);
9732 } else {
9733 if (length > *buffer_size) {
9734 printf("return buffer too small\n");
9735 return;
9736 }
9737
9738 memcpy(buffer, gb.data, length);
9739 *buffer_size = length;
9740 }
9741}
9742
9743/*------------------------------------------------------------------*/
9744
9746{
9747 // this silly stuff is required to correctly handle daylight savings time (Summer time/Winter time)
9748 // when we fill "struct tm" from user input, we cannot know if daylight savings time is in effect
9749 // and we do not know how to initialize the value of tms.tm_isdst.
9750 // This can cause the output of mktime() to be off by one hour.
9751 // (Rules for daylight savings time are set by national and local govt and in some locations, changes yearly)
9752 // (There are no locations with 2 hour or half-hour daylight savings that I know of)
9753 // (Yes, "man mktime" talks about using "tms.tm_isdst = -1")
9754 //
9755 // We assume the user is using local time and we convert in two steps:
9756 //
9757 // first we convert "struct tm" to "time_t" using mktime() with unknown tm_isdst
9758 // second we convert "time_t" back to "struct tm" using localtime_r()
9759 // this fills "tm_isdst" with correct value from the system time zone database
9760 // then we reset all the time fields (except for sub-minute fields not affected by daylight savings)
9761 // and call mktime() again, now with the correct value of "tm_isdst".
9762 // K.O. 2013-09-14
9763
9764 struct tm tms = *ptms;
9765 struct tm tms2;
9766 time_t t1 = ss_mktime(&tms);
9767 localtime_r(&t1, &tms2);
9768 tms2.tm_year = ptms->tm_year;
9769 tms2.tm_mon = ptms->tm_mon;
9770 tms2.tm_mday = ptms->tm_mday;
9771 tms2.tm_hour = ptms->tm_hour;
9772 tms2.tm_min = ptms->tm_min;
9773 time_t t2 = ss_mktime(&tms2);
9774 //printf("t1 %.0f, t2 %.0f, diff %d\n", (double)t1, (double)t2, (int)(t1-t2));
9775 return t2;
9776}
9777
9778/*------------------------------------------------------------------*/
9779
9780static std::string add_param_to_url(const char* name, const char* value)
9781{
9782 std::string s;
9783 s += name; // FIXME: should be URI-encoded
9784 s += "=";
9785 s += value; // FIXME: should be URI-encoded
9786 return s;
9787}
9788
9789/*------------------------------------------------------------------*/
9790
9792{
9793 int i;
9794 HNDLE hDB;
9795
9796 if (p->getparam("m1") && *p->getparam("m1")) {
9797 struct tm tms;
9798 memset(&tms, 0, sizeof(struct tm));
9799
9800 tms.tm_year = atoi(p->getparam("y1")) % 100;
9801
9802 std::string m1 = p->getparam("m1");
9803 for (i = 0; i < 12; i++)
9804 if (equal_ustring(m1.c_str(), mname[i]))
9805 break;
9806 if (i == 12)
9807 i = 0;
9808
9809 tms.tm_mon = i;
9810 tms.tm_mday = atoi(p->getparam("d1"));
9811 tms.tm_hour = atoi(p->getparam("h1"));
9812
9813 if (tms.tm_year < 90)
9814 tms.tm_year += 100;
9815
9817
9818 memset(&tms, 0, sizeof(struct tm));
9819 tms.tm_year = atoi(p->getparam("y2")) % 100;
9820
9821 std::string m2 = p->getparam("m2");
9822 for (i = 0; i < 12; i++)
9823 if (equal_ustring(m2.c_str(), mname[i]))
9824 break;
9825 if (i == 12)
9826 i = 0;
9827
9828 tms.tm_mon = i;
9829 tms.tm_mday = atoi(p->getparam("d2"));
9830 tms.tm_hour = atoi(p->getparam("h2"));
9831
9832 if (tms.tm_year < 90)
9833 tms.tm_year += 100;
9834
9836
9837 if (ltime_end == ltime_start)
9838 ltime_end += 3600 * 24;
9839
9840 std::string redir;
9841 redir += "?cmd=oldhistory&";
9842 redir += add_param_to_url("group", p->getparam("group"));
9843 redir += "&";
9844 redir += add_param_to_url("panel", p->getparam("panel"));
9845 redir += "&";
9846 redir += add_param_to_url("scale", toString((int)(ltime_end - ltime_start)).c_str());
9847 redir += "&";
9849 if (p->isparam("hindex")) {
9850 redir += "&";
9851 redir += add_param_to_url("index", p->getparam("hindex"));
9852 }
9853 redirect(r, redir.c_str());
9854 return;
9855 }
9856
9858 show_header(r, "History", "GET", "", 0);
9859
9860 /* set the times */
9861
9862 time_t now = time(NULL);
9863
9864 time_t starttime = now - 3600 * 24;
9865 time_t endtime = now;
9866 bool full_day = true;
9867
9868 if (p->isparam("htime")) {
9869 endtime = string_to_time(p->getparam("htime"));
9870
9871 if (p->isparam("hscale")) {
9872 starttime = endtime - atoi(p->getparam("hscale"));
9873 full_day = false;
9874 } else {
9875 starttime = endtime - 3600 * 24;
9876 full_day = false;
9877 }
9878 }
9879
9880 /* menu buttons */
9881 r->rsprintf("<tr><td colspan=2>\n");
9882 r->rsprintf("<input type=hidden name=cmd value=OldHistory>\n");
9883 r->rsprintf("<input type=submit name=hcmd value=Query>\n");
9884 r->rsprintf("<input type=submit name=hcmd value=Cancel>\n");
9885 if (p->isparam("group"))
9886 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", p->getparam("group"));
9887 if (p->isparam("panel"))
9888 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", p->getparam("panel"));
9889 if (p->isparam("htime"))
9890 r->rsprintf("<input type=hidden name=htime value=\"%s\">\n", p->getparam("htime"));
9891 if (p->isparam("hscale"))
9892 r->rsprintf("<input type=hidden name=hscale value=\"%s\">\n", p->getparam("hscale"));
9893 if (p->isparam("hindex"))
9894 r->rsprintf("<input type=hidden name=hindex value=\"%s\">\n", p->getparam("hindex"));
9895 r->rsprintf("</tr>\n\n");
9896 r->rsprintf("</table>"); //end header
9897
9898 r->rsprintf("<table class=\"dialogTable\">"); //main table
9899
9900 struct tm tms;
9902 tms.tm_year += 1900;
9903
9904 r->rsprintf("<tr><td nowrap>Start date:</td>");
9905
9906 r->rsprintf("<td>Month: <select name=\"m1\">\n");
9907 r->rsprintf("<option value=\"\">\n");
9908 for (i = 0; i < 12; i++)
9909 if (i == tms.tm_mon)
9910 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9911 else
9912 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9913 r->rsprintf("</select>\n");
9914
9915 r->rsprintf("&nbsp;Day: <select name=\"d1\">");
9916 r->rsprintf("<option selected value=\"\">\n");
9917 for (i = 0; i < 31; i++)
9918 if (i + 1 == tms.tm_mday)
9919 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9920 else
9921 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9922 r->rsprintf("</select>\n");
9923
9924 int start_hour = tms.tm_hour;
9925 if (full_day)
9926 start_hour = 0;
9927
9928 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h1\" value=\"%d\">", start_hour);
9929
9930 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">", tms.tm_year);
9931 r->rsprintf("</td></tr>\n");
9932
9933 r->rsprintf("<tr><td nowrap>End date:</td>");
9934
9936 tms.tm_year += 1900;
9937
9938 r->rsprintf("<td>Month: <select name=\"m2\">\n");
9939 r->rsprintf("<option value=\"\">\n");
9940 for (i = 0; i < 12; i++)
9941 if (i == tms.tm_mon)
9942 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9943 else
9944 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9945 r->rsprintf("</select>\n");
9946
9947 r->rsprintf("&nbsp;Day: <select name=\"d2\">");
9948 r->rsprintf("<option selected value=\"\">\n");
9949 for (i = 0; i < 31; i++)
9950 if (i + 1 == tms.tm_mday)
9951 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9952 else
9953 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9954 r->rsprintf("</select>\n");
9955
9956 int end_hour = tms.tm_hour;
9957 if (full_day)
9958 end_hour = 24;
9959
9960 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h2\" value=\"%d\">", end_hour);
9961
9962 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y2\" value=\"%d\">", tms.tm_year);
9963 r->rsprintf("</td></tr>\n");
9964
9965 r->rsprintf("</table>\n");
9966 r->rsprintf("</div>\n"); // closing for <div id="mmain">
9967 r->rsprintf("</form>\n");
9968 r->rsprintf("</body></html>\r\n");
9969}
9970
9971/*------------------------------------------------------------------*/
9972/* history plot code starts here */
9973/*------------------------------------------------------------------*/
9974
9975static int cmp_names(const void *a, const void *b)
9976{
9977 int i;
9978 const char*sa = (const char*)a;
9979 const char*sb = (const char*)b;
9980
9981 int debug = 0;
9982
9983 // Cannot use strcmp() because it does not know how to compare numerical values, e.g.
9984 // it thinks "111" is smaller than "9"
9985 //return strcmp(sa, sb);
9986
9987 if (debug)
9988 printf("compare [%s] and [%s]\n", sa, sb);
9989
9990 for (i=0; ; i++) {
9991 if (sa[i]==0 && sb[i]==0)
9992 return 0; // both strings have the same length and the same characters
9993
9994 //printf("index %d, char [%c] [%c], isdigit %d %d\n", i, sa[i], sb[i], isdigit(sa[i]), isdigit(sb[i]));
9995
9996 if (isdigit(sa[i]) && isdigit(sb[i])) {
9997 int va = atoi(sa+i);
9998 int vb = atoi(sb+i);
9999
10000 if (debug)
10001 printf("index %d, values %d %d\n", i, va, vb);
10002
10003 if (va < vb)
10004 return -1;
10005 else if (va > vb)
10006 return 1;
10007
10008 // values are equal, skip the the end of the digits, compare any trailing text
10009 continue;
10010 }
10011
10012 if (sa[i]==sb[i]) {
10013 continue;
10014 }
10015
10016 if (debug)
10017 printf("index %d, char [%c] [%c]\n", i, sa[i], sb[i]);
10018
10019 if (sa[i] == 0) // string sa is shorter
10020 return -1;
10021 else if (sb[i] == 0) // string sb is shorter
10022 return 1;
10023
10024 if (sa[i]<sb[i])
10025 return -1;
10026 else
10027 return 1;
10028 }
10029
10030 // NOT REACHED
10031}
10032
10033const bool cmp_events(const std::string& a, const std::string& b)
10034{
10035 return cmp_names(a.c_str(), b.c_str()) < 0;
10036}
10037
10038const bool cmp_events1(const std::string& a, const std::string& b)
10039{
10040 return a < b;
10041}
10042
10043const bool cmp_tags(const TAG& a, const TAG& b)
10044{
10045 return cmp_names(a.name, b.name) < 0;
10046}
10047
10048#if 0
10049static int cmp_tags(const void *a, const void *b)
10050{
10051 const TAG*sa = (const TAG*)a;
10052 const TAG*sb = (const TAG*)b;
10053 return cmp_names(sa->name, sb->name);
10054}
10055
10056static void sort_tags(int ntags, TAG* tags)
10057{
10058 qsort(tags, ntags, sizeof(TAG), cmp_tags);
10059}
10060#endif
10061
10062int xdb_get_data_index(HNDLE hDB, const char* str, void *value, int size, int index, int tid)
10063{
10064 HNDLE hKey;
10065 int status = db_find_key(hDB, 0, str, &hKey);
10066 if (status != DB_SUCCESS)
10067 return status;
10068
10069 KEY key;
10070 db_get_key(hDB, hKey, &key);
10071 if (index >= key.num_values)
10072 return DB_OUT_OF_RANGE;
10073
10074 status = db_get_data_index(hDB, hKey, value, &size, index, tid);
10075 return status;
10076}
10077
10078static int xdb_find_key(HNDLE hDB, HNDLE dir, const char* str, HNDLE* hKey, int tid, int size)
10079{
10080 int status = db_find_key(hDB, dir, str, hKey);
10081 if (status == DB_SUCCESS)
10082 return status;
10083
10084 db_create_key(hDB, dir, str, tid);
10085 status = db_find_key(hDB, dir, str, hKey);
10086 if (status != DB_SUCCESS || !*hKey) {
10087 cm_msg(MERROR, "xdb_find_key", "Invalid ODB path \"%s\"", str);
10088 str = "bad_xdb_find_key";
10089 db_create_key(hDB, dir, str, tid);
10090 db_find_key(hDB, dir, str, hKey);
10091 }
10092 assert(*hKey);
10093
10094 if (tid == TID_STRING) {
10095 db_set_data_index(hDB, *hKey, "", size, 0, TID_STRING);
10096 }
10097
10098 return status;
10099}
10100
10101static bool cmp_vars(const HistVar &a, const HistVar &b)
10102{
10103 return a.order < b.order;
10104}
10105
10106static void PrintHistPlot(const HistPlot& hp)
10107{
10108 printf("hist plot: %d variables\n", (int)hp.vars.size());
10109 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);
10110
10111 for (size_t i=0; i<hp.vars.size(); i++) {
10112 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);
10113 }
10114}
10115
10116static std::string NextHistPlotColour(const HistPlot& hp)
10117{
10118 const char* const colour[] =
10119 {
10120 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
10121 "#A0C0D0", "#D0A060", "#C04010", "#807060",
10122 "#F0C000", "#2090A0", "#D040D0", "#90B000",
10123 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
10124 NULL };
10125
10126 for (int i=0; colour[i]; i++) {
10127 bool in_use = false;
10128
10129 for (size_t j=0; j<hp.vars.size(); j++)
10130 if (hp.vars[j].colour == colour[i]) {
10131 in_use = true;
10132 break;
10133 }
10134
10135 if (!in_use)
10136 return colour[i];
10137 }
10138
10139 return "#808080";
10140}
10141
10143{
10144 int order = 0;
10145 for (size_t i=0; i<hp.vars.size(); i++)
10146 if (hp.vars[i].order > order)
10147 order = hp.vars[i].order;
10148 return order + 10;
10149}
10150
10151static void SplitEventAndTagNames(std::string var_name, std::string& event_name, std::string& tag_name) {
10152 event_name = "";
10153 tag_name = "";
10154
10155 std::vector<size_t> colons;
10156
10157 for (size_t i = 0; i < var_name.size(); i++) {
10158 if (var_name[i] == ':') {
10159 colons.push_back(i);
10160 }
10161 }
10162
10163 if (colons.size() == 0) {
10164 // No colons - leave the tag name empty
10165 event_name = var_name;
10166 } else {
10167 size_t split_pos;
10168 size_t slash_pos = var_name.find("/");
10169 bool uses_per_variable_naming = (slash_pos != std::string::npos);
10170
10171 if (uses_per_variable_naming && colons.size() % 2 == 1) {
10172 size_t middle_colon_pos = colons[colons.size() / 2];
10173 std::string slash_to_mid = var_name.substr(slash_pos + 1, middle_colon_pos - slash_pos - 1);
10174 std::string mid_to_end = var_name.substr(middle_colon_pos + 1);
10175
10176 if (slash_to_mid == mid_to_end) {
10177 // Special case - we have a string of the form Beamlime/GS2:FC1:GS2:FC1.
10178 // Logger has already warned people that having colons in the equipment/event
10179 // names is a bad idea, so we only need to worry about them in the tag name.
10181 } else {
10182 // We have a string of the form Beamlime/Demand:GS2:FC1. Split at the first colon.
10183 split_pos = colons[0];
10184 }
10185 } else {
10186 // Normal case - split at the fist colon.
10187 split_pos = colons[0];
10188 }
10189
10190 event_name = var_name.substr(0, split_pos);
10191 tag_name = var_name.substr(split_pos + 1);
10192 }
10193}
10194
10195static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel)
10196{
10197 std::string path = "History/Display/";
10198 path += group;
10199 path += "/";
10200 path += panel;
10201
10202 MVOdb* o = odb->Chdir(path.c_str());
10203 if (!o) {
10204 return;
10205 }
10206
10207 o->RS("Timescale", &hp->timescale);
10208 o->RD("Minimum", &hp->minimum);
10209 o->RD("Maximum", &hp->maximum);
10210 o->RB("Zero ylow", &hp->zero_ylow);
10211 o->RB("Log axis", &hp->log_axis);
10212 o->RB("Zero ylow", &hp->zero_ylow);
10213 o->RB("Show run markers", &hp->show_run_markers);
10214 o->RB("Show values", &hp->show_values);
10215 o->RB("Show fill", &hp->show_fill);
10216 o->RB("Show factor", &hp->show_factor);
10217 //o->RB("Enable factor and offset", &hp->enable_factor);
10218
10219 std::vector<std::string> hist_vars;
10220 std::vector<std::string> hist_formula;
10221 std::vector<std::string> hist_colour;
10222 std::vector<std::string> hist_label;
10223 std::vector<bool> hist_show_raw_value;
10224 std::vector<double> hist_factor;
10225 std::vector<double> hist_offset;
10226 std::vector<double> hist_voffset;
10227
10228 o->RSA("Variables", &hist_vars);
10229 o->RSA("Formula", &hist_formula);
10230 o->RSA("Colour", &hist_colour);
10231 o->RSA("Label", &hist_label);
10232 o->RBA("Show raw value", &hist_show_raw_value);
10233 o->RDA("Factor", &hist_factor);
10234 o->RDA("Offset", &hist_offset);
10235 o->RDA("VOffset", &hist_voffset);
10236
10237 // fix broken plots with "factor" all zero. for reasons
10238 // unknown the new history code has corrupted many
10239 // history plot definitions like this. K.O.
10240 {
10241 bool all_zero = true;
10242 for (size_t i=0; i<hist_factor.size(); i++) {
10243 if (hist_factor[i] != 0)
10244 all_zero = false;
10245 }
10246 if (all_zero) {
10247 for (size_t i=0; i<hist_factor.size(); i++) {
10248 hist_factor[i] = 1.0;
10249 }
10250 }
10251 }
10252
10253 size_t num = std::max(hist_vars.size(), hist_formula.size());
10254 num = std::max(num, hist_colour.size());
10255 num = std::max(num, hist_label.size());
10256 num = std::max(num, hist_show_raw_value.size());
10257 num = std::max(num, hist_factor.size());
10258 num = std::max(num, hist_offset.size());
10259 num = std::max(num, hist_voffset.size());
10260
10261 hist_vars.resize(num);
10262 hist_formula.resize(num);
10263 hist_colour.resize(num);
10264 hist_label.resize(num);
10265 hist_show_raw_value.resize(num);
10266 hist_factor.resize(num, 1.0);
10267 hist_offset.resize(num, 0.0);
10268 hist_voffset.resize(num, 0.0);
10269
10270 for (size_t i=0; i<num; i++) {
10271 HistVar v;
10272
10274
10275 v.formula = hist_formula[i];
10276 v.colour = hist_colour[i];
10277 v.label = hist_label[i];
10279 v.factor = hist_factor[i];
10280 v.offset = hist_offset[i];
10281 v.voffset = hist_voffset[i];
10283
10284 // one-time migration of factor and offset to formula
10285 if (hp->enable_factor && v.formula.empty()) {
10286 if (v.factor!=1 || v.offset!=0 || v.voffset!=0) {
10287 v.formula = msprintf("%g%+g*(x%+g)", v.offset, v.factor, -v.voffset);
10288 }
10289 }
10290
10291 hp->vars.push_back(v);
10292 }
10293
10294// printf("Load from ODB %s: ", path.c_str());
10295// PrintHistPlot(*hp);
10296
10297 delete o;
10298}
10299
10301{
10302 hp->timescale = p->getparam("timescale");
10303 hp->minimum = strtod(p->getparam("minimum"), NULL);
10304 hp->maximum = strtod(p->getparam("maximum"), NULL);
10305 hp->zero_ylow = *p->getparam("zero_ylow");
10306 hp->log_axis = *p->getparam("log_axis");
10307 hp->show_run_markers = *p->getparam("run_markers");
10308 hp->show_values = *p->getparam("show_values");
10309 hp->show_fill = *p->getparam("show_fill");
10310 hp->show_factor = *p->getparam("show_factor");
10311 //hp->enable_factor = *p->getparam("enable_factor");
10312
10313 for (int index=0; ; index++) {
10314 char str[256];
10315 sprintf(str, "event%d", index);
10316
10317 //printf("param event %d: [%s] [%s] [%d]\n", index, str, p->getparam(str), *p->getparam(str));
10318
10319 if (!p->isparam(str))
10320 break;
10321
10322 if (*p->getparam(str) == '/') // "/empty"
10323 continue;
10324
10325 HistVar v;
10326
10327 v.event_name = p->xgetparam(str);
10328
10329 sprintf(str, "var%d", index);
10330 v.tag_name = p->xgetparam(str);
10331
10332 sprintf(str, "form%d", index);
10333 v.formula = p->xgetparam(str);
10334
10335 sprintf(str, "col%d", index);
10336 v.colour = p->xgetparam(str);
10337
10338 sprintf(str, "lab%d", index);
10339 v.label = p->xgetparam(str);
10340
10341 sprintf(str, "raw%d", index);
10342 v.show_raw_value = atoi(p->xgetparam(str).c_str());
10343
10344 sprintf(str, "factor%d", index);
10345 if (p->isparam(str)) {
10346 v.factor = atof(p->xgetparam(str).c_str());
10347 } else {
10348 v.factor = 1.0;
10349 }
10350
10351 sprintf(str, "offset%d", index);
10352 v.offset = atof(p->xgetparam(str).c_str());
10353
10354 sprintf(str, "voffset%d", index);
10355 v.voffset = atof(p->xgetparam(str).c_str());
10356
10357 sprintf(str, "ord%d", index);
10358 if (p->isparam(str)) {
10359 v.order = atoi(p->xgetparam(str).c_str());
10360 } else {
10362 }
10363
10364 hp->vars.push_back(v);
10365 }
10366
10367 /* correctly number newly added variables */
10368 for (size_t index=0; index<hp->vars.size(); index++) {
10369 if (hp->vars[index].order < 0)
10370 hp->vars[index].order = NextHistPlotOrder(*hp);
10371 }
10372
10373// printf("Load from param:\n");
10374// PrintHistPlot(*hp);
10375}
10376
10378{
10379 int seln = atoi(p->getparam("seln"));
10380 for (int i=0; i<seln; i++) {
10381 char str[256];
10382 sprintf(str, "sel%d", i);
10383
10384 std::string par = p->getparam(str);
10385 if (par.length() < 1)
10386 continue;
10387
10388 std::string event_name, tag_name;
10389 SplitEventAndTagNames(par, event_name, tag_name);
10390
10391 if (tag_name == "")
10392 continue;
10393
10394 HistVar v;
10395
10396 v.event_name = event_name;
10397 v.tag_name = tag_name;
10400
10401 hp.vars.push_back(v);
10402 }
10403}
10404
10405static void SaveHistPlotToOdb(MVOdb* odb, const HistPlot& hp, const char* group, const char* panel)
10406{
10407 if (strlen(group) < 1) {
10408 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid group name", group, panel);
10409 return;
10410 }
10411
10412 if (strlen(panel) < 1) {
10413 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid panel name", group, panel);
10414 return;
10415 }
10416
10417 std::string path = "History/Display/";
10418 path += group;
10419 path += "/";
10420 path += panel;
10421
10422// printf("Save to ODB %s: ", path.c_str());
10423// PrintHistPlot(hp);
10424
10425 MVOdb* o = odb->Chdir(path.c_str(), true);
10426
10427 o->WS("Timescale", hp.timescale.c_str());
10428 o->WD("Minimum", hp.minimum);
10429 o->WD("Maximum", hp.maximum);
10430 o->WB("Zero ylow", hp.zero_ylow);
10431 o->WB("Log axis", hp.log_axis);
10432 o->WB("Show run markers", hp.show_run_markers);
10433 o->WB("Show values", hp.show_values);
10434 o->WB("Show fill", hp.show_fill);
10435 o->WB("Show factor and offset", hp.show_factor);
10436 //o->WB("Enable factor and offset", hp.enable_factor);
10437
10438 std::vector<std::string> hist_vars;
10439 std::vector<std::string> hist_formula;
10440 std::vector<std::string> hist_colour;
10441 std::vector<std::string> hist_label;
10442 std::vector<bool> hist_show_raw_value;
10443 std::vector<double> hist_factor;
10444 std::vector<double> hist_offset;
10445 std::vector<double> hist_voffset;
10446
10447 for (size_t i=0; i<hp.vars.size(); i++) {
10448 hist_vars.push_back(hp.vars[i].event_name + ":" + hp.vars[i].tag_name);
10449 hist_formula.push_back(hp.vars[i].formula);
10450 hist_colour.push_back(hp.vars[i].colour);
10451 hist_label.push_back(hp.vars[i].label);
10452 hist_show_raw_value.push_back(hp.vars[i].show_raw_value);
10453 hist_factor.push_back(hp.vars[i].factor);
10454 hist_offset.push_back(hp.vars[i].offset);
10455 hist_voffset.push_back(hp.vars[i].voffset);
10456 }
10457
10458 if (hp.vars.size() > 0) {
10459 o->WSA("Variables", hist_vars, 64);
10460 o->WSA("Formula", hist_formula, 64);
10461 o->WSA("Colour", hist_colour, NAME_LENGTH);
10462 o->WSA("Label", hist_label, NAME_LENGTH);
10463 o->WBA("Show raw value", hist_show_raw_value);
10464 o->WDA("Factor", hist_factor);
10465 o->WDA("Offset", hist_offset);
10466 o->WDA("VOffset", hist_voffset);
10467 } else {
10468 o->Delete("Variables");
10469 o->Delete("Formula");
10470 o->Delete("Colour");
10471 o->Delete("Label");
10472 o->Delete("Show raw value");
10473 o->Delete("Factor");
10474 o->Delete("Offset");
10475 o->Delete("VOffset");
10476 }
10477
10478 delete o;
10479}
10480
10482{
10483 /* delete variables according to "hist_order" */
10484
10485 while (1) {
10486 bool something_deleted = false;
10487 for (unsigned i=0; i<hp.vars.size(); i++) {
10488 if (hp.vars[i].order <= 0) {
10489 hp.vars.erase(hp.vars.begin() + i);
10490 something_deleted = true;
10491 }
10492 }
10493 if (!something_deleted)
10494 break;
10495 }
10496}
10497
10499{
10500 /* sort variables according to "hist_order" */
10501
10502 bool need_sort = false;
10503 for (size_t i=1; i<hp.vars.size(); i++) {
10504 if (hp.vars[i-1].order >= hp.vars[i].order) {
10505 need_sort = true;
10506 }
10507 }
10508
10509 if (need_sort) {
10510 /* sort variables by order */
10511 std::sort(hp.vars.begin(), hp.vars.end(), cmp_vars);
10512
10513 /* renumber the variables according to the new sorted order */
10514 for (size_t index=0; index<hp.vars.size(); index++)
10515 hp.vars[index].order = (index+1)*10;
10516 }
10517}
10518
10519void show_hist_config_page(MVOdb* odb, Param* p, Return* r, const char *hgroup, const char *hpanel)
10520{
10521 int status;
10522 int max_display_events = 20;
10523 int max_display_tags = 200;
10524 char str[256], hcmd[256];
10525
10526 odb->RI("History/MaxDisplayEvents", &max_display_events, true);
10527 odb->RI("History/MaxDisplayTags", &max_display_tags, true);
10528
10529 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
10530
10531 if (equal_ustring(hcmd, "Clear history cache")) {
10532 //printf("clear history cache!\n");
10533 strcpy(hcmd, "Refresh");
10535 if (mh)
10536 mh->hs_clear_cache();
10537 }
10538
10539 //printf("cmd [%s]\n", cmd);
10540 //printf("cmdx [%s]\n", p->getparam("cmdx"));
10541
10542 HistPlot hp;
10543
10544 if (equal_ustring(hcmd, "refresh") || equal_ustring(hcmd, "save")) {
10547 } else {
10549 }
10550
10552
10553 if (strlen(p->getparam("seln")) > 0)
10555
10556 //hp->Print();
10557
10558 if (hcmd[0] && equal_ustring(hcmd, "save")) {
10560
10561 if (p->getparam("redir") && *p->getparam("redir"))
10562 redirect(r, p->getparam("redir"));
10563 else {
10564 sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
10565 redirect(r, str);
10566 }
10567 return;
10568 }
10569
10570 show_header(r, "History Config", "GET", "", 0);
10571 r->rsprintf("</table>"); //close header table
10572
10573 r->rsprintf("<table class=\"mtable\">"); //open main table
10574
10575 r->rsprintf("<tr><th colspan=11 class=\"subStatusTitle\">History Panel \"%s\" / \"%s\"</th></tr>\n", hgroup, hpanel);
10576
10577 /* menu buttons */
10578 r->rsprintf("<tr><td colspan=11>\n");
10579
10580 r->rsprintf("<input type=button value=Refresh ");
10581 r->rsprintf("onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">\n");
10582
10583 r->rsprintf("<input type=button value=Save ");
10584 r->rsprintf("onclick=\"document.form1.hcmd.value='Save';document.form1.submit()\">\n");
10585
10586 {
10587 r->rsprintf("<input type=button value=Cancel ");
10588 std::string url = "?cmd=oldhistory&group=";
10589 url += hgroup;
10590 url += "&panel=";
10591 url += hpanel;
10592 url += "&hcmd=Cancel";
10593 if (p->getparam("redir")) {
10594 url += "&redir=";
10595 url += urlEncode(p->getparam("redir"));
10596 }
10597 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10598 }
10599 {
10600 r->rsprintf("<input type=button value=\"Edit in ODB\"");
10601 std::string url = "?cmd=odb&odb_path=";
10602 url += "/History/Display/";
10603 url += urlEncode(hgroup);
10604 url += "/";
10605 url += urlEncode(hpanel);
10606 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10607 }
10608 {
10609 r->rsprintf("<input type=button value=\"Edit in new editor\"");
10610 std::string url = "?cmd=hs_edit";
10611 url += "&group=";
10612 url += urlEncode(hgroup);
10613 url += "&panel=";
10614 url += urlEncode(hpanel);
10615 if (p->getparam("redir")) {
10616 url += "&redir=";
10617 url += urlEncode(p->getparam("redir"));
10618 }
10619 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10620 }
10621 r->rsprintf("<input type=button value=\"Clear history cache\"");
10622 r->rsprintf("onclick=\"document.form1.hcmd.value='Clear history cache';document.form1.submit()\">\n");
10623 r->rsprintf("<input type=button value=\"Delete panel\"");
10624 r->rsprintf("onclick=\"window.location.search='?cmd=oldhistory&group=%s&panel=%s&hcmd=Delete%%20panel'\">\n", hgroup, hpanel);
10625 r->rsprintf("</td></tr>\n");
10626
10627 r->rsprintf("<tr><td colspan=11>\n");
10628
10629 /* sort_vars */
10630 int sort_vars = *p->getparam("sort_vars");
10631 r->rsprintf("<input type=checkbox %s name=sort_vars value=1 onclick=\"this.form.submit();\">Sort variable names", sort_vars?"checked":"");
10632
10633 /* old_vars */
10634 int old_vars = *p->getparam("old_vars");
10635 r->rsprintf("&nbsp;&nbsp;<input type=checkbox %s name=old_vars value=1 onclick=\"this.form.submit();\">Show deleted and renamed variables", old_vars?"checked":"");
10636
10637 if (hp.show_factor)
10638 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10639 else
10640 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10641 r->rsprintf("Show&nbsp;factor&nbsp;and&nbsp;offset\n");
10642
10643 /* hidden command for refresh */
10644 r->rsprintf("<input type=hidden name=cmd value=Oldhistory>\n");
10645 r->rsprintf("<input type=hidden name=hcmd value=Refresh>\n");
10646 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", hpanel);
10647 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", hgroup);
10648
10649 if (p->getparam("redir") && *p->getparam("redir"))
10650 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", p->getparam("redir"));
10651
10652 r->rsprintf("</td></tr>\n");
10653
10654 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Time scale (in units 'm', 'h', 'd'):</td>\n");
10655 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());
10656
10657 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Minimum (set to '-inf' for autoscale):</td>\n");
10658 r->rsprintf("<td colspan=3><input type=text size=12 name=minimum value=%f></td><td colspan=4></td></tr>\n", hp.minimum);
10659
10660 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Maximum (set to 'inf' for autoscale):</td>\n");
10661 r->rsprintf("<td colspan=3><input type=text size=12 name=maximum value=%f></td><td colspan=4></td></tr>\n", hp.maximum);
10662
10663 r->rsprintf("<tr><td colspan=11>");
10664
10665 if (hp.zero_ylow)
10666 r->rsprintf("<input type=checkbox checked name=zero_ylow value=1>");
10667 else
10668 r->rsprintf("<input type=checkbox name=zero_ylow value=1>");
10669 r->rsprintf("Zero&nbsp;Y;&nbsp;axis\n");
10670
10671 if (hp.log_axis)
10672 r->rsprintf("<input type=checkbox checked name=log_axis value=1>");
10673 else
10674 r->rsprintf("<input type=checkbox name=log_axis value=1>");
10675 r->rsprintf("Logarithmic&nbsp;Y&nbsp;axis\n");
10676
10677 if (hp.show_run_markers)
10678 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=run_markers value=1>");
10679 else
10680 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=run_markers value=1>");
10681 r->rsprintf("Show&nbsp;run&nbsp;markers\n");
10682
10683 if (hp.show_values)
10684 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_values value=1>");
10685 else
10686 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_values value=1>");
10687 r->rsprintf("Show&nbsp;values&nbsp;of&nbsp;variables\n");
10688
10689 if (hp.show_fill)
10690 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_fill value=1>");
10691 else
10692 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_fill value=1>");
10693 r->rsprintf("Show&nbsp;graph&nbsp;fill\n");
10694
10695 r->rsprintf("</td></tr>\n");
10696
10697 /*---- events and variables ----*/
10698
10699 /* get display event name */
10700
10702 if (mh == NULL) {
10703 r->rsprintf(str, "History is not configured\n");
10704 return;
10705 }
10706
10707 time_t t = time(NULL);
10708
10709 if (old_vars)
10710 t = 0;
10711
10712 std::vector<std::string> events;
10713
10714 if (!old_vars)
10716
10717 if (events.size() == 0)
10718 mh->hs_get_events(t, &events);
10719
10720#if 0
10721 for (unsigned i=0; i<events.size(); i++)
10722 printf("event %d: \"%s\"\n", i, events[i].c_str());
10723#endif
10724
10725 // has to be sorted or equipment name code below would not work
10726 //std::sort(events.begin(), events.end(), cmp_events);
10727 std::sort(events.begin(), events.end(), cmp_events1);
10728
10729 if (strlen(p->getparam("cmdx")) > 0) {
10730 r->rsprintf("<tr><th colspan=8 class=\"subStatusTitle\">List of available history variables</th></tr>\n");
10731 r->rsprintf("<tr><th colspan=1>Sel<th colspan=1>Equipment<th colspan=1>Event<th colspan=1>Variable</tr>\n");
10732
10733 std::string cmdx = p->xgetparam("cmdx");
10734 std::string xeqname;
10735
10736 int i=0;
10737 for (unsigned e=0; e<events.size(); e++) {
10738 std::string eqname;
10739 eqname = events[e].substr(0, events[e].find("/"));
10740
10741 if (eqname.length() < 1)
10742 eqname = events[e];
10743
10744 bool once = false;
10745 if (eqname != xeqname)
10746 once = true;
10747
10748 std::string qcmd = "Expand " + eqname;
10749
10750 //printf("param [%s] is [%s]\n", qcmd.c_str(), p->getparam(qcmd.c_str()));
10751
10752 bool collapsed = true;
10753
10754 if (cmdx == qcmd)
10755 collapsed = false;
10756
10757 if (strlen(p->getparam(qcmd.c_str())) > 0)
10758 collapsed = false;
10759
10760 if (collapsed) {
10761 if (eqname == xeqname)
10762 continue;
10763
10764 r->rsprintf("<tr align=left>\n");
10765 r->rsprintf("<td></td>\n");
10766 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10767 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", qcmd.c_str());
10768 r->rsprintf("<td>%s</td>\n", "");
10769 r->rsprintf("</tr>\n");
10770 xeqname = eqname;
10771 continue;
10772 }
10773
10774 if (once)
10775 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", qcmd.c_str(), 1);
10776
10777 std::string rcmd = "Expand " + events[e];
10778
10779 //printf("param [%s] is [%s]\n", rcmd.c_str(), p->getparam(rcmd.c_str()));
10780
10781 collapsed = true;
10782
10783 if (cmdx == rcmd)
10784 collapsed = false;
10785
10786 if (strlen(p->getparam(rcmd.c_str())) > 0)
10787 collapsed = false;
10788
10789 if (collapsed) {
10790 r->rsprintf("<tr align=left>\n");
10791 r->rsprintf("<td></td>\n");
10792 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10793 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10794 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", rcmd.c_str());
10795 r->rsprintf("</tr>\n");
10796 continue;
10797 }
10798
10799 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", rcmd.c_str(), 1);
10800
10801 xeqname = eqname;
10802
10803 std::vector<TAG> tags;
10804
10805 status = mh->hs_get_tags(events[e].c_str(), t, &tags);
10806
10807 if (status == HS_SUCCESS && tags.size() > 0) {
10808
10809 if (sort_vars)
10810 std::sort(tags.begin(), tags.end(), cmp_tags);
10811
10812 for (unsigned v=0; v<tags.size(); v++) {
10813
10814 for (unsigned j=0; j<tags[v].n_data; j++) {
10815 char tagname[256];
10816
10817 if (tags[v].n_data == 1)
10818 sprintf(tagname, "%s", tags[v].name);
10819 else
10820 sprintf(tagname, "%s[%d]", tags[v].name, j);
10821
10822 bool checked = false;
10823#if 0
10824 for (int index=0; index<MAX_VARS; index++) {
10825 if (equal_ustring(vars[index].event_name, events[e].c_str()) && equal_ustring(vars[index].var_name, tagname)) {
10826 checked = true;
10827 break;
10828 }
10829 }
10830#endif
10831
10832 r->rsprintf("<tr align=left>\n");
10833 r->rsprintf("<td><input type=checkbox %s name=\"sel%d\" value=\"%s:%s\"></td>\n", checked?"checked":"", i++, events[e].c_str(), tagname);
10834 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10835 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10836 r->rsprintf("<td>%s</td>\n", tagname);
10837 r->rsprintf("</tr>\n");
10838 }
10839 }
10840 }
10841 }
10842
10843 r->rsprintf("<tr>\n");
10844 r->rsprintf("<td></td>\n");
10845 r->rsprintf("<td>\n");
10846 r->rsprintf("<input type=hidden name=seln value=%d>\n", i);
10847 r->rsprintf("<input type=submit value=\"Add Selected\">\n");
10848 r->rsprintf("</td>\n");
10849 r->rsprintf("</tr>\n");
10850 }
10851
10852 r->rsprintf("<tr><td colspan=11 style='text-align:left'>New history: displayed_value = formula(history_value)</td></tr>\n");
10853 r->rsprintf("<tr><td colspan=11 style='text-align:left'>Old history: displayed_value = offset + factor*(history_value - voffset)</td></tr>\n");
10854 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");
10855 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");
10856 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");
10857 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");
10858
10859 r->rsprintf("<tr>\n");
10860 r->rsprintf("<th>Col<th>Event<th>Variable<th>Formula<th>Colour<th>Label<th>Raw<th>Order");
10861 if (hp.show_factor) {
10862 r->rsprintf("<th>Factor<th>Offset<th>VOffset");
10863 }
10864 r->rsprintf("</tr>\n");
10865
10866 //print_vars(vars);
10867
10868 size_t nvars = hp.vars.size();
10869 for (size_t index = 0; index <= nvars; index++) {
10870
10871 r->rsprintf("<tr>");
10872
10873 if (index < nvars) {
10874 if (hp.vars[index].colour.empty())
10875 hp.vars[index].colour = NextHistPlotColour(hp);
10876 r->rsprintf("<td style=\"background-color:%s\">&nbsp;<td>\n", hp.vars[index].colour.c_str());
10877 } else {
10878 r->rsprintf("<td>&nbsp;<td>\n");
10879 }
10880
10881 /* event and variable selection */
10882
10883 r->rsprintf("<select name=\"event%d\" size=1 onChange=\"document.form1.submit()\">\n", (int)index);
10884
10885 /* enumerate events */
10886
10887 /* empty option */
10888 r->rsprintf("<option value=\"/empty\">&lt;empty&gt;\n");
10889
10890 if (index==nvars) { // last "empty" entry
10891 for (unsigned e=0; e<events.size(); e++) {
10892 const char *p = events[e].c_str();
10893 r->rsprintf("<option value=\"%s\">%s\n", p, p);
10894 }
10895 } else if ((int)events.size() > max_display_events) { // too many events
10896 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].event_name.c_str(), hp.vars[index].event_name.c_str());
10897 r->rsprintf("<option>(%d events omitted)\n", (int)events.size());
10898 } else { // show all events
10899 bool found = false;
10900 for (unsigned e=0; e<events.size(); e++) {
10901 const char *s = "";
10902 const char *p = events[e].c_str();
10903 if (equal_ustring(hp.vars[index].event_name.c_str(), p)) {
10904 s = "selected";
10905 found = true;
10906 }
10907 r->rsprintf("<option %s value=\"%s\">%s\n", s, p, p);
10908 }
10909 if (!found) {
10910 const char *p = hp.vars[index].event_name.c_str();
10911 r->rsprintf("<option selected value=\"%s\">%s\n", p, p);
10912 }
10913 }
10914
10915 r->rsprintf("</select></td>\n");
10916
10917 //if (hp.vars[index].order <= 0)
10918 // hp.vars[index].order = (index+1)*10;
10919
10920 if (index < nvars) {
10921 bool found_tag = false;
10922 std::string selected_tag = hp.vars[index].tag_name;
10923
10924 r->rsprintf("<td><select name=\"var%d\">\n", (int)index);
10925
10926 std::vector<TAG> tags;
10927
10928 status = mh->hs_get_tags(hp.vars[index].event_name.c_str(), t, &tags);
10929
10930 if (status == HS_SUCCESS && tags.size() > 0) {
10931
10932 if (/* DISABLES CODE */ (0)) {
10933 printf("Compare %d\n", cmp_names("AAA", "BBB"));
10934 printf("Compare %d\n", cmp_names("BBB", "AAA"));
10935 printf("Compare %d\n", cmp_names("AAA", "AAA"));
10936 printf("Compare %d\n", cmp_names("A", "AAA"));
10937 printf("Compare %d\n", cmp_names("A111", "A1"));
10938 printf("Compare %d\n", cmp_names("A111", "A2"));
10939 printf("Compare %d\n", cmp_names("A111", "A222"));
10940 printf("Compare %d\n", cmp_names("A111a", "A111b"));
10941 }
10942
10943 if (sort_vars)
10944 std::sort(tags.begin(), tags.end(), cmp_tags);
10945
10946 if (/* DISABLES CODE */ (0)) {
10947 printf("Event [%s] %d tags\n", hp.vars[index].event_name.c_str(), (int)tags.size());
10948
10949 for (unsigned v=0; v<tags.size(); v++) {
10950 printf("tag[%d] [%s]\n", v, tags[v].name);
10951 }
10952 }
10953
10954 unsigned count_tags = 0;
10955 for (unsigned v=0; v<tags.size(); v++)
10956 count_tags += tags[v].n_data;
10957
10958 //printf("output %d option tags\n", count_tags);
10959
10960 if ((int)count_tags < max_display_tags) {
10961 for (unsigned v=0; v<tags.size(); v++) {
10962
10963 for (unsigned j=0; j<tags[v].n_data; j++) {
10964 std::string tagname;
10965
10966 if (tags[v].n_data == 1)
10967 tagname = tags[v].name;
10968 else {
10969 char buf[256];
10970 sprintf(buf, "[%d]", j);
10971 tagname = std::string(tags[v].name) + buf;
10972 }
10973
10974 if (equal_ustring(selected_tag.c_str(), tagname.c_str())) {
10975 r->rsprintf("<option selected value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10976 found_tag = true;
10977 }
10978 else
10979 r->rsprintf("<option value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10980
10981 //printf("%d [%s] [%s] [%s][%s] %d\n", (int)index, vars[index].event_name, tagname, vars[index].var_name, selected_var, found_var);
10982 }
10983 }
10984 }
10985 }
10986
10987 if (!found_tag)
10988 if (hp.vars[index].tag_name.length() > 0)
10989 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].tag_name.c_str(), hp.vars[index].tag_name.c_str());
10990
10991 r->rsprintf("</select></td>\n");
10992 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());
10993 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());
10994 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());
10995 if (hp.vars[index].show_raw_value)
10996 r->rsprintf("<td><input type=checkbox checked name=\"raw%d\" value=1></td>", (int)index);
10997 else
10998 r->rsprintf("<td><input type=checkbox name=\"raw%d\" value=1></td>", (int)index);
10999 r->rsprintf("<td><input type=text size=3 maxlength=32 name=\"ord%d\" value=\"%d\"></td>\n", (int)index, hp.vars[index].order);
11000 if (hp.show_factor) {
11001 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"factor%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].factor);
11002 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"offset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].offset);
11003 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"voffset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].voffset);
11004 } else {
11005 r->rsprintf("<input type=hidden name=\"factor%d\" value=\"%f\">\n", (int)index, hp.vars[index].factor);
11006 r->rsprintf("<input type=hidden name=\"offset%d\" value=\"%f\">\n", (int)index, hp.vars[index].offset);
11007 r->rsprintf("<input type=hidden name=\"voffset%d\" value=\"%f\">\n", (int)index, hp.vars[index].voffset);
11008 }
11009 } else {
11010 r->rsprintf("<td colspan=2><input type=submit name=cmdx value=\"List all variables\"></td>\n");
11011 }
11012
11013 r->rsprintf("</tr>\n");
11014 }
11015
11016 r->rsprintf("</table>\n");
11017 //r->rsprintf("</form>\n");
11018 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11019 r->rsprintf("</form>\n");
11020 r->rsprintf("</body></html>\r\n");
11021}
11022
11023/*------------------------------------------------------------------*/
11024
11025void export_hist(MVOdb* odb, Return* r, const char *group, const char *panel, time_t endtime, int scale, int index, int labels)
11026{
11027 //HNDLE hDB, hkey, hkeypanel;
11028 //int size;
11029 int status;
11030 //char str[256];
11031
11032 int debug = 0;
11033
11034 ss_tzset(); // required for localtime_r()
11035
11036#if 0
11038
11039 /* check panel name in ODB */
11040 sprintf(str, "/History/Display/%s/%s", group, panel);
11042 if (!hkeypanel) {
11043 sprintf(str, "Cannot find /History/Display/%s/%s in ODB\n", group, panel);
11044 show_error(r, str);
11045 return;
11046 }
11047
11048 /* get runmarker flag */
11049 BOOL runmarker = 1;
11050 size = sizeof(runmarker);
11051 db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
11052
11053 if (scale == 0) {
11054 /* get timescale */
11055 std::string ts = "1h";
11056 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11057 if (status != DB_SUCCESS) {
11058 /* delete old integer key */
11059 db_find_key(hDB, hkeypanel, "Timescale", &hkey);
11060 if (hkey)
11062
11063 ts = "1h";
11064 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11065 }
11066
11067 scale = time_to_sec(ts.c_str());
11068 }
11069#endif
11070
11071 time_t now = ss_time();
11072
11073 if (endtime == 0)
11074 endtime = now;
11075
11078
11079 HistPlot hp;
11081
11082 time_t starttime = endtime - scale;
11083
11084 //printf("start %.0f, end %.0f, scale %.0f\n", (double)starttime, (double)endtime, (double)scale);
11085
11086 status = read_history(hp, /*hDB, group, panel,*/ index, hp.show_run_markers, starttime, endtime, 0, hsdata);
11087 if (status != HS_SUCCESS) {
11088 char str[256];
11089 sprintf(str, "History error, status %d\n", status);
11090 show_error(r, str);
11091 return;
11092 }
11093
11094 if (debug)
11095 hsdata->Print();
11096
11097 int *i_var = (int *)malloc(sizeof(int)*hsdata->nvars);
11098
11099 for (int i = 0; i < hsdata->nvars; i++)
11100 i_var[i] = -1;
11101
11102 time_t t = 0;
11103
11104 /* find first time where all variables are available */
11105 for (int i = 0; i < hsdata->nvars; i++)
11106 if (hsdata->odb_index[i] >= 0)
11107 if (hsdata->num_entries[i] > 0)
11108 if ((t == 0) || (hsdata->t[i][0] > t))
11109 t = hsdata->t[i][0];
11110
11111 if (t == 0 && hsdata->nvars > 1) {
11112 show_error(r, "No history available for choosen period");
11113 free(i_var);
11114 return;
11115 }
11116
11117 int run_index = -1;
11118 int state_index = -1;
11119 int n_run_number = 0;
11121 if (hp.show_run_markers)
11122 for (int i = 0; i < hsdata->nvars; i++) {
11123 if (hsdata->odb_index[i] == -2) {
11124 n_run_number = hsdata->num_entries[i];
11125 t_run_number = hsdata->t[i];
11126 run_index = i;
11127 } else if (hsdata->odb_index[i] == -1) {
11128 state_index = i;
11129 }
11130 }
11131
11132 //printf("runmarker %d, state %d, run %d\n", runmarker, state_index, run_index);
11133
11134 /* header */
11135 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
11136 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
11137 r->rsprintf("Accept-Ranges: bytes\r\n");
11138 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
11139 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
11140 r->rsprintf("Content-Type: text/plain\r\n");
11141 r->rsprintf("Content-disposition: attachment; filename=\"export.csv\"\r\n");
11142 r->rsprintf("\r\n");
11143
11144 /* output header line with variable names */
11145 if (hp.show_run_markers && t_run_number)
11146 r->rsprintf("Time, Timestamp, Run, Run State, ");
11147 else
11148 r->rsprintf("Time, Timestamp, ");
11149
11150 for (int i = 0, first = 1; i < hsdata->nvars; i++) {
11151 if (hsdata->odb_index[i] < 0)
11152 continue;
11153 if (hsdata->num_entries[i] <= 0)
11154 continue;
11155 if (!first)
11156 r->rsprintf(", ");
11157 first = 0;
11158 r->rsprintf("%s", hsdata->var_names[i]);
11159 }
11160 r->rsprintf("\n");
11161
11162 int i_run = 0;
11163
11164 do {
11165
11166 if (debug)
11167 printf("hsdata %p, t %d, irun %d\n", hsdata, (int)t, i_run);
11168
11169 /* find run number/state which is valid for t */
11170 if (hp.show_run_markers && t_run_number)
11171 while (i_run < n_run_number-1 && t_run_number[i_run+1] <= t)
11172 i_run++;
11173
11174 //printf("irun %d\n", i_run);
11175
11176 /* find index for all variables which is valid for t */
11177 for (int i = 0; i < hsdata->nvars; i++)
11178 while (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i] - 1 && hsdata->t[i][i_var[i]+1] <= t)
11179 i_var[i]++;
11180
11181 /* finish if last point for all variables reached */
11182 bool done = true;
11183 for (int i = 0 ; i < hsdata->nvars ; i++)
11184 if (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i]) {
11185 done = false;
11186 break;
11187 }
11188
11189 if (debug) {
11190 printf("step to time %d: ", (int)t);
11191 for (int i = 0; i < hsdata->nvars; i++) {
11192 printf(" [%d] %d, ", hsdata->num_entries[i], i_var[i]);
11193 }
11194 printf(" done: %d\n", done);
11195 }
11196
11197 if (done)
11198 break;
11199
11200 struct tm tms;
11201 localtime_r(&t, &tms);
11202
11203 char fmt[256];
11204 //strcpy(fmt, "%c");
11205 strcpy(fmt, "%Y.%m.%d %H:%M:%S");
11206 char str[256];
11207 strftime(str, sizeof(str), fmt, &tms);
11208
11209 if (t_run_number && run_index>=0 && state_index>=0) {
11210 if (t_run_number[i_run] <= t)
11211 r->rsprintf("%s, %d, %.0f, %.0f, ", str, (int)t, hsdata->v[run_index][i_run], hsdata->v[state_index][i_run]);
11212 else
11213 r->rsprintf("%s, %d, N/A, N/A, ", str, (int)t);
11214 } else
11215 r->rsprintf("%s, %d, ", str, (int)t);
11216
11217 if (debug) {
11218 for (int i= 0 ; i < hsdata->nvars ; i++)
11219 printf(" %d (%g)", i_var[i], hsdata->v[i][i_var[i]]);
11220 printf("\n");
11221 }
11222
11223 for (int i=0, first=1 ; i<hsdata->nvars ; i++) {
11224 if (i_var[i] < 0)
11225 continue;
11226 if (hsdata->odb_index[i] < 0)
11227 continue;
11228 if (!first)
11229 r->rsprintf(", ");
11230 first = 0;
11231 //r->rsprintf("(%d %g)", i_var[i], hsdata->v[i][i_var[i]]);
11232 r->rsprintf("%g", hsdata->v[i][i_var[i]]);
11233 }
11234 r->rsprintf("\n");
11235
11236 /* find next t as smallest delta t */
11237 int dt = -1;
11238 for (int i = 0 ; i < hsdata->nvars ; i++)
11239 if (i_var[i]>=0 && hsdata->odb_index[i]>=0 && hsdata->num_entries[i]>0 && i_var[i]<hsdata->num_entries[i]-1) {
11240 int xdt = hsdata->t[i][i_var[i]+1] - t;
11241 if (debug)
11242 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);
11243 if (dt <= 0 || xdt < dt)
11244 dt = xdt;
11245 }
11246
11247 if (debug)
11248 printf("dt %d\n", dt);
11249
11250 if (dt <= 0)
11251 break;
11252
11253 t += dt;
11254
11255 } while (1);
11256
11257 free(i_var);
11258}
11259
11260/*------------------------------------------------------------------*/
11261
11262void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
11263{
11265 KEY key, ikey;
11266 int i, j, k, scale, index, width, size, status, labels;
11267 char hgroup[256], hpanel[256], hcmd[256];
11268 const char def_button[][NAME_LENGTH] = { "10m", "1h", "3h", "12h", "24h", "3d", "7d" };
11269
11271
11272 hcmd[0] = hgroup[0] = hpanel[0] = 0;
11273
11274 if (p->getparam("group") && *p->getparam("group"))
11275 mstrlcpy(hgroup, p->getparam("group"), sizeof(hgroup));
11276 if (p->getparam("panel") && *p->getparam("panel"))
11277 mstrlcpy(hpanel, p->getparam("panel"), sizeof(hpanel));
11278 if (p->getparam("hcmd") && *p->getparam("hcmd"))
11279 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
11280
11281 if (equal_ustring(hcmd, "Reset")) {
11282 std::string redir;
11283 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11284 redir += "?cmd=oldhistory&group=";
11285 redir += hgroup;
11286 redir += "&panel=";
11287 redir += hpanel;
11288 redirect(r, redir.c_str());
11289 return;
11290 }
11291
11292 if (equal_ustring(hcmd, "Query")) {
11293 show_query_page(p, r);
11294 return;
11295 }
11296
11297 if (equal_ustring(hcmd, "Cancel")) {
11298 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11299 if (p->getparam("redir") && *p->getparam("redir"))
11300 redirect(r, p->getparam("redir"));
11301 else {
11302 std::string redir;
11303 redir += "?cmd=oldhistory&group=";
11304 redir += hgroup;
11305 redir += "&panel=";
11306 redir += hpanel;
11307 redirect(r, redir.c_str());
11308 }
11309 return;
11310 }
11311
11312 if (equal_ustring(hcmd, "Config") ||
11313 equal_ustring(hcmd, "Save")
11314 || equal_ustring(hcmd, "Clear history cache")
11315 || equal_ustring(hcmd, "Refresh")) {
11316
11317 show_hist_config_page(odb, p, r, hgroup, hpanel);
11318 return;
11319 }
11320
11321 if (equal_ustring(hcmd, "New")) {
11322 show_header(r, "History", "GET", "", 0);
11323
11324 r->rsprintf("<table class=\"dialogTable\">");
11325 r->rsprintf("<tr><th class=\"subStatusTitle\" colspan=2>New History Item</th><tr>");
11326 r->rsprintf("<tr><td align=center colspan=2>\n");
11327 r->rsprintf("Select group: &nbsp;&nbsp;");
11328 r->rsprintf("<select id=\"group\" name=\"group\">\n");
11329
11330 /* list existing groups */
11331 db_find_key(hDB, 0, "/History/Display", &hkey);
11332 if (hkey) {
11333 for (i = 0;; i++) {
11335
11336 if (!hkeyp)
11337 break;
11338
11339 db_get_key(hDB, hkeyp, &key);
11341 r->rsprintf("<option selected>%s</option>\n", key.name);
11342 else
11343 r->rsprintf("<option>%s</option>\n", key.name);
11344 }
11345 }
11346 if (!hkey || i == 0)
11347 r->rsprintf("<option>Default</option>\n");
11348 r->rsprintf("</select><p>\n");
11349
11350 r->rsprintf("Or enter new group name: &nbsp;&nbsp;");
11351 r->rsprintf("<input type=text size=15 maxlength=31 id=new_group name=new_group>\n");
11352
11353 r->rsprintf("<tr><td align=center colspan=2>\n");
11354 r->rsprintf("<br>Panel name: &nbsp;&nbsp;");
11355 r->rsprintf("<input type=text size=15 maxlength=31 id=panel name=panel><br><br>\n");
11356 r->rsprintf("</td></tr>\n");
11357
11358 r->rsprintf("<tr><td align=center colspan=2>");
11359 std::string str = "?cmd=oldhistory&hcmd=createnew";
11360 str += "&new_group='+document.getElementById('new_group').value+'";
11361 str += "&group='+document.getElementById('group').value+'";
11362 str += "&panel='+document.getElementById('panel').value+'";
11363 r->rsprintf("<input type=button value=Submit onclick=\"window.location.search='%s'\">\n", str.c_str());
11364 r->rsprintf("</td></tr>\n");
11365
11366 r->rsprintf("</table>\r\n");
11367 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11368 r->rsprintf("</form>\n");
11369 r->rsprintf("</body></html>\r\n");
11370 return;
11371 }
11372
11373 if (equal_ustring(hcmd, "Delete Panel")) {
11374 std::string path;
11375 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11376 path += "/History/Display/";
11377 path += hgroup;
11378 path += "/";
11379 path += hpanel;
11380 if (db_find_key(hDB, 0, path.c_str(), &hkey)==DB_SUCCESS)
11382
11383 redirect(r, "?cmd=oldhistory");
11384 return;
11385 }
11386
11387 if (equal_ustring(hcmd, "createnew")) {
11388
11389 /* strip leading/trailing spaces */
11390 while (hpanel[0] == ' ') {
11391 char str[256];
11392 mstrlcpy(str, hpanel+1, sizeof(str));
11393 mstrlcpy(hpanel, str, sizeof(hpanel));
11394 }
11395 while (strlen(hpanel)> 1 && hpanel[strlen(hpanel)-1] == ' ')
11396 hpanel[strlen(hpanel)-1] = 0;
11397
11398 /* use new group if present */
11399 if (p->isparam("new_group") && *p->getparam("new_group"))
11400 mstrlcpy(hgroup, p->getparam("new_group"), sizeof(hgroup));
11401
11402 /* configure that panel */
11403 show_hist_config_page(odb, p, r, hgroup, hpanel);
11404 return;
11405 }
11406
11407 const char* pscale = p->getparam("scale");
11408 if (pscale == NULL || *pscale == 0)
11409 pscale = p->getparam("hscale");
11410 const char* pwidth = p->getparam("width");
11411 if (pwidth == NULL || *pwidth == 0)
11412 pwidth = p->getparam("hwidth");
11413 const char* pheight = p->getparam("height");
11414 if (pheight == NULL || *pheight == 0)
11415 pheight = p->getparam("hheight");
11416 const char* pindex = p->getparam("index");
11417 if (pindex == NULL || *pindex == 0)
11418 pindex = p->getparam("hindex");
11419
11420 labels = 1;
11421 if (*p->getparam("labels") && atoi(p->getparam("labels")) == 0)
11422 labels = 0;
11423
11424 std::string bgcolor = "FFFFFF";
11425 if (*p->getparam("bgcolor"))
11426 bgcolor = p->xgetparam("bgcolor");
11427
11428 std::string fgcolor = "000000";
11429 if (*p->getparam("fgcolor"))
11430 fgcolor = p->xgetparam("fgcolor");
11431
11432 std::string gridcolor = "A0A0A0";
11433 if (*p->getparam("gcolor"))
11434 gridcolor = p->xgetparam("gcolor");
11435
11436 /* evaluate scale and offset */
11437
11438 time_t endtime = 0;
11439 if (p->isparam("time"))
11440 endtime = string_to_time(p->getparam("time"));
11441 else if (p->isparam("htime"))
11442 endtime = string_to_time(p->getparam("htime"));
11443
11444 if (pscale && *pscale)
11445 scale = time_to_sec(pscale);
11446 else
11447 scale = 0;
11448
11449 index = -1;
11450 if (pindex && *pindex)
11451 index = atoi(pindex);
11452
11453#ifdef BROKEN
11454 if (equal_ustring(hcmd, "Create ELog")) {
11455 std::string xurl;
11456 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &xurl, FALSE);
11457 if (status == DB_SUCCESS) {
11458 char url[256];
11459 get_elog_url(url, sizeof(url));
11460
11461 /*---- use external ELOG ----*/
11462 fsize = 100000;
11463 char* fbuffer = (char*)M_MALLOC(fsize);
11464 assert(fbuffer != NULL);
11465
11466 int width = 640;
11467 int height = 400;
11468
11469 if (equal_ustring(pmag, "Large")) {
11470 width = 1024;
11471 height = 768;
11472 } else if (equal_ustring(pmag, "Small")) {
11473 width = 320;
11474 height = 200;
11475 } else if (atoi(pmag) > 0) {
11476 width = atoi(pmag);
11477 height = 200;
11478 }
11479
11480 printf("hereA\n");
11481 generate_hist_graph(odb, r, hgroup, hpanel, fbuffer, &fsize, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11482
11483 /* save temporary file */
11484 std::string dir;
11485 db_get_value_string(hDB, 0, "/Elog/Logbook Dir", 0, &dir, TRUE);
11486 if (dir.length() > 0 && dir[dir.length()-1] != DIR_SEPARATOR)
11487 dir += DIR_SEPARATOR_STR;
11488
11489 time_t now = time(NULL);
11490 localtime_r(&now, &tms);
11491
11492 std::string file_name = msprintf("%02d%02d%02d_%02d%02d%02d_%s.gif",
11493 tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday,
11494 tms.tm_hour, tms.tm_min, tms.tm_sec, hpanel);
11495 std::string fname = dir + file_name;
11496
11497 /* save attachment */
11498 fh = open(fname.c_str(), O_CREAT | O_RDWR | O_BINARY, 0644);
11499 if (fh < 0) {
11500 cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", open() errno %d (%s)", fname.c_str(), errno, strerror(errno));
11501 } else {
11502 int wr = write(fh, fbuffer, fsize);
11503 if (wr != fsize) {
11504 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));
11505 }
11506 close(fh);
11507 }
11508
11509 /* redirect to ELOG */
11510 if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11511 mstrlcat(url, "/", sizeof(url));
11512 mstrlcat(url, "?cmd=New&fa=", sizeof(url));
11513 mstrlcat(url, file_name, sizeof(url));
11514 redirect(r, url);
11515
11516 M_FREE(fbuffer);
11517 return;
11518
11519 } else {
11520 /*---- use internal ELOG ----*/
11521 std::string str = msprintf("\\HS\\%s.gif", hpanel);
11522 if (p->getparam("hscale") && *p->getparam("hscale"))
11523 str += msprintf("?scale=%s", p->getparam("hscale"));
11524 if (p->getparam("htime") && *p->getparam("htime")) {
11525 if (strchr(str.c_str(), '?'))
11526 str += "&";
11527 else
11528 str += "?";
11529 str += msprintf("time=%s", p->getparam("htime"));
11530 }
11531 //if (p->getparam("hoffset") && *p->getparam("hoffset")) {
11532 // if (strchr(str, '?'))
11533 // mstrlcat(str, "&", sizeof(str));
11534 // else
11535 // mstrlcat(str, "?", sizeof(str));
11536 // sprintf(str + strlen(str), "offset=%s", p->getparam("hoffset"));
11537 //}
11538 if (p->getparam("hwidth") && *p->getparam("hwidth")) {
11539 if (strchr(str.c_str(), '?'))
11540 str += "&";
11541 else
11542 str += "?";
11543 str += msprintf("width=%s", p->getparam("hwidth"));
11544 }
11545 if (p->getparam("hindex") && *p->getparam("hindex")) {
11546 if (strchr(str.c_str(), '?'))
11547 str += "&";
11548 else
11549 str += "?";
11550 str += msprintf("index=%s", p->getparam("hindex"));
11551 }
11552
11553 show_elog_new(r, hpanel, NULL, FALSE, str.c_str(), "../../EL/");
11554 return;
11555 }
11556 }
11557#endif
11558
11559 if (equal_ustring(hcmd, "Export")) {
11560 export_hist(odb, r, hgroup, hpanel, endtime, scale, index, labels);
11561 return;
11562 }
11563
11564 if (strstr(dec_path, ".gif")) {
11565 int width = 640;
11566 int height = 400;
11567 if (equal_ustring(pwidth, "Large")) {
11568 width = 1024;
11569 height = 768;
11570 } else if (equal_ustring(pwidth, "Small")) {
11571 width = 320;
11572 height = 200;
11573 } else if (atoi(pwidth) > 0) {
11574 width = atoi(pwidth);
11575 if (atoi(pheight) > 0)
11576 height = atoi(pheight);
11577 else
11578 height = (int)(0.625 * width);
11579 }
11580
11581 //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);
11582
11583 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());
11584
11585 return;
11586 }
11587
11588 if (history_mode && index < 0)
11589 return;
11590
11591 time_t now = time(NULL);
11592
11593 /* evaluate offset shift */
11594 if (equal_ustring(p->getparam("shift"), "leftmaxall")) {
11595 if (endtime == 0)
11596 endtime = now;
11597 time_t last_written = 0;
11598 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 1, &last_written);
11599 if (status == HS_SUCCESS)
11600 endtime = last_written + scale/2;
11601 }
11602
11603 if (equal_ustring(p->getparam("shift"), "leftmax")) {
11604 if (endtime == 0)
11605 endtime = now;
11606 time_t last_written = 0;
11607 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 0, &last_written);
11608 if (status == HS_SUCCESS)
11609 if (last_written != endtime)
11610 endtime = last_written + scale/2;
11611 }
11612
11613 if (equal_ustring(p->getparam("shift"), "left")) {
11614 if (endtime == 0)
11615 endtime = now;
11616 endtime -= scale/2;
11617 //offset -= scale / 2;
11618 }
11619
11620 if (equal_ustring(p->getparam("shift"), "right")) {
11621 if (endtime == 0)
11622 endtime = now;
11623 endtime += scale/2;
11624 if (endtime > now)
11625 endtime = now;
11626 }
11627
11628 if (equal_ustring(p->getparam("shift"), "rightmax")) {
11629 endtime = 0;
11630 }
11631
11632 if (equal_ustring(p->getparam("shift"), "zoomin")) {
11633 if (endtime == 0)
11634 endtime = now;
11635 endtime -= scale / 4;
11636 scale /= 2;
11637 }
11638
11639 if (equal_ustring(p->getparam("shift"), "zoomout")) {
11640 if (endtime == 0)
11641 endtime = now;
11642 endtime += scale / 2;
11643 if (endtime > now)
11644 endtime = now;
11645 scale *= 2;
11646 }
11647
11648 int xrefresh = refresh;
11649 if (endtime != 0)
11650 xrefresh = 0;
11651 show_header(r, hpanel, "GET", "", xrefresh);
11652
11653 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
11654 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
11655 show_navigation_bar(r, "History");
11656
11657 r->rsprintf("<table class=\"mtable\">");
11658 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>History</th></tr>");
11659
11660 {
11661 /* check if panel exists */
11662 std::string path;
11663 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11664 path += "/History/Display/";
11665 path += hgroup;
11666 path += "/";
11667 path += hpanel;
11668 status = db_find_key(hDB, 0, path.c_str(), &hkey);
11669 if (status != DB_SUCCESS && !equal_ustring(hpanel, "All") && !equal_ustring(hpanel,"")) {
11670 r->rsprintf("<h1>Error: History panel \"%s\" in group \"%s\" does not exist</h1>\n", hpanel, hgroup);
11671 r->rsprintf("</table>\r\n");
11672 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11673 r->rsprintf("</form>\n");
11674 r->rsprintf("</body></html>\r\n");
11675 return;
11676 }
11677 }
11678
11679 /* define hidden field for parameters */
11680 if (pscale && *pscale)
11681 r->rsprintf("<input type=hidden name=hscale id=hscale value=%d>\n", scale);
11682 else {
11683 /* if no scale and offset given, get it from default */
11684 if (hpanel[0] && !equal_ustring(hpanel, "All") && hgroup[0]) {
11685 std::string path;
11686 path += "/History/Display/";
11687 path += hgroup;
11688 path += "/";
11689 path += hpanel;
11690 path += "/Timescale";
11691
11692 std::string scalestr = "1h";
11693 status = db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11694 if (status != DB_SUCCESS) {
11695 /* delete old integer key */
11696 db_find_key(hDB, 0, path.c_str(), &hkey);
11697 if (hkey)
11699
11700 scalestr = "1h";
11701 db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11702 }
11703
11704 r->rsprintf("<input type=hidden name=hscale id=hscale value=%s>\n", scalestr.c_str());
11705 scale = time_to_sec(scalestr.c_str());
11706 }
11707 }
11708
11709 if (endtime != 0)
11710 r->rsprintf("<input type=hidden name=htime id=htime value=%s>\n", time_to_string(endtime).c_str());
11711 if (pwidth && *pwidth)
11712 r->rsprintf("<input type=hidden name=hwidth id=hwidth value=%s>\n", pwidth);
11713 if (pheight && *pheight)
11714 r->rsprintf("<input type=hidden name=hheight id=hheight value=%s>\n", pheight);
11715 if (pindex && *pindex)
11716 r->rsprintf("<input type=hidden name=hindex id=hindex value=%s>\n", pindex);
11717
11718 r->rsprintf("</td></tr>\n");
11719
11720 if (hgroup[0] == 0) {
11721 /* "New" button */
11722 r->rsprintf("<tr><td colspan=2><input type=\"button\" name=\"New\" value=\"New\" ");
11723 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New'\"></td></tr>\n");
11724
11725 /* links for history panels */
11726 r->rsprintf("<tr><td colspan=2 style=\"text-align:left;\">\n");
11727 if (!hpanel[0])
11728 r->rsprintf("<b>Please select panel:</b><br>\n");
11729
11730 /* table for panel selection */
11731 r->rsprintf("<table class=\"historyTable\">");
11732
11733 /* "All" link */
11734 r->rsprintf("<tr><td colspan=2 class=\"titleCell\">\n");
11735 if (equal_ustring(hgroup, "All"))
11736 r->rsprintf("All &nbsp;&nbsp;");
11737 else
11738 r->rsprintf("<a href=\"?cmd=oldhistory&group=All\">ALL</a>\n");
11739 r->rsprintf("</td></tr>\n");
11740
11741 /* Setup History table links */
11742 db_find_key(hDB, 0, "/History/Display", &hkey);
11743 if (!hkey) {
11744 /* create default panel */
11745 char str[256];
11746 strcpy(str, "System:Trigger per sec.");
11747 strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11748 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables", str, 64, 2, TID_STRING);
11749 strcpy(str, "1h");
11750 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale", str, NAME_LENGTH, 1, TID_STRING);
11751
11752 strcpy(str, "1h");
11753 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale", str, NAME_LENGTH, 1, TID_STRING);
11754 i = 1;
11755 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11756 i = 1;
11757 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11758
11759 strcpy(str, "");
11760 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING);
11761 db_set_value_index(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING, FALSE);
11762 }
11763
11764 db_find_key(hDB, 0, "/History/Display", &hkey);
11765 if (hkey) {
11766 for (i = 0;; i++) {
11768
11769 if (!hkeyp)
11770 break;
11771
11772 // Group key
11773 db_get_key(hDB, hkeyp, &key);
11774
11775 char enc_name[256];
11776 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11777 urlEncode(enc_name, sizeof(enc_name));
11778
11780 r->rsprintf("<tr><td class=\"titleCell\">%s</td>\n<td>", key.name);
11781 else
11782 r->rsprintf("<tr><td class=\"titleCell\"><a href=\"?cmd=oldhistory&group=%s\">%s</a></td>\n<td>", enc_name, key.name);
11783
11784 for (j = 0;; j++) {
11785 // scan items
11787
11788 if (!hikeyp) {
11789 r->rsprintf("</tr>");
11790 break;
11791 }
11792 // Item key
11794
11795 char enc_iname[256];
11796 mstrlcpy(enc_iname, ikey.name, sizeof(enc_iname));
11797 urlEncode(enc_iname, sizeof(enc_iname));
11798
11799 if (equal_ustring(hpanel, ikey.name))
11800 r->rsprintf("<small><b>%s</b></small> &nbsp;", ikey.name);
11801 else
11802 r->rsprintf("<small><a href=\"?cmd=oldhistory&group=%s&panel=%s\">%s</a></small> &nbsp;\n", enc_name, enc_iname, ikey.name);
11803 }
11804 }
11805 }
11806
11807 r->rsprintf("</table></tr>\n");
11808
11809 } else {
11810 int found = 0;
11811
11812 /* show drop-down selectors */
11813 r->rsprintf("<tr><td colspan=2>\n");
11814
11815 r->rsprintf("Group:\n");
11816
11817 r->rsprintf("<select title=\"Select group\" id=\"fgroup\" onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value;\">\n");
11818
11819 db_find_key(hDB, 0, "/History/Display", &hkey);
11820 if (hkey) {
11821 hkeyp = 0;
11822 for (i = 0;; i++) {
11824
11825 if (!hikeyp)
11826 break;
11827
11828 if (i == 0)
11829 hkeyp = hikeyp;
11830
11831 // Group key
11833
11834 if (equal_ustring(key.name, hgroup)) {
11835 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11836 hkeyp = hikeyp;
11837 } else
11838 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11839 }
11840
11841 if (equal_ustring("ALL", hgroup)) {
11842 r->rsprintf("<option selected value=\"%s\">%s\n", "ALL", "ALL");
11843 } else {
11844 r->rsprintf("<option value=\"%s\">%s\n", "ALL", "ALL");
11845 }
11846
11847 r->rsprintf("</select>\n");
11848 r->rsprintf("&nbsp;&nbsp;Panel:\n");
11849 r->rsprintf("<select title=\"Select panel\" id=\"fpanel\" ");
11850 r->rsprintf("onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value+");
11851 r->rsprintf("'&panel='+document.getElementById('fpanel').value;\">\n");
11852
11853 found = 0;
11854 if (hkeyp) {
11855 for (i = 0;; i++) {
11856 // scan panels
11858
11859 if (!hikeyp)
11860 break;
11861
11862 // Item key
11864
11865 if (equal_ustring(hpanel, key.name)) {
11866 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11867 found = 1;
11868 } else
11869 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11870 }
11871 }
11872
11873 if (found)
11874 r->rsprintf("<option value=\"\">- all -\n");
11875 else
11876 r->rsprintf("<option selected value=\"\">- all -\n");
11877
11878 r->rsprintf("</select>\n");
11879 }
11880
11881 r->rsprintf("<noscript>\n");
11882 r->rsprintf("<input type=submit value=\"Go\">\n");
11883 r->rsprintf("</noscript>\n");
11884
11885 r->rsprintf("&nbsp;&nbsp;<input type=\"button\" name=\"New\" value=\"New\" ");
11886 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New&group=%s'\">\n", hgroup);
11887
11888 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Reset\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Reset&group=%s&panel=%s'\">\n", hgroup, hpanel);
11889
11890 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Query\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Query&group=%s&panel=%s'\">\n", hgroup, hpanel);
11891
11892 double xendtime = endtime;
11893 if (xendtime == 0)
11894 xendtime = now;
11895 double xstarttime = xendtime - scale;
11896
11897 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);
11898
11899 r->rsprintf("</td></tr>\n");
11900 }
11901
11902 //printf("hgroup [%s] hpanel [%s]\n", hgroup, hpanel);
11903
11904 /* check if whole group should be displayed */
11905 if (hgroup[0] && !equal_ustring(hgroup, "ALL") && hpanel[0] == 0) {
11906 std::string strwidth = "Small";
11907 db_get_value_string(hDB, 0, "/History/Display Settings/Width Group", 0, &strwidth, TRUE);
11908
11909 std::string path;
11910 path += "/History/Display/";
11911 path += hgroup;
11912 db_find_key(hDB, 0, path.c_str(), &hkey);
11913 if (hkey) {
11914 for (i = 0 ;; i++) { // scan group
11916
11917 if (!hikeyp)
11918 break;
11919
11921
11922 char enc_name[256];
11923 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11924 urlEncode(enc_name, sizeof(enc_name));
11925
11926 std::string ref;
11927 ref += "graph.gif?width=";
11928 ref += strwidth;
11929 ref += "&cmd=oldhistory&group=";
11930 ref += hgroup;
11931 ref += "&panel=";
11932 ref += enc_name;
11933
11934 std::string ref2;
11935 ref2 += "?cmd=oldhistory&group=";
11936 ref2 += hgroup;
11937 ref2 += "&panel=";
11938 ref2 += enc_name;
11939
11940 if (endtime != 0) {
11941 char tmp[256];
11942 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
11943 ref += "&";
11944 ref += tmp;
11945 ref2 += "?";
11946 ref2 += tmp;
11947 }
11948
11949 if (i % 2 == 0)
11950 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
11951 else
11952 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
11953 }
11954
11955 } else {
11956 r->rsprintf("Group \"%s\" not found", hgroup);
11957 }
11958 }
11959
11960 /* image panel */
11961 else if (hpanel[0] && !equal_ustring(hpanel, "All")) {
11962 /* navigation links */
11963 r->rsprintf("<tr><td>\n");
11964
11965 std::string path;
11966 path += "/History/Display/";
11967 path += hgroup;
11968 path += "/";
11969 path += hpanel;
11970 path += "/Buttons";
11971 db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11972 if (hkeybutton == 0) {
11973 /* create default buttons */
11974 db_create_key(hDB, 0, path.c_str(), TID_STRING);
11975 status = db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11976 if (status != DB_SUCCESS || !hkey) {
11977 cm_msg(MERROR, "show_hist_page", "Cannot create history panel with invalid ODB path \"%s\"", path.c_str());
11978 return;
11979 }
11981 }
11982
11983 r->rsprintf("<script>\n");
11984 r->rsprintf("function histDisp(p) {\n");
11985 r->rsprintf(" var params = '?cmd=oldhistory&group=%s&panel=%s';\n", hgroup, hpanel);
11986 r->rsprintf(" params += '&'+p;\n");
11987 r->rsprintf(" if (document.getElementById(\'hscale\') !== null)\n");
11988 r->rsprintf(" params += '&hscale='+document.getElementById(\'hscale\').value;\n");
11989 r->rsprintf(" if (document.getElementById(\'htime\') !== null)\n");
11990 r->rsprintf(" params += '&htime='+document.getElementById(\'htime\').value;\n");
11991 r->rsprintf(" if (document.getElementById(\'hwdith\') !== null)\n");
11992 r->rsprintf(" params += '&hwidth='+document.getElementById(\'hwidth\').value;\n");
11993 r->rsprintf(" if (document.getElementById(\'hindex\') !== null)\n");
11994 r->rsprintf(" params += '&hindex='+document.getElementById(\'hindex\').value;\n");
11995 r->rsprintf(" window.location.search = params;\n");
11996 r->rsprintf("}\n\n");
11997 r->rsprintf("</script>\n");
11998
12000
12001 for (i = 0; i < key.num_values; i++) {
12002 char str[256];
12003 size = sizeof(str);
12005 r->rsprintf("<input type=\"button\" title=\"display last %s\" value=%s onclick=\"histDisp('scale=%s')\">\n", str, str, str);
12006 }
12007
12008 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')\">");
12009 r->rsprintf("<input type=\"button\" value=\"<<\" title=\"go back in time to last available data\" onclick=\"histDisp('shift=leftmax')\">");
12010 r->rsprintf("<input type=\"button\" value=\"<\" title=\"go back in time\" onclick=\"histDisp('shift=left')\">");
12011
12012 r->rsprintf("<input type=\"button\" value=\" + \" title=\"zoom in\" onclick=\"histDisp('shift=zoomin')\">");
12013 r->rsprintf("<input type=\"button\" value=\" - \" title=\"zoom out\" onclick=\"histDisp('shift=zoomout')\">");
12014
12015 if (endtime != 0) {
12016 r->rsprintf("<input type=\"button\" value=\">\" title=\"go forward in time\" onclick=\"histDisp('shift=right')\">");
12017 r->rsprintf("<input type=\"button\" value=\">>\" title=\"go to currently updated fresh data\" onclick=\"histDisp('shift=rightmax')\">");
12018 }
12019
12020 r->rsprintf("<td>\n");
12021 r->rsprintf("<input type=\"button\" value=\"Large\" title=\"large display\" onclick=\"histDisp('width=Large')\">\n");
12022 r->rsprintf("<input type=\"button\" value=\"Small\" title=\"large display\" onclick=\"histDisp('width=Small')\">\n");
12023 r->rsprintf("<input type=\"button\" value=\"Create Elog\" title=\"large display\" onclick=\"histDisp('hcmd=Create Elog')\">\n");
12024 r->rsprintf("<input type=\"button\" value=\"Config\" title=\"large display\" onclick=\"histDisp('hcmd=Config')\">\n");
12025 r->rsprintf("<input type=\"button\" value=\"Export\" title=\"large display\" onclick=\"histDisp('hcmd=Export')\">\n");
12026 r->rsprintf("</tr>\n");
12027
12028 char paramstr[256];
12029
12030 paramstr[0] = 0;
12031 sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12032 if (endtime != 0)
12034 if (pwidth && *pwidth)
12035 sprintf(paramstr + strlen(paramstr), "&width=%s", pwidth);
12036 else {
12037 std::string wi = "640";
12038 db_get_value_string(hDB, 0, "/History/Display Settings/Width Individual", 0, &wi, TRUE);
12039 sprintf(paramstr + strlen(paramstr), "&width=%s", wi.c_str());
12040 }
12041 if (pheight && *pheight)
12042 sprintf(paramstr + strlen(paramstr), "&height=%s", pheight);
12043
12044 /* define image map */
12045 r->rsprintf("<map name=\"%s\">\r\n", hpanel);
12046
12047 if (!(pindex && *pindex)) {
12048 std::string path;
12049 path += "/History/Display/";
12050 path += hgroup;
12051 path += "/";
12052 path += hpanel;
12053 path += "/Variables";
12054 db_find_key(hDB, 0, path.c_str(), &hkey);
12055 if (hkey) {
12056 db_get_key(hDB, hkey, &key);
12057
12058 for (i = 0; i < key.num_values; i++) {
12059 std::string ref;
12060 //if (paramstr[0]) {
12061 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&%s&index=%d", hgroup, hpanel, paramstr, i);
12062 //} else {
12063 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&index=%d", hgroup, hpanel, i);
12064 //}
12065
12066 ref += "?cmd=oldhistory&group=";
12067 ref += hgroup;
12068 ref += "&panel=";
12069 ref += hpanel;
12070 if (paramstr[0]) {
12071 ref += "&";
12072 ref += paramstr;
12073 }
12074 ref += "&index=";
12075 ref += toString(i);
12076
12077 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());
12078 }
12079 }
12080 } else {
12081 std::string ref = "?cmd=oldhistory&group=";
12082 ref += hgroup;
12083 ref += "&panel=";
12084 ref += hpanel;
12085
12086 if (paramstr[0]) {
12087 ref += "&";
12088 ref += paramstr;
12089 }
12090
12091 if (equal_ustring(pwidth, "Large"))
12092 width = 1024;
12093 else if (equal_ustring(pwidth, "Small"))
12094 width = 320;
12095 else if (atoi(pwidth) > 0)
12096 width = atoi(pwidth);
12097 else
12098 width = 640;
12099
12100 r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 0, 0, width, 20, ref.c_str());
12101 }
12102
12103 r->rsprintf("</map>\r\n");
12104
12105 /* Display individual panels */
12106 if (pindex && *pindex)
12107 sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12108
12109 std::string ref;
12110 //sprintf(ref, "graph.gif?cmd=oldhistory&group=%s&panel=%s%s", hgroup, hpanel, paramstr);
12111 ref += "graph.gif?cmd=oldhistory&group=";
12112 ref += hgroup;
12113 ref += "&panel=";
12114 ref += hpanel;
12115 ref += paramstr;
12116
12117 /* put reference to graph */
12118 r->rsprintf("<tr><td colspan=2><img src=\"%s\" usemap=\"#%s\"></tr>\n", ref.c_str(), hpanel);
12119 }
12120
12121 else if (equal_ustring(hgroup, "All")) {
12122 /* Display all panels */
12123 db_find_key(hDB, 0, "/History/Display", &hkey);
12124 if (hkey)
12125 for (i = 0, k = 0;; i++) { // scan Groups
12127
12128 if (!hkeyp)
12129 break;
12130
12131 db_get_key(hDB, hkeyp, &key);
12132
12133 char enc_group_name[256];
12136
12137 for (j = 0;; j++, k++) {
12138 // scan items
12140
12141 if (!hikeyp)
12142 break;
12143
12145
12146 char enc_panel_name[256];
12149
12150 std::string ref;
12151 ref += "graph.gif?width=Small";
12152 ref += "&cmd=oldhistory&group=";
12154 ref += "&panel=";
12156
12157 std::string ref2;
12158 ref2 += "?cmd=oldhistory&group=";
12160 ref2 += "&panel=";
12162
12163 if (endtime != 0) {
12164 char tmp[256];
12165 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
12166 ref += "&";
12167 ref += tmp;
12168 ref2 += "&";
12169 ref2 += tmp;
12170 }
12171
12172 if (k % 2 == 0)
12173 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
12174 else
12175 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
12176 } // items loop
12177 } // Groups loop
12178 } // All
12179 r->rsprintf("</table>\r\n");
12180 r->rsprintf("</div>\n"); // closing for <div id="mmain">
12181 r->rsprintf("</form>\n");
12182 r->rsprintf("</body></html>\r\n");
12183}
12184
12185
12186/*------------------------------------------------------------------*/
12187
12188void send_icon(Return* r, const char *icon)
12189{
12190 int length;
12191 const unsigned char *picon;
12192 char str[256], format[256];
12193 time_t now;
12194
12195 if (strstr(icon, "favicon.ico") != 0) {
12196 length = sizeof(favicon_ico);
12198 } else if (strstr(icon, "favicon.png") != 0) {
12199 length = sizeof(favicon_png);
12201 } else
12202 return;
12203
12204 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
12205 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12206 r->rsprintf("Accept-Ranges: bytes\r\n");
12207
12208 /* set expiration time to one day */
12209 time(&now);
12210 now += (int) (3600 * 24);
12211 struct tm gmt_tms;
12212 gmtime_r(&now, &gmt_tms);
12213 strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12214 strftime(str, sizeof(str), format, &gmt_tms);
12215 r->rsprintf("Expires: %s\r\n", str);
12216
12217 if (equal_ustring(icon, "favicon.ico"))
12218 r->rsprintf("Content-Type: image/x-icon\r\n");
12219 else
12220 r->rsprintf("Content-Type: image/png\r\n");
12221
12222 r->rsprintf("Content-Length: %d\r\n\r\n", length);
12223
12224 r->rmemcpy(picon, length);
12225}
12226
12227/*------------------------------------------------------------------*/
12228
12230{
12231 std::string cookie_pwd;
12232 std::string cookie_wpwd;
12233 std::string cookie_cpwd;
12234 int refresh = 0;
12235 //int expand_equipment = 0;
12236};
12237
12238/*------------------------------------------------------------------*/
12239
12241{
12242 gMutex.lock();
12243 t->fTimeLocked = GetTimeSec();
12244}
12245
12247{
12249 gMutex.unlock();
12250}
12251
12252/*------------------------------------------------------------------*/
12253
12254void interprete(Param* p, Return* r, Attachment* a, const Cookies* c, const char *dec_path, RequestTrace* t)
12255/********************************************************************\
12256
12257 Routine: interprete
12258
12259 Purpose: Main interpreter of web commands
12260
12261 \********************************************************************/
12262{
12263 int status;
12264 HNDLE hkey, hDB;
12265
12266 //printf("dec_path [%s]\n", dec_path);
12267
12268 if (strstr(dec_path, "favicon.ico") != 0 ||
12269 strstr(dec_path, "favicon.png")) {
12270 send_icon(r, dec_path);
12271 return;
12272 }
12273
12274 const char* password = p->getparam("pwd");
12275 const char* wpassword = p->getparam("wpwd");
12276 const char* command = p->getparam("cmd");
12277
12278 //printf("interprete: dec_path [%s], command [%s]\n", dec_path, command);
12279
12281 MVOdb* odb = gOdb;
12282
12283 if (history_mode) {
12284 if (equal_ustring(command, "history")) {
12285 if (equal_ustring(command, "config")) {
12286 return;
12287 }
12288
12289 Lock(t);
12290 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12291 Unlock(t);
12292 return;
12293 }
12294 return;
12295 }
12296
12297 /* check for password */
12298 db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12299 if (!password[0] && hkey) {
12300 char str[256];
12301 int size = sizeof(str);
12302 db_get_data(hDB, hkey, str, &size, TID_STRING);
12303
12304 /* check for excemption */
12305 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12306 if (hkey == 0 && strcmp(c->cookie_pwd.c_str(), str) != 0) {
12307 Lock(t);
12309 Unlock(t);
12310 return;
12311 }
12312 }
12313
12314 /*---- redirect with cookie if password given --------------------*/
12315
12316 if (password[0]) {
12317 r->rsprintf("HTTP/1.1 302 Found\r\n");
12318 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12319
12320 time_t now;
12321 time(&now);
12322
12323 now += 3600 * 24;
12324
12325 struct tm gmt_tms;
12326 gmtime_r(&now, &gmt_tms);
12327
12328 char str[256];
12329 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12330
12331 r->rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12332 ss_crypt(password, "mi"), str);
12333
12334 r->rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12335 return;
12336 }
12337
12338 if (wpassword[0]) {
12339 /* check if password correct */
12340 if (!check_web_password(r, hDB, dec_path, ss_crypt(wpassword, "mi"), p->getparam("redir")))
12341 return;
12342
12343 r->rsprintf("HTTP/1.1 302 Found\r\n");
12344 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12345
12346 time_t now;
12347 time(&now);
12348
12349 now += 3600 * 24;
12350
12351 struct tm gmt_tms;
12352 gmtime_r(&now, &gmt_tms);
12353
12354 char str[256];
12355 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", &gmt_tms);
12356
12357 r->rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", ss_crypt(wpassword, "mi"), str);
12358
12359 sprintf(str, "./%s", p->getparam("redir"));
12360 r->rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12361 return;
12362 }
12363
12364 /*---- send sound file -------------------------------------------*/
12365
12366 if (strlen(dec_path) > 3 &&
12367 dec_path[strlen(dec_path)-3] == 'm' &&
12368 dec_path[strlen(dec_path)-2] == 'p' &&
12369 dec_path[strlen(dec_path)-1] == '3') {
12370 if (strrchr(dec_path, '/'))
12371 send_resource(r, strrchr(dec_path, '/')+1);
12372 else
12374 return;
12375 }
12376
12377 /*---- send midas.js and midas.css -------------------------------*/
12378
12379 if (strstr(dec_path, "midas.js")) {
12380 send_resource(r, "midas.js");
12381 return;
12382 }
12383
12384 if (strstr(dec_path, "midas.css")) {
12385 send_resource(r, "midas.css");
12386 return;
12387 }
12388
12389 /*---- send mhttpd.js --------------------------------------------*/
12390
12391 if (strstr(dec_path, "mhttpd.js")) {
12392 send_resource(r, "mhttpd.js");
12393 return;
12394 }
12395
12396 /*---- send obsolete.js ------------------------------------------*/
12397
12398 if (strstr(dec_path, "obsolete.js")) {
12399 send_resource(r, "obsolete.js");
12400 return;
12401 }
12402
12403 /*---- send the obsolete mhttpd.css ------------------------------*/
12404
12405 if (strstr(dec_path, "mhttpd.css")) {
12406 send_resource(r, "mhttpd.css");
12407 return;
12408 }
12409
12410 /*---- send controls.js ------------------------------------------*/
12411
12412 if (strstr(dec_path, "controls.js")) {
12413 send_resource(r, "controls.js");
12414 return;
12415 }
12416
12417 /*---- send example web page -------------------------------------*/
12418
12419 if (equal_ustring(command, "example")) {
12420 send_resource(r, "example.html");
12421 return;
12422 }
12423
12424 /*---- send example custom page -------------------------------------*/
12425
12426 if (equal_ustring(command, "custom_example")) {
12427 send_resource(r, "custom_example.html");
12428 return;
12429 }
12430
12431 if (equal_ustring(command, "plot_example")) {
12432 send_resource(r, "plot_example.html");
12433 return;
12434 }
12435
12436 /*---- script command --------------------------------------------*/
12437
12438 if (p->getparam("script") && *p->getparam("script")) {
12439
12440 std::string str = msprintf("%s?script=%s", dec_path, p->getparam("script"));
12441 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12442 return;
12443
12444 std::string path;
12445 path += "/Script/";
12446 path += p->getparam("script");
12447
12448 Lock(t);
12449
12450 cm_exec_script(path.c_str());
12451
12452 Unlock(t);
12453
12454 if (p->isparam("redir"))
12455 redirect2(r, p->getparam("redir"));
12456 else
12457 redirect2(r, "");
12458
12459 return;
12460 }
12461
12462 /*---- customscript command --------------------------------------*/
12463
12464 if (p->getparam("customscript") && *p->getparam("customscript")) {
12465
12466 std::string str = msprintf("%s?customscript=%s", dec_path, p->getparam("customscript"));
12467 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12468 return;
12469
12470 std::string path;
12471 path += "/CustomScript/";
12472 path += p->getparam("customscript");
12473
12474 Lock(t);
12475
12476 cm_exec_script(path.c_str());
12477
12478 Unlock(t);
12479
12480 if (p->isparam("redir"))
12481 redirect2(r, p->getparam("redir"));
12482 else
12483 redirect2(r, str.c_str());
12484
12485 return;
12486 }
12487
12488 /*---- send the new html pages -----------------------------------*/
12489
12490 if (equal_ustring(command, "start")) {
12491 send_resource(r, "start.html");
12492 return;
12493 }
12494
12495 if ((equal_ustring(command, "") || equal_ustring(command, "status")) && strlen(dec_path) == 0) {
12496 if (midas::odb::exists("/Custom/Status")) {
12497 midas::odb custom("/Custom");
12498
12499 std::string filename = custom["Status"];
12500 filename = add_custom_path(filename);
12501
12502 // if custom file exists, send it (like normal web server)
12503 if (ss_file_exist(filename.c_str())) {
12504 send_file(r, filename);
12505 return;
12506 }
12507 } else
12508 send_resource(r, "status.html");
12509 return;
12510 }
12511
12512 if (equal_ustring(command, "eqtable")) {
12513 send_resource(r, "eqtable.html");
12514 return;
12515 }
12516
12517 if (equal_ustring(command, "newODB")) {
12518 send_resource(r, "odb.html");
12519 return;
12520 }
12521
12522 if (equal_ustring(command, "programs")) {
12523 send_resource(r, "programs.html");
12524 return;
12525 }
12526
12527 if (equal_ustring(command, "alarms")) {
12528 send_resource(r, "alarms.html");
12529 return;
12530 }
12531
12532 if (equal_ustring(command, "transition")) {
12533 send_resource(r, "transition.html");
12534 return;
12535 }
12536
12537 if (equal_ustring(command, "messages")) {
12538 send_resource(r, "messages.html");
12539 return;
12540 }
12541
12542 if (equal_ustring(command, "config") &&
12543 !(dec_path[0] == 'H' && dec_path[1] == 'S' && dec_path[2] == '/')) {
12544 send_resource(r, "config.html");
12545 return;
12546 }
12547
12548 if (equal_ustring(command, "chat")) {
12549 send_resource(r, "chat.html");
12550 return;
12551 }
12552
12553 if (equal_ustring(command, "buffers")) {
12554 send_resource(r, "buffers.html");
12555 return;
12556 }
12557
12558 if (equal_ustring(command, "Show elog")) {
12559 send_resource(r, "elog_show.html");
12560 return;
12561 }
12562
12563 if (equal_ustring(command, "Query elog")) {
12564 send_resource(r, "elog_query_form.html");
12565 return;
12566 }
12567
12568 if (equal_ustring(command, "New elog")) {
12569 send_resource(r, "elog_edit.html");
12570 return;
12571 }
12572
12573 if (equal_ustring(command, "Edit elog")) {
12574 send_resource(r, "elog_edit.html");
12575 return;
12576 }
12577
12578 if (equal_ustring(command, "Reply Elog")) {
12579 send_resource(r, "elog_edit.html");
12580 return;
12581 }
12582
12583 if (equal_ustring(command, "Last elog")) {
12584 send_resource(r, "elog_show.html");
12585 return;
12586 }
12587
12588 if (equal_ustring(command, "Submit Query")) {
12589 send_resource(r, "elog_query.html");
12590 return;
12591 }
12592
12593 if (equal_ustring(dec_path, "spinning-wheel.gif")) {
12594 send_resource(r, "spinning-wheel.gif");
12595 return;
12596 }
12597
12598 /*---- java script commands --------------------------------------*/
12599
12600 if (equal_ustring(command, "jset") ||
12601 equal_ustring(command, "jget") ||
12602 equal_ustring(command, "jcopy") ||
12603 equal_ustring(command, "jpaste") ||
12604 equal_ustring(command, "jkey") ||
12605 equal_ustring(command, "jcreate") ||
12606 equal_ustring(command, "jresize") ||
12607 equal_ustring(command, "jlink") ||
12608 equal_ustring(command, "jrename") ||
12609 equal_ustring(command, "jreorder") ||
12610 equal_ustring(command, "jdelete") ||
12611 equal_ustring(command, "jmsg") ||
12612 equal_ustring(command, "jalm") ||
12613 equal_ustring(command, "jgenmsg") ||
12614 equal_ustring(command, "jrpc_rev0") ||
12615 equal_ustring(command, "jrpc_rev1") ||
12616 equal_ustring(command, "jrpc")) {
12617 Lock(t);
12618 javascript_commands(p, r, c->cookie_cpwd.c_str());
12619 Unlock(t);
12620 return;
12621 }
12622
12623 /*---- history editord -------------------------------------------*/
12624
12625 if (equal_ustring(command, "hs_edit")) {
12626 send_resource(r, "hs_edit.html");
12627 return;
12628 }
12629
12630 /*---- history command -------------------------------------------*/
12631
12632 if (equal_ustring(command, "oldhistory")) {
12633 Lock(t);
12634 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12635 Unlock(t);
12636 return;
12637 }
12638
12639 if (equal_ustring(command, "history")) {
12640 send_resource(r, "history.html");
12641 return;
12642 }
12643
12644 /*---- MSCB command ----------------------------------------------*/
12645
12646 if (equal_ustring(command, "MSCB")) {
12647 if (equal_ustring(command, "set")) {
12648 std::string str;
12649 str += dec_path;
12650 str += "?";
12651 str += add_param_to_url("cmd", command);
12652 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12653 return;
12654 }
12655
12656 Lock(t);
12657
12658#ifdef HAVE_MSCB
12659 show_mscb_page(p, r, c->refresh);
12660#else
12661 show_error(r, "MSCB support not compiled into this version of mhttpd");
12662#endif
12663
12664 Unlock(t);
12665 return;
12666 }
12667
12668 /*---- help command ----------------------------------------------*/
12669
12670 if (equal_ustring(command, "help")) {
12671 Lock(t);
12673 Unlock(t);
12674 return;
12675 }
12676
12677 /*---- trigger equipment readout ---------------------------*/
12678
12679 if (strncmp(command, "Trigger", 7) == 0) {
12680 std::string cmd;
12681 cmd += "?cmd=";
12682 cmd += command;
12683 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), cmd.c_str())) {
12684 return;
12685 }
12686
12687 Lock(t);
12688
12689 /* extract equipment name */
12690 char eq_name[NAME_LENGTH];
12691
12692 mstrlcpy(eq_name, command + 8, sizeof(eq_name));
12693 if (strchr(eq_name, ' '))
12694 *strchr(eq_name, ' ') = 0;
12695
12696 /* get frontend name */
12697 std::string path;
12698 path += "/Equipment/";
12699 path += eq_name;
12700 path += "/Common/Frontend name";
12701 char fe_name[NAME_LENGTH];
12702 int size = NAME_LENGTH;
12703 db_get_value(hDB, 0, path.c_str(), fe_name, &size, TID_STRING, TRUE);
12704
12705 /* and ID */
12706 path = "";
12707 path += "/Equipment/";
12708 path += eq_name;
12709 path += "/Common/Event ID";
12710 WORD event_id = 0;
12711 size = sizeof(event_id);
12712 db_get_value(hDB, 0, path.c_str(), &event_id, &size, TID_WORD, TRUE);
12713
12714 if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12715 std::string str;
12716 str += "Frontend \"";
12717 str += fe_name;
12718 str += "\" not running!";
12719 show_error(r, str.c_str());
12720 } else {
12721 HNDLE hconn;
12723 if (status != RPC_SUCCESS) {
12724 std::string str;
12725 str += "Cannot connect to frontend \"";
12726 str += fe_name;
12727 str +="\" !";
12728 show_error(r, str.c_str());
12729 } else {
12731 if (status != CM_SUCCESS)
12732 show_error(r, "Error triggering event");
12733 else
12734 redirect(r, "");
12735
12736 //cm_disconnect_client(hconn, FALSE);
12737 }
12738 }
12739
12740 Unlock(t);
12741
12742 return;
12743 }
12744
12745 /*---- switch to next subrun -------------------------------------*/
12746
12747 if (strncmp(command, "Next Subrun", 11) == 0) {
12748 int i = TRUE;
12749 db_set_value(hDB, 0, "/Logger/Next subrun", &i, sizeof(i), 1, TID_BOOL);
12750 redirect(r, "");
12751 return;
12752 }
12753
12754 /*---- cancel command --------------------------------------------*/
12755
12756 if (equal_ustring(command, "cancel")) {
12757 if (p->isparam("redir"))
12758 redirect(r, p->getparam("redir"));
12759 else
12760 redirect(r, "");
12761 return;
12762 }
12763
12764 /*---- set command -----------------------------------------------*/
12765
12766 if (equal_ustring(command, "set")) {
12767 char str[256];
12768 mstrlcpy(str, "?cmd=set", sizeof(str));
12769 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str))
12770 return;
12771
12772 const char* group = p->getparam("group");
12773 int index = atoi(p->getparam("index"));
12774 const char* value = p->getparam("value");
12775
12776 Lock(t);
12777 show_set_page(p, r, group, index, value);
12778 Unlock(t);
12779 return;
12780 }
12781
12782 /*---- find command ----------------------------------------------*/
12783
12784 if (equal_ustring(command, "find")) {
12785 const char* value = p->getparam("value");
12786 Lock(t);
12788 Unlock(t);
12789 return;
12790 }
12791
12792 /*---- CAMAC CNAF command ----------------------------------------*/
12793
12794 if (equal_ustring(command, "CNAF") || strncmp(dec_path, "CNAF", 4) == 0) {
12795 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), "?cmd=CNAF"))
12796 return;
12797
12798 Lock(t);
12799 show_cnaf_page(p, r);
12800 Unlock(t);
12801 return;
12802 }
12803
12804 /*---- ELog command ----------------------------------------------*/
12805
12806 if (equal_ustring(command, "elog")) {
12807 /* redirect to external ELOG if URL present */
12810 std::string external_elog_url;
12811 int size = sizeof(external_elog);
12812 status = db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
12813 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
12814 if (external_elog && (external_elog_url.length() > 0)) {
12815 redirect(r, external_elog_url.c_str());
12816 return;
12817 }
12818 send_resource(r, "elog_show.html");
12819 return;
12820 }
12821
12822 // special processing for "Elog last 7d", etc
12823
12824 char cmdx[32];
12825 mstrlcpy(cmdx, command, sizeof(cmdx));
12826 cmdx[9] = 0;
12827
12828 if (equal_ustring(cmdx, "Elog last")) {
12829 // "Elog last 7d", etc
12830 send_resource(r, "elog_query.html");
12831 return;
12832 }
12833
12834 if (equal_ustring(command, "Create ELog from this page")) {
12835 std::string redir;
12836 redir += "?cmd=New+elog";
12837 redir += "&odb_path=";
12838 redir += p->getparam("odb_path");
12839 redirect(r, redir.c_str());
12840 return;
12841 }
12842
12843 if (equal_ustring(command, "Submit elog")) {
12844 Lock(t);
12845 submit_elog(odb, p, r, a);
12846 Unlock(t);
12847 return;
12848 }
12849
12850 if (equal_ustring(command, "elog_att")) {
12851 Lock(t);
12853 Unlock(t);
12854 return;
12855 }
12856
12857 /*---- accept command --------------------------------------------*/
12858
12859 if (equal_ustring(command, "accept")) {
12860 int refresh = atoi(p->getparam("refr"));
12861
12862 /* redirect with cookie */
12863 r->rsprintf("HTTP/1.1 302 Found\r\n");
12864 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12865 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
12866
12867 time_t now;
12868 time(&now);
12869
12870 now += 3600 * 24 * 365;
12871
12872 struct tm gmt_tms;
12873 gmtime_r(&now, &gmt_tms);
12874
12875 char str[256];
12876 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12877
12878 r->rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
12879 r->rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
12880
12881 return;
12882 }
12883
12884 /*---- slow control display --------------------------------------*/
12885
12886 if (equal_ustring(command, "eqtable")) {
12887 Lock(t);
12888 show_eqtable_page(p, r, c->refresh);
12889 Unlock(t);
12890 return;
12891 }
12892
12893 /*---- sequencer page --------------------------------------------*/
12894
12895 if (equal_ustring(command, "Sequencer")) {
12896 send_resource(r, "sequencer.html");
12897 return;
12898 }
12899
12900 // obsolete
12901 if (equal_ustring(command, "seq")) {
12902 send_resource(r, "sequencer.html");
12903 return;
12904 }
12905
12906 if (equal_ustring(command, "start_script")) {
12907 send_resource(r, "start_script.html");
12908 return;
12909 }
12910
12911 if (equal_ustring(command, "load_script")) {
12912 send_resource(r, "load_script.html");
12913 return;
12914 }
12915
12916 if (equal_ustring(command, "edit_script")) {
12917 send_resource(r, "edit_script.html");
12918 return;
12919 }
12920
12921 /*---- show ODB --------------------------------------------------*/
12922
12923 if (equal_ustring(command, "oldOdb")) {
12924 int write_access = TRUE;
12925 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
12926 if (hkey) {
12927 char str[256];
12928 int size = sizeof(str);
12929 db_get_data(hDB, hkey, str, &size, TID_STRING);
12930 if (strcmp(c->cookie_wpwd.c_str(), str) == 0)
12932 else
12934 }
12935
12936 std::string odb_path;
12937 if (p->getparam("odb_path") && *p->getparam("odb_path"))
12938 odb_path = p->getparam("odb_path");
12939
12940 Lock(t);
12941 show_odb_page(p, r, odb_path.c_str(), write_access);
12942 Unlock(t);
12943 return;
12944 }
12945
12946 /*---- New ODB browser --------------------------------------------*/
12947
12948 if (equal_ustring(command, "odb")) {
12949 send_resource(r, "odb.html");
12950 return;
12951 }
12952
12953 /*---- ODB show open records --------------------------------------*/
12954
12955 if (equal_ustring(command, "odb_sor")) {
12956 send_resource(r, "odb_sor.html");
12957 return;
12958 }
12959
12960 /*---- ODB show clients -------------------------------------------*/
12961
12962 if (equal_ustring(command, "odb_scl")) {
12963 send_resource(r, "odb_scl.html");
12964 return;
12965 }
12966
12967 /*---- old ODB path ----------------------------------------------*/
12968
12969 if ((command[0]==0) && dec_path[0]) {
12970 if (equal_ustring(dec_path, "root")) {
12971 std::string new_url = "./?cmd=odb";
12972 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
12973 redirect_307(r, new_url.c_str());
12974 return;
12975 }
12976 }
12977
12978 if ((command[0]==0) && dec_path[0]) {
12979 HNDLE hkey;
12981 //printf("try odb path [%s], status %d\n", dec_path, status);
12982 if (status == DB_SUCCESS) {
12983 int level = 0;
12984 for (const char* s = dec_path; *s; s++) {
12985 if (*s == '/')
12986 level++;
12987 }
12988 std::string new_url;
12989 if (level == 0) {
12990 // Top-level directory like /Logger, (which appears in dec_path as "Logger")
12991 new_url += "./";
12992 } else {
12993 for (int i=0; i<level; i++) {
12994 if (i>0)
12995 new_url += "/";
12996 new_url += "..";
12997 }
12998 }
12999 new_url += "?cmd=odb";
13000 new_url += "&odb_path=";
13002 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13003 redirect_307(r, new_url.c_str());
13004 return;
13005 }
13006 }
13007
13008 /*---- event dump ------------------------------------------------*/
13009
13010 if (equal_ustring(command, "event dump")) {
13011 send_resource(r, "event_dump.html");
13012 return;
13013 }
13014
13015 /*---- custom page -----------------------------------------------*/
13016
13017 if (equal_ustring(command, "custom")) {
13018 Lock(t);
13019 show_custom_page(p, r, c->cookie_cpwd.c_str());
13020 Unlock(t);
13021 return;
13022 }
13023
13024 /*---- custom page accessed by direct URL that used to be under /CS/... ----*/
13025
13026 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13027 std::string odb_path;
13028 std::string value;
13029 int status;
13030
13031 odb_path = "";
13032 odb_path += "/Custom/Images/";
13033 odb_path += dec_path;
13034 odb_path += "/Background";
13035
13036 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13037
13038 //printf("Try custom gif [%s] status %d\n", odb_path.c_str(), status);
13039
13040 if (status == DB_SUCCESS) {
13041 if (strstr(dec_path, "..")) {
13042 std::string str;
13043 str += "Invalid custom gif name \'";
13044 str += dec_path;
13045 str += "\' contains \'..\'";
13046 show_error_404(r, str.c_str());
13047 return;
13048 }
13049
13050 Lock(t);
13052 Unlock(t);
13053 return;
13054 }
13055
13056 bool found_custom = false;
13057
13058 odb_path = "";
13059 odb_path += "/Custom/";
13060 odb_path += dec_path;
13061
13062 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13063
13064 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13065
13066 if (status == DB_SUCCESS) {
13067 found_custom = true;
13068 } else {
13069 odb_path = "";
13070 odb_path += "/Custom/";
13071 odb_path += dec_path;
13072 odb_path += "&";
13073
13074 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13075
13076 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13077
13078 if (status == DB_SUCCESS) {
13079 found_custom = true;
13080 } else {
13081 odb_path = "";
13082 odb_path += "/Custom/";
13083 odb_path += dec_path;
13084 odb_path += "!";
13085
13086 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13087
13088 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13089
13090 if (status == DB_SUCCESS) {
13091 found_custom = true;
13092 }
13093 }
13094 }
13095
13096 if (found_custom) {
13097 //printf("custom file: serving [%s] value [%s]\n", dec_path, value.c_str());
13098 if (strstr(dec_path, "..")) {
13099 std::string str;
13100 str += "Invalid custom page name \'";
13101 str += dec_path;
13102 str += "\' contains \'..\'";
13103 show_error_404(r, str.c_str());
13104 return;
13105 }
13106
13107 p->setparam("page", dec_path);
13108 Lock(t);
13109 show_custom_page(p, r, c->cookie_cpwd.c_str());
13110 Unlock(t);
13111 return;
13112 }
13113 }
13114
13115 /* new custom pages */
13116 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13117 std::string custom_path;
13118 status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
13119 if ((status == DB_SUCCESS) && (custom_path.length() > 0)) {
13120 if (strstr(dec_path, "..")) {
13121 std::string str;
13122 str += "Invalid custom file name \'";
13123 str += dec_path;
13124 str += "\' contains \'..\'";
13125 show_error_404(r, str.c_str());
13126 return;
13127 }
13128
13129 std::string full_filename = add_custom_path(dec_path);
13130
13131 // if custom file exists, send it (like normal web server)
13132 if (ss_file_exist(full_filename.c_str())) {
13134 return;
13135 }
13136 }
13137 }
13138
13139 /*---- redirect if web page --------------------------------------*/
13140
13141 //if (strlen(command) > 0) {
13142 // if (send_resource(r, std::string(command) + ".html", false))
13143 // return;
13144 //}
13145
13146 /*---- serve url as a resource file ------------------------------*/
13147
13148 if (strlen(p->getparam("path")) > 0) {
13149 if (send_resource(r, p->getparam("path"), false)) {
13150 return;
13151 }
13152 }
13153
13154 /*---- show status -----------------------------------------------*/
13155
13156 if (elog_mode) {
13157 redirect(r, "EL/");
13158 return;
13159 }
13160
13161 /* header */
13162 r->rsprintf("HTTP/1.1 400 Bad Request\r\n");
13163 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
13164 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
13165 r->rsprintf("\r\n");
13166 r->rsprintf("Error: Invalid URL \"%s\" or query \"%s\" or command \"%s\"\n", p->getparam("path"), p->getparam("query"), command);
13167}
13168
13169/*------------------------------------------------------------------*/
13170
13171void decode_query(Param* pp, const char *query_string)
13172{
13173 int len = strlen(query_string);
13174 char *buf = (char *)malloc(len+1);
13175 memcpy(buf, query_string, len+1);
13176 char* p = buf;
13177 p = strtok(p, "&");
13178 while (p != NULL) {
13179 char *pitem = p;
13180 p = strchr(p, '=');
13181 if (p != NULL) {
13182 *p++ = 0;
13183 urlDecode(pitem); // parameter name
13184 if (!equal_ustring(pitem, "format"))
13185 urlDecode(p); // parameter value
13186
13187 pp->setparam(pitem, p); // decoded query parameters
13188
13189 p = strtok(NULL, "&");
13190 }
13191 }
13192 free(buf);
13193}
13194
13195void decode_get(Return* rr, char *string, const Cookies* c, const char* url, const char* query_string, RequestTrace* t)
13196{
13197 char path[256];
13198
13199 //printf("decode_get: string [%s], decode_url %d, url [%s], query_string [%s]\n", string, decode_url, url, query_string);
13200
13201 Param* param = new Param();
13202
13203 param->initparam();
13204
13205 if (url)
13206 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13207 else {
13208 mstrlcpy(path, string + 1, sizeof(path)); /* strip leading '/' */
13209
13210 if (strchr(path, '?'))
13211 *strchr(path, '?') = 0;
13212 }
13213
13214 param->setparam("path", path);
13215
13216 assert(query_string != NULL);
13217
13218 decode_query(param, query_string);
13219
13220 param->setparam("query", query_string);
13221
13222 char dec_path[256];
13223 mstrlcpy(dec_path, path, sizeof(dec_path));
13224
13225 interprete(param, rr, NULL, c, dec_path, t);
13226
13227 param->freeparam();
13228 delete param;
13229}
13230
13231/*------------------------------------------------------------------*/
13232
13233void decode_post(Return* rr, const char *header, const char *string, const char *boundary, int length, const Cookies* c, const char* url, RequestTrace* t)
13234{
13235 bool debug_decode_post = false;
13236
13237 Param* param = new Param;
13238
13239 param->initparam();
13240
13241 char path[256];
13242
13243 if (url)
13244 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13245 else {
13246 mstrlcpy(path, header + 1, sizeof(path)); /* strip leading '/' */
13247 if (strchr(path, '?'))
13248 *strchr(path, '?') = 0;
13249 if (strchr(path, ' '))
13250 *strchr(path, ' ') = 0;
13251 }
13252 param->setparam("path", path); // undecoded path
13253
13254 Attachment* a = new Attachment;
13255
13256 const char* pinit = string;
13257
13258 /* return if no boundary defined */
13259 if (!boundary[0])
13260 return;
13261
13262 if (strstr(string, boundary))
13263 string = strstr(string, boundary) + strlen(boundary);
13264
13266 printf("decode_post: -->[%s]<--\n", string);
13267
13268 do {
13269 //printf("decode_post: [%s]\n", string);
13270 if (strstr(string, "name=")) {
13271 const char* pitem = strstr(string, "name=") + 5;
13272 if (*pitem == '\"')
13273 pitem++;
13274
13275 //printf("decode_post: pitem [%s]\n", pitem);
13276
13277 if (strncmp(pitem, "attfile", 7) == 0) {
13278 int n = pitem[7] - '1';
13279
13280 char file_name[256];
13281 file_name[0] = 0;
13282
13283 /* evaluate file attachment */
13284 if (strstr(pitem, "filename=")) {
13285 const char* p = strstr(pitem, "filename=") + 9;
13286 if (*p == '\"')
13287 p++;
13288 if (strstr(p, "\r\n\r\n"))
13289 string = strstr(p, "\r\n\r\n") + 4;
13290 else if (strstr(p, "\r\r\n\r\r\n"))
13291 string = strstr(p, "\r\r\n\r\r\n") + 6;
13292
13293 mstrlcpy(file_name, p, sizeof(file_name));
13294
13295 char* pp = file_name;
13296 if (strchr(pp, '\"'))
13297 *strchr(pp, '\"') = 0;
13298
13299 /* set attachment filename */
13300 char str[256];
13301 sprintf(str, "attachment%d", n);
13303 printf("decode_post: [%s] = [%s]\n", str, file_name);
13304 param->setparam(str, file_name); // file_name should be decoded?
13305 }
13306
13307 /* find next boundary */
13308 const char* ptmp = string;
13309 const char* p = NULL;
13310 do {
13311 while (*ptmp != '-')
13312 ptmp++;
13313
13314 p = strstr(ptmp, boundary);
13315 if (p != NULL) {
13316 while (*p == '-')
13317 p--;
13318 if (*p == 10)
13319 p--;
13320 if (*p == 13)
13321 p--;
13322 p++;
13323 break;
13324 } else
13325 ptmp += strlen(ptmp);
13326
13327 } while (TRUE);
13328
13329 /* save pointer to file */
13330 if (file_name[0]) {
13331 size_t size = (POINTER_T) p - (POINTER_T) string;
13332 char* buf = (char*)malloc(size+1);
13333 if (!buf) {
13334 return;
13335 }
13336 memcpy(buf, string, size);
13337 buf[size] = 0; // make sure string is NUL terminated
13338 a->attachment_buffer[n] = buf;
13339 a->attachment_size[n] = size;
13341 printf("decode_post: attachment[%d] size %d data --->[%s]<---\n", n, (int)a->attachment_size[n], a->attachment_buffer[n]);
13342 }
13343
13344 string = strstr(p, boundary) + strlen(boundary);
13345 } else {
13346 const char* p = pitem;
13347 if (strstr(p, "\r\n\r\n"))
13348 p = strstr(p, "\r\n\r\n") + 4;
13349 else if (strstr(p, "\r\r\n\r\r\n"))
13350 p = strstr(p, "\r\r\n\r\r\n") + 6;
13351
13352 char* ppitem = (char*)strchr(pitem, '\"'); // NB: defeat "const char* string"
13353 if (ppitem)
13354 *ppitem = 0;
13355
13356 char* pb = (char*)(strstr(p, boundary)); // NB: defeat "const char* string"
13357 if (pb) {
13358 string = pb + strlen(boundary);
13359 *pb = 0;
13360 char* ptmp = (char*)(p + (strlen(p) - 1)); // NB: defeat "const char* string"
13361 while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13362 *ptmp-- = 0;
13363 } else {
13364 show_error(rr, "Invalid POST request");
13365 return;
13366 }
13368 printf("decode_post: [%s] = [%s]\n", pitem, p);
13369 param->setparam(pitem, p); // in decode_post()
13370 }
13371
13372 while (*string == '-' || *string == '\n' || *string == '\r')
13373 string++;
13374 }
13375
13376 } while ((POINTER_T) string - (POINTER_T) pinit < length);
13377
13378 char dec_path[256];
13379 mstrlcpy(dec_path, path, sizeof(dec_path));
13380
13381 interprete(param, rr, a, c, dec_path, t);
13382
13383 delete a;
13384 delete param;
13385}
13386
13387/*------------------------------------------------------------------*/
13388
13390{
13391 HNDLE hDB, hKeyEq, hKey;
13393 int i, status;
13394 KEY key;
13395
13396 /* check /Runinfo structure */
13398 assert(status == DB_SUCCESS);
13399
13400 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), FALSE);
13401 if (status == DB_STRUCT_MISMATCH) {
13402 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), TRUE);
13403 if (status == DB_SUCCESS) {
13404 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo corrected successfully");
13405 } else {
13406 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13407 return 0;
13408 }
13409 } else if (status == DB_NO_KEY) {
13410 cm_msg(MERROR, "check_odb_records", "ODB subtree /Runinfo does not exist");
13411 status = db_create_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str());
13412 if (status == DB_SUCCESS) {
13413 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo created successfully");
13414 } else {
13415 cm_msg(MERROR, "check_odb_records", "Cannot create ODB subtree /Runinfo, db_create_record() status %d", status);
13416 return 0;
13417 }
13418 } else if (status != DB_SUCCESS) {
13419 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13420 return 0;
13421 }
13422
13423 /* check /Equipment/<name>/Common structures */
13424 if (db_find_key(hDB, 0, "/equipment", &hKeyEq) == DB_SUCCESS) {
13425 for (i = 0 ;; i++) {
13427 if (!hKey)
13428 break;
13429 db_get_key(hDB, hKey, &key);
13430
13432 if (status == DB_STRUCT_MISMATCH) {
13434 if (status == DB_SUCCESS) {
13435 cm_msg(MINFO, "check_odb_records", "ODB subtree /Equipment/%s/Common corrected successfully", key.name);
13436 } else {
13437 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13438 }
13439 } else if (status != DB_SUCCESS) {
13440 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13441 }
13442 }
13443 }
13444
13445 return CM_SUCCESS;
13446}
13447
13448
13449/*------------------------------------------------------------------*/
13450
13451std::atomic_bool _abort{false};
13452
13453void ctrlc_handler(int sig)
13454{
13455 _abort = true;
13456}
13457
13458/*------------------------------------------------------------------*/
13459
13460#ifdef HAVE_MONGOOSE6
13461static std::vector<std::string> gUserAllowedHosts;
13462#endif
13463static std::vector<std::string> gAllowedHosts;
13464#ifdef HAVE_MONGOOSE6
13465static const std::string gOdbAllowedHosts = "/Experiment/Security/mhttpd hosts/Allowed hosts";
13466#endif
13467
13468#ifdef HAVE_MONGOOSE6
13469static void load_allowed_hosts(HNDLE hDB, HNDLE hKey, int index, void* info)
13470{
13471 if (hKey != 0)
13472 cm_msg(MINFO, "load_allowed_hosts", "Reloading mhttpd hosts access control list via hotlink callback");
13473
13474 gAllowedHosts.clear();
13475
13476 // copy the user allowed hosts
13477 for (unsigned int i=0; i<gUserAllowedHosts.size(); i++)
13478 gAllowedHosts.push_back(gUserAllowedHosts[i]);
13479
13480 int total = 0;
13481 int last = 0;
13482 for (int i=0; ; i++) {
13483 std::string s;
13484 int status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), i, &s, FALSE);
13485 //printf("get %d, status %d, string [%s]\n", i, status, s.c_str());
13486 if (status != DB_SUCCESS) {
13487 total = i;
13488 break;
13489 }
13490
13491 if (s.length() < 1) // skip emties
13492 continue;
13493
13494 if (s[0] == '#') // skip commented-out entries
13495 continue;
13496
13497 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
13498 gAllowedHosts.push_back(s);
13499 last = i;
13500 }
13501
13502 //printf("total %d, last %d\n", total, last);
13503
13504 if (total - last < 5) {
13505 int new_size = last + 10;
13506 //printf("new size %d\n", new_size);
13507 int status = db_resize_string(hDB, 0, gOdbAllowedHosts.c_str(), new_size, 256);
13508 if (status != DB_SUCCESS) {
13509 cm_msg(MERROR, "load_allowed_hosts", "Cannot resize the allowed hosts access control list, db_resize_string(%d) status %d", new_size, status);
13510 }
13511 }
13512}
13513
13514static int init_allowed_hosts()
13515{
13516 HNDLE hDB;
13517 HNDLE hKey;
13518 int status;
13519
13521
13522 // create "allowed hosts" so we can watch it
13523
13524 std::string s;
13525 status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), 0, &s, TRUE);
13526
13527 if (status != DB_SUCCESS) {
13528 cm_msg(MERROR, "init_allowed_hosts", "Cannot create the mhttpd hosts access control list, db_get_value_string() status %d", status);
13529 return status;
13530 }
13531
13532 status = db_find_key(hDB, 0, gOdbAllowedHosts.c_str(), &hKey);
13533
13534 if (status != DB_SUCCESS || hKey == 0) {
13535 cm_msg(MERROR, "init_allowed_hosts", "Cannot find the mhttpd hosts access control list, db_find_key() status %d", status);
13536 return status;
13537 }
13538
13539 load_allowed_hosts(hDB, 0, 0, NULL);
13540
13542
13543 if (status != DB_SUCCESS) {
13544 cm_msg(MERROR, "init_allowed_hosts", "Cannot watch the mhttpd hosts access control list, db_watch() status %d", status);
13545 return status;
13546 }
13547
13548 return SUCCESS;
13549}
13550
13551 int check_midas_acl(const struct sockaddr *sa, int len) {
13552 // access control list is empty?
13553 if (gAllowedHosts.size() == 0)
13554 return 1;
13555
13556 char hname[NI_MAXHOST];
13557 hname[0] = 0;
13558
13559 int status;
13560 const char* status_string = "success";
13561
13562 status = getnameinfo(sa, len, hname, sizeof(hname), NULL, 0, 0);
13563
13564 if (status)
13566
13567 //printf("connection from [%s], status %d (%s)\n", hname, status, status_string);
13568
13569 if (status != 0) {
13570 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, status, status_string);
13571 return 0;
13572 }
13573
13574 /* always permit localhost */
13575 if (strcmp(hname, "localhost.localdomain") == 0)
13576 return 1;
13577 if (strcmp(hname, "localhost") == 0)
13578 return 1;
13579
13580 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++)
13581 if (gAllowedHosts[i] == hname) {
13582 return 1;
13583 }
13584
13585 printf("Rejecting connection from \'%s\'\n", hname);
13586 return 0;
13587 }
13588
13589int open_listening_socket(int port)
13590{
13591 int status;
13592 struct sockaddr_in bind_addr;
13593
13594 /* create a new socket */
13595 int lsock = socket(AF_INET, SOCK_STREAM, 0);
13596
13597 if (lsock == -1) {
13598 printf("Cannot create socket, socket() errno %d (%s)\n", errno, strerror(errno));
13599 return -1;
13600 }
13601
13602 /* bind local node name and port to socket */
13603 memset(&bind_addr, 0, sizeof(bind_addr));
13604 bind_addr.sin_family = AF_INET;
13605 bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13606 bind_addr.sin_port = htons((short) port);
13607
13608 /* try reusing address */
13609 int flag = 1;
13610 status = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13611
13612 if (status < 0) {
13613 printf("Cannot setsockopt(SOL_SOCKET, SO_REUSEADDR), errno %d (%s)\n", errno, strerror(errno));
13614 return -1;
13615 }
13616
13617 status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13618
13619 if (status < 0) {
13620 printf("Cannot bind() to port %d, bind() errno %d (%s)\n", port, errno, strerror(errno));
13621 return -1;
13622 }
13623
13624 /* listen for connection */
13626 if (status < 0) {
13627 printf("Cannot listen() on port %d, errno %d (%s), bye!\n", port, errno, strerror(errno));
13628 return -1;
13629 }
13630
13631 printf("mhttpd is listening on port %d\n", port);
13632
13633 return lsock;
13634}
13635#endif
13636
13637/*------------------------------------------------------------------*/
13638
13639int try_file_mg(const char* try_dir, const char* filename, std::string& path, FILE** fpp, bool trace)
13640{
13641 if (fpp)
13642 *fpp = NULL;
13643 if (!try_dir)
13644 return SS_FILE_ERROR;
13645 if (strlen(try_dir) < 1)
13646 return SS_FILE_ERROR;
13647
13648 path = try_dir;
13649 if (path[path.length()-1] != DIR_SEPARATOR)
13650 path += DIR_SEPARATOR_STR;
13651 path += filename;
13652
13653 FILE* fp = fopen(path.c_str(), "r");
13654
13655 if (trace) {
13656 if (fp)
13657 printf("file \"%s\": OK!\n", path.c_str());
13658 else
13659 printf("file \"%s\": not found.\n", path.c_str());
13660 }
13661
13662 if (!fp)
13663 return SS_FILE_ERROR;
13664 else if (fpp)
13665 *fpp = fp;
13666 else
13667 fclose(fp);
13668
13669 return SUCCESS;
13670}
13671
13672int find_file_mg(const char* filename, std::string& path, FILE** fpp, bool trace)
13673{
13674 std::string exptdir = cm_get_path();
13675
13676 if (try_file_mg(".", filename, path, fpp, trace) == SUCCESS)
13677 return SUCCESS;
13678
13679 if (try_file_mg(getenv("MIDAS_DIR"), filename, path, fpp, trace) == SUCCESS)
13680 return SUCCESS;
13681
13682 if (try_file_mg(exptdir.c_str(), filename, path, fpp, trace) == SUCCESS)
13683 return SUCCESS;
13684
13685 if (try_file_mg(getenv("MIDASSYS"), filename, path, fpp, trace) == SUCCESS)
13686 return SUCCESS;
13687
13688 // setup default filename
13689 try_file_mg(exptdir.c_str(), filename, path, NULL, false);
13690 return SS_FILE_ERROR;
13691}
13692
13693#ifdef HAVE_MONGOOSE6
13694#include "mongoose6.h"
13695#endif
13696
13697#ifdef HAVE_MONGOOSE616
13698#undef closesocket
13699#include "mongoose616.h"
13700// cs_md5() in not in mongoose.h
13701extern void cs_md5(char buf[33], ...);
13702#endif
13703
13704static bool verbose_mg = false;
13705static bool trace_mg = false;
13706static bool trace_mg_recv = false;
13707static bool trace_mg_send = false;
13708#ifdef HAVE_MONGOOSE616
13709static bool multithread_mg = true;
13710#endif
13711
13712#ifdef HAVE_MONGOOSE6
13713static struct mg_mgr mgr_mg;
13714#endif
13715
13717 std::string username;
13718 std::string realm;
13719 std::string password;
13720};
13721
13722class Auth {
13723public:
13724 std::string realm;
13725 std::string passwd_filename;
13726 std::vector<AuthEntry> passwords;
13727public:
13728 int Init();
13729};
13730
13731static bool read_passwords(Auth* auth);
13732
13734{
13735 std::string exptname = cm_get_experiment_name();
13736
13737 if (!exptname.empty())
13738 realm = exptname;
13739 else
13740 realm = "midas";
13741
13742 bool ok = read_passwords(this);
13743 if (!ok) {
13744 cm_msg(MERROR, "mongoose", "mongoose web server password file \"%s\" has no passwords for realm \"%s\"", passwd_filename.c_str(), realm.c_str());
13745 cm_msg(MERROR, "mongoose", "please add passwords by running: htdigest %s %s midas", passwd_filename.c_str(), realm.c_str());
13746 return SS_FILE_ERROR;
13747 }
13748
13749 return SUCCESS;
13750}
13751
13753
13754static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri,
13755 size_t uri_len, const char *ha1, size_t ha1_len,
13756 const char *nonce, size_t nonce_len, const char *nc,
13757 size_t nc_len, const char *cnonce, size_t cnonce_len,
13758 const char *qop, size_t qop_len, char *resp) {
13759 static const char colon[] = ":";
13760 static const size_t one = 1;
13761 char ha2[33];
13762
13763 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
13764 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
13765 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
13766 colon, one, ha2, sizeof(ha2) - 1, NULL);
13767}
13768
13769/*
13770 * Check for authentication timeout.
13771 * Clients send time stamp encoded in nonce. Make sure it is not too old,
13772 * to prevent replay attacks.
13773 * Assumption: nonce is a hexadecimal number of seconds since 1970.
13774 */
13775static int xmg_check_nonce(const char *nonce) {
13776 unsigned long now = (unsigned long) time(NULL);
13777 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
13778 return now < val || now - val < 3600;
13779}
13780
13781/*
13782 * Authenticate HTTP request against opened passwords file.
13783 * Returns 1 if authenticated, 0 otherwise.
13784 */
13785
13787 const char *domain) {
13788 mg_printf(c,
13789 "HTTP/1.1 401 Unauthorized\r\n"
13790 "WWW-Authenticate: Digest qop=\"auth\", "
13791 "realm=\"%s\", nonce=\"%lu\"\r\n"
13792 "Content-Length: 0\r\n\r\n",
13793 domain, (unsigned long) time(NULL));
13794}
13795
13797{
13798 std::string path;
13799 FILE *fp;
13800 int status = find_file_mg("htpasswd.txt", path, &fp, trace_mg||verbose_mg);
13801
13802 auth->passwd_filename = path;
13803 auth->passwords.clear();
13804
13805 if (status != SUCCESS || fp == NULL) {
13806 cm_msg(MERROR, "mongoose", "mongoose web server cannot find password file \"%s\"", path.c_str());
13807 cm_msg(MERROR, "mongoose", "please create password file: touch %s", path.c_str());
13808 return false;
13809 }
13810
13811 bool have_realm = false;
13812 char buf[256];
13813
13814 /*
13815 * Read passwords file line by line. If should have htdigest format,
13816 * i.e. each line should be a colon-separated sequence:
13817 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
13818 */
13819 while (fgets(buf, sizeof(buf), fp) != NULL) {
13820 char f_user[256];
13821 char f_domain[256];
13822 char f_ha1[256];
13823
13824 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3) {
13825 AuthEntry e;
13826 e.realm = f_domain;
13827 e.username = f_user;
13828 e.password = f_ha1;
13829
13830 if (e.realm == auth->realm) {
13831 have_realm = true;
13832 auth->passwords.push_back(e);
13833 }
13834 }
13835 }
13836
13837 fclose(fp);
13838
13839 return have_realm;
13840}
13841
13842#ifdef HAVE_MONGOOSE6
13843std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13844{
13845 assert(!"this code is untested!");
13846
13847 char* buf = NULL;
13848 int buf_size = 0;
13849
13850 while (1) {
13851 if (buf_size == 0) {
13852 buf_size = 256;
13853 buf = (char*)malloc(buf_size);
13854 assert(buf != NULL);
13855 }
13856
13857 int size = mg_http_parse_header(hdr, var_name, buf, buf_size);
13858
13859 if (size <= 0) {
13860 free(buf);
13861 return "";
13862 }
13863
13864 if (size < buf_size) {
13865 std::string s = buf;
13866 free(buf);
13867 return s;
13868 }
13869
13870 buf_size = buf_size*2 + 16;
13871 buf = (char*)realloc(buf, buf_size);
13872 assert(buf != NULL);
13873 }
13874}
13875#endif
13876
13877#ifdef HAVE_MONGOOSE616
13878std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13879{
13880 char* buf = NULL;
13881 int buf_size = 0;
13882 int size = mg_http_parse_header2(hdr, var_name, &buf, buf_size);
13883 if (size <= 0)
13884 return "";
13885 assert(buf != NULL);
13886 std::string s = buf;
13887 free(buf);
13888 return s;
13889}
13890#endif
13891
13892static std::string check_digest_auth(struct http_message *hm, Auth* auth)
13893{
13894 char expected_response[33];
13895
13896 //printf("HereA!\n");
13897
13898 /* Parse "Authorization:" header, fail fast on parse error */
13899 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
13900
13901 if (!hdr)
13902 return "";
13903
13904 //printf("HereB!\n");
13905
13906 std::string user = find_var_mg(hdr, "username");
13907 std::string cnonce = find_var_mg(hdr, "cnonce");
13908 std::string response = find_var_mg(hdr, "response");
13909 std::string uri = find_var_mg(hdr, "uri");
13910 std::string qop = find_var_mg(hdr, "qop");
13911 std::string nc = find_var_mg(hdr, "nc");
13912 std::string nonce = find_var_mg(hdr, "nonce");
13913
13914 if (user.length()<1) return "";
13915 if (cnonce.length()<1) return "";
13916 if (response.length()<1) return "";
13917 if (uri.length()<1) return "";
13918 if (qop.length()<1) return "";
13919 if (nc.length()<1) return "";
13920 if (nonce.length()<1) return "";
13921
13922 if (xmg_check_nonce(nonce.c_str()) == 0) return "";
13923 //printf("HereB8!\n");
13924
13925 //printf("HereC!\n");
13926
13927 const char* uri_end = strchr(hm->uri.p, ' ');
13928 if (!uri_end) return "";
13929
13930 size_t uri_length = uri_end - hm->uri.p;
13931
13932 if (uri_length != uri.length())
13933 return "";
13934
13935 int cmp = strncmp(hm->uri.p, uri.c_str(), uri_length);
13936
13937 //printf("check URI: message %d %d [%d] authorization [%s]\n", (int)hm->uri.len, uri_length, cmp, uri);
13938
13939 if (cmp != 0)
13940 return "";
13941
13942 for (unsigned i=0; i<auth->passwords.size(); i++) {
13943 AuthEntry* e = &auth->passwords[i];
13944 if (e->username != user)
13945 continue;
13946 if (e->realm != auth->realm)
13947 continue;
13948 const char* f_ha1 = e->password.c_str();
13949 int uri_len = hm->uri.len;
13950 if (hm->uri.p[uri_len] == '?')
13951 uri_len += hm->query_string.len + 1; // "+1" accounts for the "?" character
13952 xmg_mkmd5resp(hm->method.p, hm->method.len,
13953 hm->uri.p, uri_len,
13954 f_ha1, strlen(f_ha1),
13955 nonce.c_str(), nonce.length(),
13956 nc.c_str(), nc.length(),
13957 cnonce.c_str(), cnonce.length(),
13958 qop.c_str(), qop.length(),
13960 int cmp = strcasecmp(response.c_str(), expected_response);
13961 //printf("digest_auth: expected %s, got %s, cmp %d\n", expected_response, response.c_str(), cmp);
13962 if (cmp == 0) {
13963 return e->username;
13964 }
13965 }
13966
13967 return "";
13968}
13969
13970#ifdef HAVE_MONGOOSE616
13971
13972struct HostlistCacheEntry
13973{
13974 time_t time_created = 0;
13976 int count_used = 0;
13977 bool ipv4 = false;
13978 bool ipv6 = false;
13979 uint32_t ipv4addr = 0;
13980 struct in6_addr ipv6addr;
13981 std::string hostname;
13982 int gai_status = 0;
13983 std::string gai_strerror;
13984 bool ok = false;
13985};
13986
13987static std::vector<HostlistCacheEntry*> gHostlistCache;
13988
13989static void print_hostlist_cache()
13990{
13991 time_t now = time(NULL);
13992
13993 for (unsigned i=0; i<gHostlistCache.size(); i++) {
13995 if (!e) {
13996 // empty slot
13997 continue;
13998 }
13999
14000 printf("%3d: %s \"%s\", ok %d, count_used %d, age created: %d, last_used %d",
14001 i,
14002 e->ipv4?"IPv4":(e->ipv6?"IPv6":"????"),
14003 e->hostname.c_str(),
14004 e->ok,
14005 e->count_used,
14006 (int)(now - e->time_created),
14007 (int)(now - e->time_last_used));
14008
14009 if (e->gai_status) {
14010 printf(", getnameinfo() status %d (%s)", e->gai_status, e->gai_strerror.c_str());
14011 }
14012
14013 printf("\n");
14014 }
14015}
14016
14017static bool mongoose_check_hostlist(const union socket_address *sa)
14018{
14019 time_t now = time(NULL);
14020 bool ipv4 = false;
14021 bool ipv6 = false;
14022 uint32_t ipv4addr = 0;
14023 struct in6_addr ipv6addr;
14024
14025 if (sa->sa.sa_family == AF_INET) {
14026 ipv4 = true;
14027 ipv4addr = sa->sin.sin_addr.s_addr;
14028 } else if (sa->sa.sa_family == AF_INET6) {
14029 ipv6 = true;
14030 memcpy(&ipv6addr, &sa->sin6.sin6_addr, sizeof(ipv6addr));
14031 } else {
14032 printf("Rejecting connection from unknown address family %d (AF_xxx)\n", sa->sa.sa_family);
14033 return false;
14034 }
14035
14036 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14038 if (!e) {
14039 // empty slot
14040 continue;
14041 }
14042
14043 if ((ipv4 == e->ipv4) && (ipv4addr == e->ipv4addr)) {
14044 // IPv4 address match
14045 e->time_last_used = now;
14046 e->count_used++;
14047 return e->ok;
14048 }
14049
14050 if ((ipv6 == e->ipv6) && (memcmp(&ipv6addr, &e->ipv6addr, sizeof(ipv6addr)) == 0)) {
14051 // IPv6 address match
14052 e->time_last_used = now;
14053 e->count_used++;
14054 return e->ok;
14055 }
14056
14057 // not this one. maybe expire old entries?
14058
14059 if (e->time_last_used < now - 24*60*60) {
14060 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);
14062 delete e;
14063 }
14064 }
14065
14066 // not found in cache
14067
14068 assert(ipv4 || ipv6);
14069
14071
14072 bool found = false;
14073 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14074 if (gHostlistCache[i] == NULL) {
14075 gHostlistCache[i] = e;
14076 found = true;
14077 }
14078 }
14079 if (!found) {
14080 gHostlistCache.push_back(e);
14081 }
14082
14083 e->time_created = now;
14084 e->time_last_used = now;
14085 e->count_used = 1;
14086 e->ipv4 = ipv4;
14087 e->ipv6 = ipv6;
14088 if (ipv4)
14089 e->ipv4addr = ipv4addr;
14090 if (ipv6)
14091 memcpy(&e->ipv6addr, &ipv6addr, sizeof(ipv6addr));
14092 e->ok = false;
14093
14094 char hname[NI_MAXHOST];
14095 hname[0] = 0;
14096
14097 e->gai_status = getnameinfo(&sa->sa, sizeof(*sa), hname, sizeof(hname), NULL, 0, 0);
14098
14099 if (e->gai_status) {
14100 e->gai_strerror = gai_strerror(e->gai_status);
14101
14102 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, e->gai_status, e->gai_strerror.c_str());
14103
14104 e->ok = false;
14105 return e->ok;
14106 }
14107
14108 printf("connection from \"%s\"\n", hname);
14109
14110 e->hostname = hname;
14111
14112 /* always permit localhost */
14113 if (e->hostname == "localhost.localdomain")
14114 e->ok = true;
14115 else if (e->hostname == "localhost")
14116 e->ok = true;
14117 else {
14118 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++) {
14119 if (e->hostname == gAllowedHosts[i]) {
14120 e->ok = true;
14121 }
14122 }
14123 }
14124
14125 if (!e->ok) {
14126 printf("Rejecting connection from \'%s\'\n", hname);
14127 }
14128
14130
14131 return e->ok;
14132}
14133
14134#endif
14135
14136static std::string mgstr(const mg_str* s)
14137{
14138 return std::string(s->p, s->len);
14139}
14140
14141static const std::string find_header_mg(const struct http_message *msg, const char* name)
14142{
14143 size_t nlen = strlen(name);
14144 for (int i=0; i<MG_MAX_HTTP_HEADERS; i++) {
14145 if (msg->header_names[i].len != nlen)
14146 continue;
14147 if (strncmp(msg->header_names[i].p, name, nlen) != 0)
14148 continue;
14149 return mgstr(&msg->header_values[i]);
14150 }
14151 return "";
14152}
14153
14154static const std::string find_cookie_mg(const struct http_message *msg, const char* cookie_name)
14155{
14156 const std::string cookies = find_header_mg(msg, "Cookie");
14157 if (cookies.length() < 1)
14158 return "";
14159 const char* p = strstr(cookies.c_str(), cookie_name);
14160 if (!p)
14161 return "";
14162 const char* v = p+strlen(cookie_name);
14163 if (*v != '=')
14164 return "";
14165 v++;
14166 //printf("cookie [%s] value [%s]\n", cookie_name, v);
14167 return v;
14168}
14169
14170// Generic event handler
14171
14172static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
14173{
14174 struct mbuf *io = &nc->recv_mbuf;
14175 switch (ev) {
14176 case MG_EV_POLL: // periodic call from loop_mg() via mg_mgr_poll()
14177 break;
14178 case MG_EV_ACCEPT:
14179 if (trace_mg)
14180 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> accept\n", nc, ev, ev_data);
14181 break;
14182 case MG_EV_RECV:
14183 if (trace_mg)
14184 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);
14185#if 0
14186 // This event handler implements simple TCP echo server
14187 mg_send(nc, io->buf, io->len); // Echo received data back
14188 mbuf_remove(io, io->len); // Discard data from recv buffer
14189#endif
14190 break;
14191 case MG_EV_SEND:
14192 if (trace_mg)
14193 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> send %d bytes\n", nc, ev, ev_data, *(int*)ev_data);
14194 break;
14195 case MG_EV_CLOSE:
14196 if (trace_mg)
14197 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> close\n", nc, ev, ev_data);
14198 break;
14199 default:
14200 if (trace_mg)
14201 printf("handle_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
14202 break;
14203 }
14204}
14205
14207{
14208 // extract password cookies
14209
14210 char cookie_pwd[256]; // general access password
14211 char cookie_wpwd[256]; // "write mode" password
14212 char cookie_cpwd[256]; // custom page and javascript password
14213
14214 cookie_pwd[0] = 0;
14215 cookie_wpwd[0] = 0;
14216 cookie_cpwd[0] = 0;
14217
14218 std::string s = find_cookie_mg(msg, "midas_pwd");
14219 if (s.length() > 0) {
14220 mstrlcpy(cookie_pwd, s.c_str(), sizeof(cookie_pwd));
14221 cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
14222 }
14223
14224 s = find_cookie_mg(msg, "midas_wpwd");
14225 if (s.length()) {
14226 mstrlcpy(cookie_wpwd, s.c_str(), sizeof(cookie_pwd));
14227 cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
14228 }
14229
14230 s = find_cookie_mg(msg, "cpwd");
14231 if (s.length()) {
14232 mstrlcpy(cookie_cpwd, s.c_str(), sizeof(cookie_pwd));
14233 cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
14234 }
14235
14236 // extract refresh rate
14237 c->refresh = DEFAULT_REFRESH;
14238 s = find_cookie_mg(msg, "midas_refr");
14239 if (s.length() > 0)
14240 c->refresh = atoi(s.c_str());
14241
14242 // extract equipment expand flag
14243 //c->expand_equipment = 0;
14244 //s = find_cookie_mg(msg, "midas_expeq");
14245 //if (s.length() > 0)
14246 // c->expand_equipment = atoi(s.c_str());
14247
14248 c->cookie_pwd = cookie_pwd;
14249 c->cookie_wpwd = cookie_wpwd;
14250 c->cookie_cpwd = cookie_cpwd;
14251}
14252
14253#define RESPONSE_SENT 1
14254#define RESPONSE_QUEUED 2
14255#define RESPONSE_501 3
14256
14257static int handle_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14258{
14260
14261 decode_cookies(&cookies, msg);
14262
14263 // lock shared structures
14264
14265#ifdef HAVE_MONGOOSE6
14267 assert(status == SS_SUCCESS);
14268#endif
14269
14270 //t->fTimeLocked = GetTimeSec();
14271
14272 // prepare return buffer
14273
14274 Return *rr = new Return();
14275
14276 rr->zero();
14277
14278 // call midas
14279
14280 decode_get(rr, NULL, &cookies, uri, query_string, t);
14281
14282 if (trace_mg)
14283 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14284
14286
14287 if (rr->return_length == -1) {
14288 delete rr;
14289#ifdef HAVE_MONGOOSE6
14290 //t->fTimeUnlocked = GetTimeSec();
14292#endif
14293 return RESPONSE_501;
14294 }
14295
14296 if (rr->return_length == 0)
14297 rr->return_length = strlen(rr->return_buffer);
14298
14299 //t->fTimeUnlocked = GetTimeSec();
14300
14301#ifdef HAVE_MONGOOSE6
14303#endif
14304
14305 mg_send(nc, rr->return_buffer, rr->return_length);
14306
14307 if (!strstr(rr->return_buffer, "Content-Length")) {
14308 // cannot do pipelined http if response generated by mhttpd
14309 // decode_get() has no Content-Length header.
14310 // must close the connection.
14312 }
14313
14314 t->fTimeSent = GetTimeSec();
14315
14316 delete rr;
14317
14318 return RESPONSE_SENT;
14319}
14320
14321#ifdef HAVE_MONGOOSE616
14322
14323static uint32_t s_ncseqno = 1;
14324
14325struct MongooseNcUserData
14326{
14327 uint32_t ncseqno = 0;
14328
14329 MongooseNcUserData() // ctor
14330 {
14331 ncseqno = s_ncseqno++;
14332 //printf("MongooseNcUserData::ctor! ncseqno %d\n", ncseqno);
14333 }
14334
14335 ~MongooseNcUserData() // ctor
14336 {
14337 //printf("MongooseNcUserData::dtor! ncseqno %d\n", ncseqno);
14338 }
14339};
14340
14341static uint32_t GetNcSeqno(const mg_connection* nc)
14342{
14343 if (nc == NULL)
14344 return 0;
14345 if (nc->user_data == NULL)
14346 return 0;
14348 return ncud->ncseqno;
14349}
14350
14351static uint32_t s_wseqno = 1;
14352
14353struct MongooseWorkObject
14354{
14355 uint32_t wseqno = 0;
14356 mg_connection* nc = NULL;
14357 uint32_t wncseqno = 0;
14358 bool http_get = false;
14359 bool http_post = false;
14360 bool mjsonrpc = false;
14362 std::string origin;
14363 std::string uri;
14364 std::string query_string;
14365 std::string post_body;
14366 std::string post_boundary;
14367 RequestTrace* t = NULL;
14368 bool send_done = false;
14369
14371 {
14372 wseqno = s_wseqno++;
14373 nc = xnc;
14374 wncseqno = GetNcSeqno(nc);
14375
14376 //printf("MongooseWorkObject::ctor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14377 }
14378
14379 ~MongooseWorkObject() // dtor
14380 {
14381 //printf("MongooseWorkObject::dtor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14382
14383 // poison pointers
14384 nc = NULL;
14385 t = NULL;
14386 }
14387};
14388
14390{
14391 std::atomic_bool fIsRunning{false};
14392 std::thread* fThread = NULL; // thread
14393 void* fNc = NULL; // thread is attached to this network connection
14394 std::mutex fMutex;
14395 std::deque<MongooseWorkObject*> fQueue;
14396 std::condition_variable fNotify;
14397
14398 //MongooseThreadObject() // ctor
14399 //{
14400 // printf("MongooseThreadObject %p created!\n", this);
14401 //}
14402
14403 //~MongooseThreadObject() // dtor
14404 //{
14405 // printf("MongooseThreadObject %p destroyed!\n", this);
14406 //}
14407};
14408
14409static std::vector<MongooseThreadObject*> gMongooseThreads;
14410
14412
14414{
14415 //printf("FindThread: nc %p, thread %s\n", nc, ss_tid_to_string(ss_gettid()).c_str());
14416
14418
14419 for (auto it : gMongooseThreads) {
14421 if (to->fNc == nc) {
14422 //printf("to %p, nc %p: found thread\n", to, nc);
14423 return to;
14424 }
14425 if (to->fNc == NULL) {
14427 }
14428 }
14429
14430 if (last_not_connected) {
14432 to->fNc = nc;
14433 //printf("to %p, nc %p: reusing thread\n", to, nc);
14434 return to;
14435 }
14436
14438
14439 to->fNc = nc;
14440
14441 //printf("to %p, nc %p: new thread\n", to, nc);
14442
14443 gMongooseThreads.push_back(to);
14444
14445 printf("Mongoose web server is using %d threads \r", (int)gMongooseThreads.size());
14446 fflush(stdout);
14447
14448 to->fThread = new std::thread(mongoose_thread, to);
14449
14450 return to;
14451}
14452
14453void FreeThread(void* nc)
14454{
14455 //printf("FreeThread, nc %p\n", nc);
14456
14457 for (auto it : gMongooseThreads) {
14459 if (to->fNc == nc) {
14460 //printf("to %p, nc %p: connection closed\n", to, nc);
14461 to->fNc = NULL;
14462 return;
14463 }
14464 }
14465
14466 //printf("to %p, nc %p: connection closed, but no thread\n", nullptr, nc);
14467}
14468
14470{
14471 w->nc = nc;
14473 assert(to->fNc == nc);
14474 to->fMutex.lock();
14475 to->fQueue.push_back(w);
14476 to->fMutex.unlock();
14477 to->fNotify.notify_one();
14478}
14479
14480static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag = false);
14481
14482static int queue_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14483{
14485 w->http_get = true;
14486 decode_cookies(&w->cookies, msg);
14487 w->uri = uri;
14488 w->query_string = query_string;
14489 w->t = t;
14490
14491 mongoose_queue(nc, w);
14492
14493 return RESPONSE_QUEUED;
14494}
14495
14496static int queue_decode_post(struct mg_connection *nc, const http_message* msg, const char* boundary, const char* uri, const char* query_string, RequestTrace* t)
14497{
14499 w->http_post = true;
14500 decode_cookies(&w->cookies, msg);
14501 w->uri = uri;
14502 w->query_string = query_string;
14503 w->post_body = mgstr(&msg->body);
14504 w->post_boundary = boundary;
14505 w->t = t;
14506
14507 mongoose_queue(nc, w);
14508
14509 return RESPONSE_QUEUED;
14510}
14511
14512static int queue_mjsonrpc(struct mg_connection *nc, const std::string& origin, const std::string& post_body, RequestTrace* t)
14513{
14515 w->mjsonrpc = true;
14516 w->origin = origin;
14517 w->post_body = post_body;
14518 w->t = t;
14519
14520 mongoose_queue(nc, w);
14521
14522 return RESPONSE_QUEUED;
14523}
14524
14526{
14527 // lock shared structures
14528
14529 //int status = ss_mutex_wait_for(request_mutex, 0);
14530 //assert(status == SS_SUCCESS);
14531
14532 //w->t->fTimeLocked = GetTimeSec();
14533
14534 // prepare return buffer
14535
14536 Return *rr = new Return();
14537
14538 rr->zero();
14539
14540 // call midas
14541
14542 decode_get(rr, NULL, &w->cookies, w->uri.c_str(), w->query_string.c_str(), w->t);
14543
14544 if (trace_mg)
14545 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14546
14547 w->t->fTimeProcessed = GetTimeSec();
14548
14549 if (rr->return_length == -1) {
14550 delete rr;
14551 //w->t->fTimeUnlocked = GetTimeSec();
14552 //ss_mutex_release(request_mutex);
14553 return RESPONSE_501;
14554 }
14555
14556 if (rr->return_length == 0)
14557 rr->return_length = strlen(rr->return_buffer);
14558
14559 //w->t->fTimeUnlocked = GetTimeSec();
14560
14561 //ss_mutex_release(request_mutex);
14562
14563 bool close_flag = false;
14564
14565 if (!strstr(rr->return_buffer, "Content-Length")) {
14566 // cannot do pipelined http if response generated by mhttpd
14567 // decode_get() has no Content-Length header.
14568 // must close the connection.
14569 close_flag = true;
14570 }
14571
14572 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14573
14574 w->t->fTimeSent = GetTimeSec();
14575
14576 delete rr;
14577
14578 return RESPONSE_SENT;
14579}
14580
14582{
14583 const char* post_data = w->post_body.c_str();
14584 int post_data_len = w->post_body.length();
14585
14586 // lock shared strctures
14587
14588 //int status = ss_mutex_wait_for(request_mutex, 0);
14589 //assert(status == SS_SUCCESS);
14590
14591 // prepare return buffer
14592
14593 Return* rr = new Return;
14594
14595 rr->zero();
14596
14597 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14598
14599 decode_post(rr, NULL, (char*)post_data, w->post_boundary.c_str(), post_data_len, &w->cookies, w->uri.c_str(), w->t);
14600
14601 if (trace_mg)
14602 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14603
14604 if (rr->return_length == -1) {
14605 //ss_mutex_release(request_mutex);
14606 delete rr;
14607 return RESPONSE_501;
14608 }
14609
14610 if (rr->return_length == 0)
14611 rr->return_length = strlen(rr->return_buffer);
14612
14613 //ss_mutex_release(request_mutex);
14614
14615 bool close_flag = false;
14616 if (!strstr(rr->return_buffer, "Content-Length")) {
14617 // cannot do pipelined http if response generated by mhttpd
14618 // decode_get() has no Content-Length header.
14619 // must close the connection.
14620 close_flag = true;
14621 }
14622
14623 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14624
14625 delete rr;
14626
14627 return RESPONSE_SENT;
14628
14629}
14630
14632{
14633 w->t->fRPC = w->post_body;
14634
14635 //int status = ss_mutex_wait_for(request_mutex, 0);
14636 //assert(status == SS_SUCCESS);
14637
14638 //gMutex.lock();
14639 //w->t->fTimeLocked = GetTimeSec();
14640
14641 MJsonNode* reply = mjsonrpc_decode_post_data(w->post_body.c_str());
14642
14643 //w->t->fTimeUnlocked = GetTimeSec();
14644 //gMutex.unlock();
14645
14646 //ss_mutex_release(request_mutex);
14647
14648 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14649 const char* ptr;
14650 size_t size;
14651 reply->GetArrayBuffer(&ptr, &size);
14652
14653 std::string headers;
14654 headers += "HTTP/1.1 200 OK\n";
14655 if (w->origin.length() > 0)
14656 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14657 else
14658 headers += "Access-Control-Allow-Origin: *\n";
14659 headers += "Access-Control-Allow-Credentials: true\n";
14660 headers += "Content-Length: " + toString(size) + "\n";
14661 headers += "Content-Type: application/octet-stream\n";
14662 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14663
14664 //printf("sending headers: %s\n", headers.c_str());
14665 //printf("sending reply: %s\n", reply_string.c_str());
14666
14667 std::string send = headers + "\n";
14668
14669 w->t->fTimeProcessed = GetTimeSec();
14670
14671 mongoose_send(nc, w, send.c_str(), send.length(), ptr, size);
14672
14673 w->t->fTimeSent = GetTimeSec();
14674
14675 delete reply;
14676
14677 return RESPONSE_SENT;
14678 }
14679
14680 std::string reply_string = reply->Stringify();
14681 int reply_length = reply_string.length();
14682
14683 std::string headers;
14684 headers += "HTTP/1.1 200 OK\n";
14685 if (w->origin.length() > 0)
14686 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14687 else
14688 headers += "Access-Control-Allow-Origin: *\n";
14689 headers += "Access-Control-Allow-Credentials: true\n";
14690 headers += "Content-Length: " + toString(reply_length) + "\n";
14691 headers += "Content-Type: application/json\n";
14692 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14693
14694 //printf("sending headers: %s\n", headers.c_str());
14695 //printf("sending reply: %s\n", reply_string.c_str());
14696
14697 std::string send = headers + "\n" + reply_string;
14698
14699 w->t->fTimeProcessed = GetTimeSec();
14700
14701 mongoose_send(nc, w, send.c_str(), send.length(), NULL, 0);
14702
14703 w->t->fTimeSent = GetTimeSec();
14704
14705 delete reply;
14706
14707 return RESPONSE_SENT;
14708}
14709
14711{
14712 if (w->http_get)
14713 return thread_http_get(nc, w);
14714 else if (w->http_post)
14715 return thread_http_post(nc, w);
14716 else if (w->mjsonrpc)
14717 return thread_mjsonrpc(nc, w);
14718 else
14719 return RESPONSE_501;
14720}
14721
14722#endif
14723
14724static int handle_decode_post(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14725{
14726
14727 char boundary[256];
14728 boundary[0] = 0;
14729 const std::string ct = find_header_mg(msg, "Content-Type");
14730 if (ct.length() > 0) {
14731 const char* s = strstr(ct.c_str(), "boundary=");
14732 if (s)
14733 mstrlcpy(boundary, s+9, sizeof(boundary));
14734 }
14735
14736#ifdef HAVE_MONGOOSE616
14737 if (multithread_mg)
14738 return queue_decode_post(nc, msg, boundary, uri, query_string, t);
14739#endif
14740
14742
14743 decode_cookies(&cookies, msg);
14744
14745 const char* post_data = msg->body.p;
14746 int post_data_len = msg->body.len;
14747
14748 // lock shared strctures
14749
14750#ifdef HAVE_MONGOOSE6
14752 assert(status == SS_SUCCESS);
14753#endif
14754
14755 // prepare return buffer
14756
14757 Return* rr = new Return;
14758
14759 rr->zero();
14760
14761 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14762
14763 decode_post(rr, NULL, (char*)post_data, boundary, post_data_len, &cookies, uri, t);
14764
14765 if (trace_mg)
14766 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14767
14768 if (rr->return_length == -1) {
14769#ifdef HAVE_MONGOOSE6
14771#endif
14772 delete rr;
14773 return RESPONSE_501;
14774 }
14775
14776 if (rr->return_length == 0)
14777 rr->return_length = strlen(rr->return_buffer);
14778
14779#ifdef HAVE_MONGOOSE6
14781#endif
14782
14783 mg_send(nc, rr->return_buffer, rr->return_length);
14784
14785 if (!strstr(rr->return_buffer, "Content-Length")) {
14786 // cannot do pipelined http if response generated by mhttpd
14787 // decode_get() has no Content-Length header.
14788 // must close the connection.
14790 }
14791
14792 delete rr;
14793
14794 return RESPONSE_SENT;
14795}
14796
14797static int handle_http_get(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14798{
14799 std::string query_string = mgstr(&msg->query_string);
14800
14801 if (trace_mg||verbose_mg)
14802 printf("handle_http_get: uri [%s], query [%s]\n", uri, query_string.c_str());
14803
14804 if (query_string == "mjsonrpc_schema") {
14805 MJsonNode* s = mjsonrpc_get_schema();
14806 std::string reply = s->Stringify();
14807 delete s;
14808
14809 int reply_length = reply.length();
14810
14811 const std::string origin_header = find_header_mg(msg, "Origin");
14812
14813 std::string headers;
14814 headers += "HTTP/1.1 200 OK\n";
14815 if (origin_header.length() > 0)
14816 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14817 else
14818 headers += "Access-Control-Allow-Origin: *\n";
14819 headers += "Access-Control-Allow-Credentials: true\n";
14820 headers += "Content-Length: " + toString(reply_length) + "\n";
14821 headers += "Content-Type: application/json\n";
14822 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14823
14824 //printf("sending headers: %s\n", headers.c_str());
14825 //printf("sending reply: %s\n", reply.c_str());
14826
14827 std::string send = headers + "\n" + reply;
14828
14830
14831 mg_send(nc, send.c_str(), send.length());
14832
14833 t->fTimeSent = GetTimeSec();
14834
14835 return RESPONSE_SENT;
14836 }
14837
14838 if (query_string == "mjsonrpc_schema_text") {
14839 MJsonNode* s = mjsonrpc_get_schema();
14840 std::string reply = mjsonrpc_schema_to_text(s);
14841 delete s;
14842
14843 int reply_length = reply.length();
14844
14845 const std::string origin_header = find_header_mg(msg, "Origin");
14846
14847 std::string headers;
14848 headers += "HTTP/1.1 200 OK\n";
14849 if (origin_header.length() > 0)
14850 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14851 else
14852 headers += "Access-Control-Allow-Origin: *\n";
14853 headers += "Access-Control-Allow-Credentials: true\n";
14854 headers += "Content-Length: " + toString(reply_length) + "\n";
14855 headers += "Content-Type: text/plain\n";
14856 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14857
14858 //printf("sending headers: %s\n", headers.c_str());
14859 //printf("sending reply: %s\n", reply.c_str());
14860
14861 std::string send = headers + "\n" + reply;
14862
14864
14865 mg_send(nc, send.c_str(), send.length());
14866
14867 t->fTimeSent = GetTimeSec();
14868
14869 return RESPONSE_SENT;
14870 }
14871
14872#ifdef HAVE_MONGOOSE616
14873 if (multithread_mg)
14874 return queue_decode_get(nc, msg, uri, query_string.c_str(), t);
14875#endif
14876
14877 return handle_decode_get(nc, msg, uri, query_string.c_str(), t);
14878}
14879
14880static int handle_http_post(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14881{
14882 std::string query_string = mgstr(&msg->query_string);
14883 std::string post_data = mgstr(&msg->body);
14884
14885 if (trace_mg||verbose_mg)
14886 printf("handle_http_post: uri [%s], query [%s], post data %d bytes\n", uri, query_string.c_str(), (int)post_data.length());
14887
14888 if (query_string == "mjsonrpc") {
14889 const std::string origin_header = find_header_mg(msg, "Origin");
14890 const std::string ctype_header = find_header_mg(msg, "Content-Type");
14891
14892 if (strstr(ctype_header.c_str(), "application/json") == NULL) {
14893 std::string headers;
14894 headers += "HTTP/1.1 415 Unsupported Media Type\n";
14895 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14896
14897 //printf("sending headers: %s\n", headers.c_str());
14898 //printf("sending reply: %s\n", reply.c_str());
14899
14900 std::string send = headers + "\n";
14901
14903
14904 mg_send(nc, send.c_str(), send.length());
14905
14906 t->fTimeSent = GetTimeSec();
14907
14908 return RESPONSE_SENT;
14909 }
14910
14911#ifdef HAVE_MONGOOSE616
14912 if (multithread_mg)
14913 return queue_mjsonrpc(nc, origin_header, post_data, t);
14914#endif
14915
14916 //printf("post body: %s\n", post_data.c_str());
14917
14918 t->fRPC = post_data;
14919
14920#ifdef HAVE_MONGOOSE6
14922 assert(status == SS_SUCCESS);
14923#endif
14924
14925 //t->fTimeLocked = GetTimeSec();
14926
14927 MJsonNode* reply = mjsonrpc_decode_post_data(post_data.c_str());
14928
14929 //t->fTimeUnlocked = GetTimeSec();
14930
14931#ifdef HAVE_MONGOOSE6
14933#endif
14934
14935 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14936 const char* ptr;
14937 size_t size;
14938 reply->GetArrayBuffer(&ptr, &size);
14939
14940 std::string headers;
14941 headers += "HTTP/1.1 200 OK\n";
14942 if (origin_header.length() > 0)
14943 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14944 else
14945 headers += "Access-Control-Allow-Origin: *\n";
14946 headers += "Access-Control-Allow-Credentials: true\n";
14947 headers += "Content-Length: " + toString(size) + "\n";
14948 headers += "Content-Type: application/octet-stream\n";
14949 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14950
14951 //printf("sending headers: %s\n", headers.c_str());
14952 //printf("sending reply: %s\n", reply_string.c_str());
14953
14954 std::string send = headers + "\n";
14955
14957
14958 mg_send(nc, send.c_str(), send.length());
14959 mg_send(nc, ptr, size);
14960
14961 t->fTimeSent = GetTimeSec();
14962
14963 delete reply;
14964
14965 return RESPONSE_SENT;
14966 }
14967
14968 std::string reply_string = reply->Stringify();
14969 int reply_length = reply_string.length();
14970
14971 std::string headers;
14972 headers += "HTTP/1.1 200 OK\n";
14973 if (origin_header.length() > 0)
14974 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14975 else
14976 headers += "Access-Control-Allow-Origin: *\n";
14977 headers += "Access-Control-Allow-Credentials: true\n";
14978 headers += "Content-Length: " + toString(reply_length) + "\n";
14979 headers += "Content-Type: application/json\n";
14980 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14981
14982 //printf("sending headers: %s\n", headers.c_str());
14983 //printf("sending reply: %s\n", reply_string.c_str());
14984
14985 std::string send = headers + "\n" + reply_string;
14986
14988
14989 mg_send(nc, send.c_str(), send.length());
14990
14991 t->fTimeSent = GetTimeSec();
14992
14993 delete reply;
14994
14995 return RESPONSE_SENT;
14996 }
14997
14998 return handle_decode_post(nc, msg, uri, query_string.c_str(), t);
14999}
15000
15002{
15003 //
15004 // JSON-RPC CORS pre-flight request, see
15005 // https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
15006 //
15007 // OPTIONS /resources/post-here/ HTTP/1.1
15008 // Host: bar.other
15009 // User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
15010 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
15011 // Accept-Language: en-us,en;q=0.5
15012 // Accept-Encoding: gzip,deflate
15013 // Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
15014 // Connection: keep-alive
15015 // Origin: http://foo.example
15016 // Access-Control-Request-Method: POST
15017 // Access-Control-Request-Headers: X-PINGOTHER
15018 //
15019 // HTTP/1.1 200 OK
15020 // Date: Mon, 01 Dec 2008 01:15:39 GMT
15021 // Server: Apache/2.0.61 (Unix)
15022 // Access-Control-Allow-Origin: http://foo.example
15023 // Access-Control-Allow-Methods: POST, GET, OPTIONS
15024 // Access-Control-Allow-Headers: X-PINGOTHER
15025 // Access-Control-Max-Age: 1728000
15026 // Vary: Accept-Encoding, Origin
15027 // Content-Encoding: gzip
15028 // Content-Length: 0
15029 // Keep-Alive: timeout=2, max=100
15030 // Connection: Keep-Alive
15031 // Content-Type: text/plain
15032 //
15033
15034 const std::string origin_header = find_header_mg(msg, "Origin");
15035
15036 if (trace_mg||verbose_mg)
15037 printf("handle_http_options_cors: origin [%s]\n", origin_header.c_str());
15038
15039 std::string headers;
15040 headers += "HTTP/1.1 200 OK\n";
15041 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15042 if (origin_header.length() > 0)
15043 headers += "Access-Control-Allow-Origin: " + origin_header + "\n";
15044 else
15045 headers += "Access-Control-Allow-Origin: *\n";
15046 headers += "Access-Control-Allow-Headers: Content-Type\n";
15047 headers += "Access-Control-Allow-Credentials: true\n";
15048 headers += "Access-Control-Max-Age: 120\n";
15049 headers += "Content-Length: 0\n";
15050 headers += "Content-Type: text/plain\n";
15051 //printf("sending headers: %s\n", headers.c_str());
15052 //printf("sending reply: %s\n", reply.c_str());
15053
15054 std::string send = headers + "\n";
15055
15057
15058 mg_send(nc, send.c_str(), send.length());
15059
15060 t->fTimeSent = GetTimeSec();
15061}
15062
15063// HTTP event handler
15064
15065static bool mongoose_passwords_enabled(const struct mg_connection *nc);
15066
15067#ifdef HAVE_MONGOOSE616
15068static MVOdb* gProxyOdb = NULL;
15069#endif
15070
15072{
15073 std::string method = mgstr(&msg->method);
15074 std::string query_string = mgstr(&msg->query_string);
15075 std::string uri_encoded = mgstr(&msg->uri);
15076 std::string uri = UrlDecode(uri_encoded.c_str());
15077
15078 if (trace_mg)
15079 printf("handle_http_message: method [%s] uri [%s] proto [%s]\n", method.c_str(), uri.c_str(), mgstr(&msg->proto).c_str());
15080
15081 RequestTrace* t = new RequestTrace;
15083 t->fMethod = method;
15084 t->fUri = uri;
15085 t->fQuery = query_string;
15086
15087 // process OPTIONS for Cross-origin (CORS) preflight request
15088 // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
15089 if (method == "OPTIONS" && query_string == "mjsonrpc" && mg_get_http_header(msg, "Access-Control-Request-Method") != NULL) {
15090 handle_http_options_cors(nc, msg, t);
15091 t->fCompleted = true;
15093 return;
15094 }
15095
15097 std::string username = check_digest_auth(msg, gAuthMg);
15098
15099 // Cannot re-read the password file - it is not thread safe to do so
15100 // unless I lock gAuthMg for each call check_digest_auth() and if I do so,
15101 // I will serialize (single-thread) all the http requests and defeat
15102 // the whole point of multithreading the web server. K.O.
15103 //
15105 //if (username.length() < 1) {
15106 // bool ok = read_passwords(&gAuthMg);
15107 // if (ok)
15108 // username = check_digest_auth(msg, &gAuthMg);
15109 //}
15110
15111 if (trace_mg)
15112 printf("handle_http_message: auth user: \"%s\"\n", username.c_str());
15113
15114 if (username.length() == 0) {
15115 if (trace_mg||verbose_mg)
15116 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());
15117
15119 t->fCompleted = true;
15121 return;
15122 }
15123 t->fAuthOk = true;
15124 } else {
15125 t->fAuthOk = true;
15126 }
15127
15128#ifdef HAVE_MONGOOSE616
15129 if (gProxyOdb && starts_with(uri, "/proxy/")) {
15130 std::string::size_type p1 = uri.find("/", 1);
15131 if (p1 == uri.length()-1) {
15132 std::string response = "404 Not Found (Proxy name is missing)";
15133 mg_send_head(nc, 404, response.length(), NULL);
15134 mg_send(nc, response.c_str(), response.length());
15135 delete t;
15136 return;
15137 }
15138 std::string::size_type p2 = uri.find("/", p1+1);
15139 if (p2 == std::string::npos) {
15140 std::string response = "404 Not Found (Proxy URL should end with a slash)";
15141 mg_send_head(nc, 404, response.length(), NULL);
15142 mg_send(nc, response.c_str(), response.length());
15143 delete t;
15144 return;
15145 }
15146 std::string p = uri.substr(p1+1, p2-p1-1);
15147 //printf("uri [%s], p1: %d, p2: %d, substr: [%s]\n", uri.c_str(), (int)p1, (int)p2, p.c_str());
15148 if (p.length() < 1) {
15149 std::string response = "404 Not Found (Double-slash or Proxy name is too short)";
15150 mg_send_head(nc, 404, response.length(), NULL);
15151 mg_send(nc, response.c_str(), response.length());
15152 delete t;
15153 return;
15154 }
15155 std::string destination;
15156 gProxyOdb->RS(p.c_str(), &destination);
15157 if (destination.length() < 1) {
15158 std::string response = "404 Not Found (Proxy not found in ODB)";
15159 mg_send_head(nc, 404, response.length(), NULL);
15160 mg_send(nc, response.c_str(), response.length());
15161 delete t;
15162 return;
15163 } else if (destination[0] == '#') {
15164 std::string response = "404 Not Found (Proxy commented-out in ODB)";
15165 mg_send_head(nc, 404, response.length(), NULL);
15166 mg_send(nc, response.c_str(), response.length());
15167 delete t;
15168 return;
15169 } else if (ends_with_char(destination, '/')) {
15170 std::string response = "404 Not Found (Proxy address should not end with a slash)";
15171 mg_send_head(nc, 404, response.length(), NULL);
15172 mg_send(nc, response.c_str(), response.length());
15173 delete t;
15174 return;
15175 } else if (!starts_with(destination, "http")) {
15176 std::string response = "404 Not Found (Proxy address does not start with http";
15177 mg_send_head(nc, 404, response.length(), NULL);
15178 mg_send(nc, response.c_str(), response.length());
15179 delete t;
15180 return;
15181 } else {
15182 std::string m;
15183 m += "/proxy";
15184 m += "/";
15185 m += p;
15186 mg_str mount = mg_mk_str(m.c_str());
15188 if (verbose_mg||trace_mg) {
15189 printf("proxy: uri [%s] mount [%s] upstream [%s]\n", uri.c_str(), mgstr(&mount).c_str(), mgstr(&upstream).c_str());
15190 }
15192 delete t;
15193 return;
15194 }
15195 }
15196#endif
15197
15198 int response = RESPONSE_501;
15199
15200 if (method == "GET")
15201 response = handle_http_get(nc, msg, uri.c_str(), t);
15202 else if (method == "POST")
15203 response = handle_http_post(nc, msg, uri.c_str(), t);
15204
15205 if (response == RESPONSE_501) {
15206 if (trace_mg||verbose_mg)
15207 printf("handle_http_message: sending 501 Not Implemented error\n");
15208
15209 std::string response = "501 Not Implemented";
15210 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15211 mg_send(nc, response.c_str(), response.length());
15212 }
15213
15214 if (response != RESPONSE_QUEUED) {
15215 t->fCompleted = true;
15217 }
15218}
15219
15220#ifdef HAVE_MONGOOSE6
15221
15222static void handle_http_event_mg(struct mg_connection *nc, int ev, void *ev_data)
15223{
15224 switch (ev) {
15225 case MG_EV_HTTP_REQUEST:
15226 if (trace_mg)
15227 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15229 break;
15230 default:
15231 if (trace_mg)
15232 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15233 break;
15234 }
15235}
15236
15237static void handle_http_redirect(struct mg_connection *nc, int ev, void *ev_data)
15238{
15239 switch (ev) {
15240 case MG_EV_HTTP_REQUEST:
15241 {
15243 if (trace_mg)
15244 printf("handle_http_redirect: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15245
15246 mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: https://%s%s\r\n\r\n",
15247 ((std::string*)(nc->user_data))->c_str(),
15248 mgstr(&msg->uri).c_str());
15250 }
15251 break;
15252 default:
15253 if (trace_mg)
15254 printf("handle_http_redirect: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15255 }
15256}
15257
15258#endif
15259
15260#ifdef HAVE_MONGOOSE616
15261
15262// from mongoose examples/multithreaded/multithreaded.c
15263
15264//static sock_t s_sock[2];
15265static std::atomic_bool s_shutdown{false};
15266static struct mg_mgr s_mgr;
15267static std::atomic_int s_rseqno{1};
15268static std::mutex s_mg_broadcast_mutex;
15269
15270#if 0
15271// This info is passed to the worker thread
15272struct work_request {
15273 void* nc;
15275};
15276#endif
15277
15278// This info is passed by the worker thread to mg_broadcast
15279struct work_result {
15280 mg_connection* nc = NULL;
15281 uint32_t check = 0x12345678;
15282 int rseqno = 0;
15284 const char* p1 = NULL;
15285 size_t s1 = 0;
15286 const char* p2 = NULL;
15287 size_t s2 = 0;
15288 bool close_flag = false;
15289 bool send_501 = false;
15290};
15291
15292#if 0
15293static void mongoose_queue(void *nc, MongooseWorkObject *w)
15294{
15295 struct work_request req = {nc, w};
15296
15297 //printf("nc: %p: wseqno: %d, queue work object!\n", nc, w->wseqno);
15298
15299 if (write(s_sock[0], &req, sizeof(req)) < 0) {
15300 fprintf(stderr, "mongoose_queue: Error: write(s_sock(0)) error %d (%s)\n", errno, strerror(errno));
15301 abort();
15302 }
15303}
15304#endif
15305
15306static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data)
15307{
15308 (void) ev;
15309 struct work_result *res = (struct work_result *)ev_data;
15310
15311 assert(res != NULL);
15312 assert(res->w != NULL);
15313
15314 //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);
15315
15316 // check for correct connection, note that nc objects are reused and after a socket is closed
15317 // and a new one is opened, the same nc address and the same nc->sock can now refer to a completely
15318 // different tcp connection. So we check ncseqno instead of nc. K.O.
15319
15320 //if (res->nc != nc)
15321 //return;
15322
15323 if (GetNcSeqno(nc) != res->w->wncseqno)
15324 return;
15325
15326 //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);
15327
15328 if (res->send_501) {
15329 std::string response = "501 Not Implemented";
15330 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15331 mg_send(nc, response.c_str(), response.length());
15332 }
15333
15334 if (res->s1 > 0)
15335 mg_send(nc, res->p1, res->s1);
15336
15337 if (res->s2 > 0)
15338 mg_send(nc, res->p2, res->s2);
15339
15340 if (res->close_flag) {
15341 // cannot do pipelined http if response generated by mhttpd
15342 // decode_get() has no Content-Length header.
15343 // must close the connection.
15345 }
15346
15347 res->w->send_done = true;
15348}
15349
15350static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag)
15351{
15352 //printf("nc: %p: send %d and %d\n", nc, (int)s1, (int)s2);
15353 struct work_result res;
15354 res.nc = nc;
15355 res.w = w;
15356 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15357 res.p1 = p1;
15358 res.s1 = s1;
15359 res.p2 = p2;
15360 res.s2 = s2;
15361 res.close_flag = close_flag;
15362 res.send_501 = false;
15363 //printf("nc: %p: call mg_broadcast()\n", nc);
15364
15365 // NB: mg_broadcast() is advertised as thread-safe, but it is not.
15366 //
15367 // in mongoose 6.16, mg_brodacast() and mg_mgr_handle_ctl_sock() have several problems:
15368 //
15369 // a) "wrong thread" read from mgr->ctl[0], defeating the handshake
15370 //
15371 // b) "lost messages". if more than one message is written to mgr->ctl[0], the second message
15372 // will be "eaten" by mg_mgr_handle_ctl_sock() because of mistatch between number of bytes read and written
15373 // in the two functions. mg_mgr_handle_ctl_sock() always reads about 8000 bytes while mg_broadcast()
15374 // writes 8 bytes per message, (per examples/multithreaded/multithreaded.c. mhttpd messages are a bit longer).
15375 // So if multiple messages are present in the msg->ctl[0] pipe, the read call (of about 8000 bytes)
15376 // in mg_mgr_handle_ctl_sock() will return several messages (last message may be truncated)
15377 // but only the first message will be processed by the code. any additional messages are ignored.
15378 //
15379 // Problems (a) and (b) are easy to fix by using a mutex to serialize mg_broadcast().
15380 //
15381 // c) if the mg_broadcast() message contains pointers to the data buffer to be sent out,
15382 // the caller of mg_broadcast() should not free these data buffers until mg_send() is called
15383 // in "on_work_complete()". In theory, the caller of mg_broadcast() could wait until on_work_complete()
15384 // sets a "done" flag. In practice, if the corresponding network connection is closed before
15385 // mg_mgr_handle_ctl_sock() has looped over it, on_work_complete() will never run
15386 // and the "done" flag will never be set. (Of course, network connections are permitted to close
15387 // at any time without warning, but) the firefox browser closes the network connections "a lot"
15388 // especially when user pressed the "page reload" button at the moment when HTTP transations
15389 // are "in flight". (google-chrome tends to permit these "lame duck" transactions to complete and mongoose
15390 // does not see unexpected socket closures, at least not as many).
15391 //
15392 // To fix problem (c) I need to know when mg_mgr_handle_ctl_sock()'s loop over network connections
15393 // has completed (two cases: (a) my on_work_complete() was hopefully called and finished,
15394 // and (b) the "right" network connection was already closed (for whatever reason) and my on_work_complete()
15395 // was never called).
15396 //
15397 // My solution is to change the handshake between mg_broadcast() and mg_mgr_handle_ctl_sock() by sending
15398 // the handshake reply after looping over the network connections instead of after reading the message
15399 // from msg->ctl[1].
15400 //
15401 // This requires a modification to the code in mongoose.c. If this change is lost/undone, nothing will work.
15402 //
15403
15404 s_mg_broadcast_mutex.lock();
15405 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15406 s_mg_broadcast_mutex.unlock();
15407}
15408
15410{
15411 struct work_result res;
15412 res.nc = nc;
15413 res.w = w;
15414 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15415 res.p1 = 0;
15416 res.s1 = 0;
15417 res.p2 = 0;
15418 res.s2 = 0;
15419 res.close_flag = false;
15420 res.send_501 = true;
15421 //printf("nc: %p, call mg_broadcast()\n", nc);
15422
15423 s_mg_broadcast_mutex.lock();
15424 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15425 s_mg_broadcast_mutex.unlock();
15426}
15427
15428#if 0
15429void *worker_thread_proc(void *param)
15430{
15431 //struct mg_mgr *mgr = (struct mg_mgr *) param;
15432 struct work_request req = {0};
15433
15434 while ((! _abort) && (! s_shutdown)) {
15435 int rd = read(s_sock[1], &req, sizeof(req));
15436 if (rd == 0) {
15437 // socket closed, shutdown the thread
15438 break;
15439 }
15440 if (rd < 0) {
15441 if (_abort || s_shutdown) {
15442 return NULL;
15443 }
15444 fprintf(stderr, "worker_thread_proc: Error: read(s_sock(1)) returned %d, error %d (%s)\n", rd, errno, strerror(errno));
15445 abort();
15446 return NULL;
15447 }
15448
15449 //printf("nc: %p: received request!\n", req.nc);
15450
15451 int response = thread_work_function(req.nc, req.w);
15452
15453 if (response == RESPONSE_501) {
15454 if (trace_mg||verbose_mg)
15455 printf("handle_http_message: sending 501 Not Implemented error\n");
15456 mongoose_send_501(req.nc, req.w);
15457 }
15458
15459 req.w->t->fCompleted = true;
15460 gTraceBuf->AddTraceMTS(req.w->t);
15461
15462 //printf("nc: %p: wseqno: %d, delete work object!\n", req.nc, req.w->wseqno);
15463
15464 delete req.w;
15465 req.w = NULL;
15466 }
15467 return NULL;
15468}
15469#endif
15470
15472{
15473 //printf("to %p, nc %p: thread %p started!\n", to, to->fNc, to->fThread);
15474
15475 std::unique_lock<std::mutex> ulm(to->fMutex, std::defer_lock);
15476
15477 to->fIsRunning = true;
15478
15479 while ((! _abort) && (! s_shutdown)) {
15481
15482 ulm.lock();
15483 while (to->fQueue.empty()) {
15484 //printf("to %p, nc %p, thread %p: waiting!\n", to, to->fNc, to->fThread);
15485 to->fNotify.wait(ulm);
15486 if (_abort || s_shutdown) {
15487 break;
15488 }
15489 }
15490
15491 if (_abort || s_shutdown) {
15492 break;
15493 }
15494
15495 w = to->fQueue.front();
15496 to->fQueue.pop_front();
15497 ulm.unlock();
15498
15499 //printf("to %p, nc %p: wseqno: %d, received request!\n", to, w->nc, w->wseqno);
15500
15501 int response = thread_work_function(w->nc, w);
15502
15503 if (response == RESPONSE_501) {
15504 if (trace_mg||verbose_mg)
15505 printf("handle_http_message: sending 501 Not Implemented error\n");
15506 mongoose_send_501(w->nc, w);
15507 }
15508
15509 // mg_broadcast() called on_work_complete() on the main thread and waited until it finished
15510
15511 if (!w->send_done) {
15512 // NB: careful here, if connection nc was closed, pointer nc points to nowhere! do not dereference it!
15513 // NB: stay quiet about it, nothing special about network connctions closing and opening as they wish.
15514 //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);
15515 }
15516
15517 w->t->fCompleted = true;
15518 gTraceBuf->AddTraceMTS(w->t);
15519
15520 //printf("nc: %p: wseqno: %d, delete work object!\n", w->nc, w->wseqno);
15521
15522 delete w;
15523 }
15524
15525 to->fIsRunning = false;
15526
15527 //printf("to %p, nc %p: thread %p finished!\n", to, to->fNc, to->fThread);
15528}
15529
15530static bool mongoose_hostlist_enabled(const struct mg_connection *nc);
15531
15532static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
15533{
15534 (void) nc;
15535 (void) ev_data;
15536
15537 //if (trace_mg && ev != 0) {
15538 // printf("ev_handler: connection %p, event %d\n", nc, ev);
15539 //}
15540
15541 switch (ev) {
15542 case 0:
15543 break;
15544 default: {
15545 if (trace_mg) {
15546 printf("ev_handler: connection %p, event %d\n", nc, ev);
15547 }
15548 break;
15549 }
15550 case MG_EV_ACCEPT:
15551 assert(nc->user_data == NULL);
15552 nc->user_data = new MongooseNcUserData();
15553
15554 if (trace_mg) {
15555 printf("ev_handler: connection %p, MG_EV_ACCEPT, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15556 }
15557 if (s_shutdown) {
15558 //printf("XXX nc %p!\n", nc);
15560 } else if (mongoose_hostlist_enabled(nc)) {
15561 if (!mongoose_check_hostlist(&nc->sa)) {
15563 }
15564 }
15565 break;
15566 case MG_EV_RECV:
15567 if (trace_mg_recv) {
15568 printf("ev_handler: connection %p, MG_EV_RECV, %d bytes\n", nc, *(int*)ev_data);
15569 }
15570 if (s_shutdown) {
15571 //printf("RRR nc %p!\n", nc);
15573 }
15574 break;
15575 case MG_EV_SEND:
15576 if (trace_mg_send) {
15577 printf("ev_handler: connection %p, MG_EV_SEND, %d bytes\n", nc, *(int*)ev_data);
15578 }
15579 break;
15580 case MG_EV_HTTP_CHUNK: {
15581 if (trace_mg) {
15582 printf("ev_handler: connection %p, MG_EV_HTTP_CHUNK\n", nc);
15583 }
15584 if (s_shutdown) {
15585 //printf("RRR1 nc %p!\n", nc);
15587 }
15588 break;
15589 }
15590 case MG_EV_HTTP_REQUEST: {
15591 struct http_message* msg = (struct http_message*)ev_data;
15592 if (trace_mg) {
15593 printf("ev_handler: connection %p, MG_EV_HTTP_REQUEST \"%s\" \"%s\"\n", nc, mgstr(&msg->method).c_str(), mgstr(&msg->uri).c_str());
15594 }
15595 if (s_shutdown) {
15596 //printf("RRR2 nc %p!\n", nc);
15598 } else {
15599 handle_http_message(nc, msg);
15600 }
15601 break;
15602 }
15603 case MG_EV_CLOSE: {
15604 if (trace_mg) {
15605 printf("ev_handler: connection %p, MG_EV_CLOSE, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15606 }
15607 //printf("CCC nc %p!\n", nc);
15608 FreeThread(nc);
15609 if (nc->user_data) {
15611 nc->user_data = NULL;
15612 delete ncud;
15613 ncud = NULL;
15614 }
15615 }
15616 }
15617}
15618
15619#define FLAG_HTTPS MG_F_USER_1
15620#define FLAG_PASSWORDS MG_F_USER_2
15621#define FLAG_HOSTLIST MG_F_USER_3
15622
15623static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15624{
15625 int flags = 0;
15626 if (nc && nc->listener) {
15627 flags = nc->listener->flags;
15628 }
15629 //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);
15630 return flags & FLAG_PASSWORDS;
15631}
15632
15633static bool mongoose_hostlist_enabled(const struct mg_connection *nc)
15634{
15635 int flags = 0;
15636 if (nc && nc->listener) {
15637 flags = nc->listener->flags;
15638 }
15639 //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);
15640 return flags & FLAG_HOSTLIST;
15641}
15642
15643static int mongoose_listen(const char* address, int flags)
15644{
15645#if MG_ENABLE_SSL
15646#else
15647 if (flags & FLAG_HTTPS) {
15648 cm_msg(MERROR, "mongoose_listen", "https port \"%s\" requested, but mhttpd compiled without MG_ENABLE_SSL", address);
15649 return SS_SOCKET_ERROR;
15650 }
15651#endif
15652
15653 struct mg_connection *nc = mg_bind(&s_mgr, address, ev_handler);
15654 if (nc == NULL) {
15655 cm_msg(MERROR, "mongoose_listen", "Cannot mg_bind address \"%s\"", address);
15656 return SS_SOCKET_ERROR;
15657 }
15658
15659 if (flags & FLAG_HTTPS) {
15660#if MG_ENABLE_SSL
15661 std::string cert_file;
15662
15663 int status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
15664
15665 if (status != SUCCESS) {
15666 cm_msg(MERROR, "mongoose_listen", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
15667 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");
15668 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");
15669 return SS_FILE_ERROR;
15670 }
15671
15672 printf("Mongoose web server will use https certificate file \"%s\"\n", cert_file.c_str());
15673
15674 const char* errmsg = mg_set_ssl(nc, cert_file.c_str(), NULL);
15675 if (errmsg) {
15676 cm_msg(MERROR, "mongoose_listen", "Cannot enable https with certificate file \"%s\", error: %s", cert_file.c_str(), errmsg);
15677 return SS_SOCKET_ERROR;
15678 }
15679
15680 // NB: where is the warning that the SSL certificate has expired?!? K.O.
15681#else
15682 abort(); // cannot happen!
15683#endif
15684 }
15685
15687
15688 nc->flags |= flags;
15689
15690 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");
15691
15692 return SUCCESS;
15693}
15694
15695static int mongoose_init(MVOdb* odb, bool no_passwords, bool no_hostlist, const std::vector<std::string>& user_hostlist)
15696{
15697 bool enable_localhost_port = true;
15698 int localhost_port = 8080;
15699 bool localhost_port_passwords = false;
15700
15701 bool enable_insecure_port = false;
15702 int insecure_port = 8081;
15703 bool insecure_port_passwords = true;
15704 bool insecure_port_hostlist = true;
15705
15706 bool enable_https_port = false;
15707 int https_port = 8443;
15708 bool https_port_passwords = true;
15709 bool https_port_hostlist = false;
15710
15711 std::vector<std::string> hostlist;
15712 hostlist.push_back("localhost");
15713
15714 bool enable_ipv6 = true;
15715
15716 odb->RB("Enable localhost port", &enable_localhost_port, true);
15717 odb->RI("localhost port", &localhost_port, true);
15718 odb->RB("localhost port passwords", &localhost_port_passwords, true);
15719 odb->RB("Enable insecure port", &enable_insecure_port, true);
15720 odb->RI("insecure port", &insecure_port, true);
15721 odb->RB("insecure port passwords", &insecure_port_passwords, true);
15722 odb->RB("insecure port host list", &insecure_port_hostlist, true);
15723 odb->RB("Enable https port", &enable_https_port, true);
15724 odb->RI("https port", &https_port, true);
15725 odb->RB("https port passwords", &https_port_passwords, true);
15726 odb->RB("https port host list", &https_port_hostlist, true);
15727 odb->RSA("Host list", &hostlist, true, 10, 256);
15728 odb->RB("Enable IPv6", &enable_ipv6, true);
15729
15730 // populate the MIME.types table
15731 gProxyOdb = odb->Chdir("Proxy", true);
15732 std::string proxy_example = "#http://localhost:8080";
15733 gProxyOdb->RS("example", &proxy_example, true);
15734
15735 // populate the MIME.types table
15736 SaveMimetypes(odb->Chdir("mime.types", true));
15737
15738 if (!no_passwords
15742 gAuthMg = new Auth();
15743 int status = gAuthMg->Init();
15744 if (status != SUCCESS) {
15745 printf("mongoose_init: Error: Cannot initialize authorization object!\n");
15746 return status;
15747 }
15748 printf("HTTP Digest authentication with realm \"%s\" and password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
15749 } else {
15750 printf("Password protection is off\n");
15751 }
15752
15753 if (!no_hostlist
15756 gAllowedHosts.clear();
15757
15758 // copy the user allowed hosts
15759 for (unsigned int i=0; i<user_hostlist.size(); i++)
15760 gAllowedHosts.push_back(user_hostlist[i]);
15761
15762 for (unsigned i=0; i<hostlist.size(); i++) {
15763 std::string s = hostlist[i];
15764 if (s.length() < 1) // skip emties
15765 continue;
15766
15767 if (s[0] == '#') // skip commented-out entries
15768 continue;
15769
15770 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
15771 gAllowedHosts.push_back(s);
15772 }
15773
15774 printf("Hostlist active, connections will be accepted only from: ");
15775 for (unsigned i=0; i<gAllowedHosts.size(); i++) {
15776 if (i>0)
15777 printf(", ");
15778 printf("%s", gAllowedHosts[i].c_str());
15779 }
15780 printf("\n");
15781 } else {
15782 printf("Hostlist off, connections from anywhere will be accepted\n");
15783 }
15784
15786
15787 bool listen_failed = false;
15788
15790 char str[256];
15791 sprintf(str, "localhost:%d", localhost_port);
15792 int status = mongoose_listen(str, 0);
15793 if (status != SUCCESS)
15794 listen_failed = true;
15795 if (enable_ipv6) {
15796 sprintf(str, "[::1]:%d", localhost_port);
15798 if (status != SUCCESS)
15799 listen_failed = true;
15800 }
15801 }
15802
15804 char str[256];
15805 int flags = 0;
15810 if (enable_ipv6) {
15811 sprintf(str, "[::]:%d", insecure_port);
15813 if (status != SUCCESS)
15814 listen_failed = true;
15815 } else {
15816 sprintf(str, "%d", insecure_port);
15818 if (status != SUCCESS)
15819 listen_failed = true;
15820 }
15821 }
15822
15823 if (enable_https_port) {
15824 char str[256];
15825 int flags = 0;
15830 flags |= FLAG_HTTPS;
15831 if (enable_ipv6) {
15832 sprintf(str, "[::]:%d", https_port);
15834 if (status != SUCCESS)
15835 listen_failed = true;
15836 } else {
15837 sprintf(str, "%d", https_port);
15839 if (status != SUCCESS)
15840 listen_failed = true;
15841 }
15842 }
15843
15844 if (listen_failed) {
15845 cm_msg(MERROR, "mongoose_init", "Failed to listen on a TCP port enabled in ODB /WebServer");
15846 return SS_SOCKET_ERROR;
15847 }
15848
15849 return SUCCESS;
15850}
15851
15852static void mongoose_poll(int msec = 200)
15853{
15855}
15856
15857static void mongoose_cleanup()
15858{
15859 printf("Mongoose web server shutting down\n");
15860
15861 s_shutdown = true;
15862
15863 // close listener sockets
15864 if (s_mgr.active_connections) {
15865 struct mg_connection* nc = s_mgr.active_connections;
15866 while (nc) {
15867 //printf("nc %p, next %p, user_data %p, listener %p, flags %lu\n", nc, nc->next, nc->user_data, nc->listener, nc->flags);
15868 if (nc->flags & MG_F_LISTENING) {
15870 }
15871 nc = nc->next;
15872 }
15873 }
15874
15875 // tell threads to shut down
15876 for (auto it : gMongooseThreads) {
15878 to->fNotify.notify_one();
15879 }
15880
15881 // wait until all threads stop
15882 for (int i=0; i<10; i++) {
15883 int count_running = 0;
15884 for (auto it : gMongooseThreads) {
15886 //printf("AAA6C %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15887 if (to->fIsRunning) {
15888 count_running++;
15889 }
15890 }
15891 printf("Mongoose web server shutting down, %d threads still running\n", count_running);
15892 if (count_running == 0)
15893 break;
15894 mongoose_poll(1000);
15895 }
15896
15897 // delete thread objects
15898 for (auto it : gMongooseThreads) {
15900 //printf("AAA7B %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15901 if (to->fIsRunning) {
15902 cm_msg(MERROR, "mongoose", "thread failed to shut down");
15903 continue;
15904 }
15905 to->fThread->join();
15906 delete to->fThread;
15907 delete to;
15908 }
15909 gMongooseThreads.clear();
15910
15912
15913 //closesocket(s_sock[0]);
15914 //closesocket(s_sock[1]);
15915
15916 // make leak sanitizer happy!
15917 for (auto e : gHostlistCache) {
15918 delete e;
15919 }
15920 gHostlistCache.clear();
15921 if (gProxyOdb) {
15922 delete gProxyOdb;
15923 gProxyOdb = NULL;
15924 }
15925 if (gMimeTypesOdb) {
15926 delete gMimeTypesOdb;
15928 }
15929
15930 printf("Mongoose web server shut down\n");
15931}
15932
15933#endif
15934
15935#ifdef HAVE_MONGOOSE6
15936
15937static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15938{
15939 return true;
15940}
15941
15943{
15944 HNDLE hDB;
15945 int size;
15946 int status;
15947
15948 //if (verbose)
15949 // trace_mg = true;
15950
15951 if (verbose)
15952 verbose_mg = true;
15953
15955 assert(status == CM_SUCCESS);
15956
15957 int http_port = 8080;
15958 int https_port = 8443;
15959 int http_redirect_to_https = 1;
15960
15961 size = sizeof(http_port);
15962 db_get_value(hDB, 0, "/Experiment/midas http port", &http_port, &size, TID_INT, TRUE);
15963
15964 size = sizeof(https_port);
15965 db_get_value(hDB, 0, "/Experiment/midas https port", &https_port, &size, TID_INT, TRUE);
15966
15967 size = sizeof(http_redirect_to_https);
15968 db_get_value(hDB, 0, "/Experiment/http redirect to https", &http_redirect_to_https, &size, TID_BOOL, TRUE);
15969
15970 bool need_cert_file = false;
15971 bool need_password_file = false;
15972
15973 if (user_http_port)
15975
15976 if (user_https_port)
15978
15979 if (https_port) {
15980 need_cert_file = true;
15981 need_password_file = true;
15982 }
15983
15984 if (!https_port)
15986
15988 // no passwords serving over http unless
15989 // http is just a redict to https
15990 need_password_file = false;
15991 }
15992
15993 if (socket_priviledged_port >= 0) {
15994 // no passwords if serving unencrypted http on port 80
15995 need_password_file = false;
15996 printf("Mongoose web server password portection is disabled: serving unencrypted http on port 80\n");
15997 }
15998
15999 bool have_at_least_one_port = false;
16000
16001 std::string cert_file;
16002
16003 if (need_cert_file) {
16004 status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
16005
16006 if (status != SUCCESS) {
16007 cm_msg(MERROR, "mongoose", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
16008 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");
16009 return SS_FILE_ERROR;
16010 }
16011
16012 printf("Mongoose web server will use SSL certificate file \"%s\"\n", cert_file.c_str());
16013 }
16014
16015 if (need_password_file) {
16016 gAuthMg = new Auth();
16017 status = gAuthMg->Init();
16018 if (status != SUCCESS) {
16019 printf("Error: Cannot initialize authorization object!\n");
16020 return status;
16021 }
16022 printf("Mongoose web server will use authentication realm \"%s\", password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
16023 } else {
16024 printf("Mongoose web server will not use password protection\n");
16025 }
16026
16027 if (trace_mg)
16028 printf("start_mg!\n");
16029
16030#ifndef OS_WINNT
16032#endif
16033
16034 if (!gTraceBuf) {
16036 }
16037
16038 if (!request_mutex) {
16040 assert(status==SS_SUCCESS || status==SS_CREATED);
16041 }
16042
16044
16045 // use socket bound to priviledged port (setuid-mode)
16046 if (socket_priviledged_port >= 0) {
16048 if (nc == NULL) {
16049 cm_msg(MERROR, "mongoose", "Cannot create mg_connection for set-uid-root privileged port");
16050 return SS_SOCKET_ERROR;
16051 }
16052
16053 nc->flags |= MG_F_LISTENING;
16054#ifdef MG_ENABLE_THREADS
16056#endif
16059
16061 printf("mongoose web server is listening on the set-uid-root privileged port\n");
16062 }
16063
16064 if (http_port != 80) { // port 80 is already handled by socket_priviledged_port
16065 char str[256];
16066 sprintf(str, "%d", http_port);
16068 if (nc == NULL) {
16069 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", http_port);
16070 return SS_SOCKET_ERROR;
16071 }
16072
16073#ifdef MG_ENABLE_THREADS
16075#endif
16077
16079 std::string hostname = ss_gethostname();
16080 char str[256];
16081 sprintf(str, "%d", https_port);
16082 std::string s = hostname + ":" + std::string(str);
16083 nc->user_data = new std::string(s);
16085 printf("mongoose web server is redirecting HTTP port %d to https://%s\n", http_port, s.c_str());
16086 } else {
16088 }
16089
16091 printf("mongoose web server is listening on the HTTP port %d\n", http_port);
16092 }
16093
16094 if (https_port) {
16095#ifdef MG_ENABLE_SSL
16096 char str[256];
16097 sprintf(str, "%d", https_port);
16099 if (nc == NULL) {
16100 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", https_port);
16101 return SS_SOCKET_ERROR;
16102 }
16103
16104 mg_set_ssl(nc, cert_file.c_str(), NULL);
16105#ifdef MG_ENABLE_THREADS
16107#endif
16110
16112 printf("mongoose web server is listening on the HTTPS port %d\n", https_port);
16113#else
16114 cm_msg(MERROR, "mongoose", "https port %d requested, but mhttpd compiled without MG_ENABLE_SSL", https_port);
16115 return SS_SOCKET_ERROR;
16116#endif
16117 }
16118
16120 cm_msg(MERROR, "mongoose", "cannot start: no ports defined");
16121 return SS_FILE_ERROR;
16122 }
16123
16124 return SUCCESS;
16125}
16126
16127int stop_mg()
16128{
16129 if (trace_mg)
16130 printf("stop_mg!\n");
16131
16132 // Stop the server.
16134
16135 if (trace_mg)
16136 printf("stop_mg done!\n");
16137 return SUCCESS;
16138}
16139
16140int loop_mg()
16141{
16142 int status = SUCCESS;
16143
16144 /* establish Ctrl-C handler - will set _abort to TRUE */
16146
16147 while (!_abort) {
16148
16149 /* cm_yield() is not thread safe, need to take a lock */
16150
16151#ifdef HAVE_MONGOOSE6
16153#endif
16154 gMutex.lock();
16155
16156 /* check for shutdown message */
16157 status = cm_yield(0);
16158 if (status == RPC_SHUTDOWN)
16159 break;
16160
16161 gMutex.unlock();
16162#ifdef HAVE_MONGOOSE6
16164#endif
16165
16166 //ss_sleep(10);
16167
16168 mg_mgr_poll(&mgr_mg, 10);
16169 }
16170
16171 return status;
16172}
16173#endif
16174
16175static MJsonNode* get_http_trace(const MJsonNode* params)
16176{
16177 if (!params) {
16178 MJSO *doc = MJSO::I();
16179 doc->D("get current value of mhttpd http_trace");
16180 doc->P(NULL, 0, "there are no input parameters");
16181 doc->R(NULL, MJSON_INT, "current value of http_trace");
16182 return doc;
16183 }
16184
16185 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16186}
16187
16188static MJsonNode* set_http_trace(const MJsonNode* params)
16189{
16190 if (!params) {
16191 MJSO* doc = MJSO::I();
16192 doc->D("set new value of mhttpd http_trace");
16193 doc->P(NULL, MJSON_INT, "new value of http_trace");
16194 doc->R(NULL, MJSON_INT, "new value of http_trace");
16195 return doc;
16196 }
16197
16198 http_trace = params->GetInt();
16199 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16200}
16201
16203{
16204 mjsonrpc_add_handler("set_http_trace", set_http_trace);
16205 mjsonrpc_add_handler("get_http_trace", get_http_trace);
16206}
16207
16208/*------------------------------------------------------------------*/
16209
16210int main(int argc, const char *argv[])
16211{
16212 int status;
16213 int daemon = FALSE;
16214#ifdef HAVE_MONGOOSE6
16215 int user_http_port = 0;
16216 int user_https_port = 0;
16217#endif
16218#ifdef HAVE_MONGOOSE616
16219 bool no_passwords = false;
16220 bool no_hostlist = false;
16221#endif
16222 const char *myname = "mhttpd";
16223
16224 setbuf(stdout, NULL);
16225 setbuf(stderr, NULL);
16226#ifdef SIGPIPE
16227 /* avoid getting killed by "Broken pipe" signals */
16229#endif
16230
16231#ifdef HAVE_MONGOOSE6
16232 //
16233 // if running setuid-root, unconditionally bind to port 80.
16234 //
16235
16236 int socket_priviledged_port = -1;
16237
16238#ifdef OS_UNIX
16239 // in setuid-root mode bind to priviledged port
16240 if (getuid() != geteuid()) {
16241 int port80 = 80;
16242
16243 printf("mhttpd is running in setuid-root mode.\n");
16244
16246 if (socket_priviledged_port < 0) {
16247 printf("Cannot open listening socket on TCP port %d, aborting.\n", port80);
16248 exit(1);
16249 }
16250
16251 // give up root privilege
16252 status = setuid(getuid());
16253 if (status != 0) {
16254 printf("Cannot give up root privelege, aborting.\n");
16255 exit(1);
16256 }
16257 status = setuid(getuid());
16258 if (status != 0) {
16259 printf("Cannot give up root privelege, aborting.\n");
16260 exit(1);
16261 }
16262 }
16263#endif
16264#endif
16265
16266 char midas_hostname[256];
16267 char midas_expt[256];
16268
16269 /* get default from environment */
16271
16272 /* parse command line parameters */
16273#ifdef HAVE_MONGOOSE6
16274 gUserAllowedHosts.clear();
16275#else
16276 std::vector<std::string> user_hostlist;
16277#endif
16278 for (int i = 1; i < argc; i++) {
16279 if (argv[i][0] == '-' && argv[i][1] == 'D')
16280 daemon = TRUE;
16281 else if (argv[i][0] == '-' && argv[i][1] == 'v')
16282 verbose = TRUE;
16283 else if (argv[i][0] == '-' && argv[i][1] == 'E')
16284 elog_mode = TRUE;
16285 else if (argv[i][0] == '-' && argv[i][1] == 'H') {
16287#ifdef HAVE_MONGOOSE6
16288 } else if (strcmp(argv[i], "--http") == 0) {
16289 if (argv[i+1]) {
16290 user_http_port = atoi(argv[i+1]);
16291 }
16292 } else if (strcmp(argv[i], "--https") == 0) {
16293 if (argv[i+1]) {
16294 user_https_port = atoi(argv[i+1]);
16295 }
16296#endif
16297 } else if (strcmp(argv[i], "--trace-mg") == 0) {
16298 trace_mg = true;
16299 trace_mg_recv = true;
16300 trace_mg_send = true;
16301 } else if (strcmp(argv[i], "--no-trace-mg-recv") == 0) {
16302 trace_mg_recv = false;
16303 } else if (strcmp(argv[i], "--no-trace-mg-send") == 0) {
16304 trace_mg_send = false;
16305 } else if (strcmp(argv[i], "--verbose-mg") == 0) {
16306 verbose_mg = true;
16307#ifdef HAVE_MONGOOSE616
16308 } else if (strcmp(argv[i], "--no-multithread") == 0) {
16309 multithread_mg = false;
16310 } else if (strcmp(argv[i], "--no-passwords") == 0) {
16311 no_passwords = true;
16312 } else if (strcmp(argv[i], "--no-hostlist") == 0) {
16313 no_hostlist = true;
16314#endif
16315 } else if (argv[i][0] == '-') {
16316 if (i + 1 >= argc || argv[i + 1][0] == '-')
16317 goto usage;
16318 if (argv[i][1] == 'h')
16320 else if (argv[i][1] == 'e')
16321 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
16322 else if (argv[i][1] == 'a') {
16323#ifdef HAVE_MONGOOSE6
16324 gUserAllowedHosts.push_back(argv[++i]);
16325#else
16326 user_hostlist.push_back(argv[++i]);
16327#endif
16328 } else if (argv[i][1] == 'p') {
16329 printf("Option \"-p port_number\" for the old web server is obsolete.\n");
16330 printf("mongoose web server is the new default, port number is set in ODB or with \"--http port_number\".\n");
16331 printf("To run the obsolete old web server, please use \"--oldserver\" switch.\n");
16332 return 1;
16333 } else {
16334 usage:
16335 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-v] [-D] [-a Hostname]\n\n", argv[0]);
16336 printf(" -a add hostname to the hostlist of hosts allowed to connect to mhttpd\n");
16337 printf(" -e experiment to connect to\n");
16338 printf(" -h connect to midas server (mserver) on given host\n");
16339 printf(" -v display verbose HTTP communication\n");
16340 printf(" -D become a daemon\n");
16341 printf(" -E only display ELog system\n");
16342 printf(" -H only display history plots\n");
16343#ifdef HAVE_MONGOOSE6
16344 printf(" --http port - bind to specified HTTP port (default is ODB \"/Experiment/midas http port\")\n");
16345 printf(" --https port - bind to specified HTTP port (default is ODB \"/Experiment/midas https port\")\n");
16346#endif
16347 printf(" --verbose-mg - trace mongoose web requests\n");
16348 printf(" --trace-mg - trace mongoose events\n");
16349 printf(" --no-trace-mg-recv - do not trace mongoose recv events\n");
16350 printf(" --no-trace-mg-send - dop not trace mongoose send events\n");
16351#ifdef HAVE_MONGOOSE616
16352 printf(" --no-multithread - disable mongoose multithreading\n");
16353 printf(" --no-passwords - disable password protection\n");
16354 printf(" --no-hostlist - disable access control host list\n");
16355#endif
16356 return 0;
16357 }
16358 }
16359 }
16360
16361 if (daemon) {
16362 printf("Becoming a daemon...\n");
16364 }
16365
16366#ifdef OS_LINUX
16367 /* write PID file */
16368 FILE *f = fopen("/var/run/mhttpd.pid", "w");
16369 if (f != NULL) {
16370 fprintf(f, "%d", ss_getpid());
16371 fclose(f);
16372 }
16373#endif
16374
16375 if (history_mode)
16376 myname = "mhttpd_history";
16377
16378 /*---- connect to experiment ----*/
16382 return 1;
16383 else if (status == DB_INVALID_HANDLE) {
16384 std::string s = cm_get_error(status);
16385 puts(s.c_str());
16386 } else if (status != CM_SUCCESS) {
16387 std::string s = cm_get_error(status);
16388 puts(s.c_str());
16389 return 1;
16390 }
16391
16392 /* mhttpd needs the watchdog thread until we are sure
16393 * we do not have any long sleeps anywhere in the mhttpd code.
16394 * this includes reads from the history files or databases,
16395 * that can take arbitrary long time */
16397
16398 /* Get ODB handles */
16399
16400 HNDLE hDB;
16401
16403
16404 MVOdb *odb = MakeMidasOdb(hDB);
16405 gOdb = odb;
16406
16407 /* do ODB record checking */
16408 if (!check_odb_records(odb)) {
16409 // check_odb_records() fails with nothing printed to the terminal
16410 // because mhttpd does not print cm_msg(MERROR, ...) messages to the terminal.
16411 // At least print something!
16412 printf("check_odb_records() failed, see messages and midas.log, bye!\n");
16414 return 1;
16415 }
16416
16417#ifdef HAVE_MONGOOSE6
16418 if (init_allowed_hosts() != SUCCESS) {
16419 printf("init_allowed_hosts() failed, see messages and midas.log, bye!\n");
16421 return 1;
16422 }
16423
16424 if (verbose) {
16425 if (gAllowedHosts.size() > 0) {
16426 printf("mhttpd allowed hosts list: ");
16427 for (unsigned int i=0; i<gAllowedHosts.size(); i++) {
16428 if (i>0)
16429 printf(", ");
16430 printf("%s", gAllowedHosts[i].c_str());
16431 }
16432 printf("\n");
16433 } else {
16434 printf("mhttpd allowed hosts list is empty\n");
16435 }
16436 }
16437
16438 // populate the MIME.types table
16439 SaveMimetypes(odb->Chdir("WebServer/mime.types", true));
16440#endif
16441
16442 /* initialize odb entries needed for mhttpd and midas web pages */
16443 init_mhttpd_odb(odb);
16444
16445 /* initialize menu buttons */
16446 init_menu_buttons(odb);
16447
16448 /* initialize elog odb entries */
16449 init_elog_odb();
16450
16451 /* initialize the JSON RPC handlers */
16452 mjsonrpc_init();
16454
16456
16457#ifdef HAVE_MONGOOSE6
16459 if (status != SUCCESS) {
16460 // At least print something!
16461 printf("could not start the mongoose web server, see messages and midas.log, bye!\n");
16463 return 1;
16464 }
16465#endif
16466
16467#ifdef HAVE_MONGOOSE616
16468
16469#ifdef SIGPIPE
16470#ifdef SIG_IGN
16472#endif
16473#endif
16474
16475 if (!gTraceBuf) {
16477 }
16478
16479 //if (!request_mutex) {
16480 // status = ss_mutex_create(&request_mutex, FALSE);
16481 // assert(status==SS_SUCCESS || status==SS_CREATED);
16482 //}
16483
16484 /* establish Ctrl-C handler - will set _abort to TRUE */
16486
16487 MVOdb* o = odb->Chdir("WebServer", true);
16489 if (status != SUCCESS) {
16490 // At least print something!
16491 printf("Error: Could not start the mongoose web server, see messages and midas.log, bye!\n");
16493 return 1;
16494 }
16495
16496 delete o;
16497#endif
16498
16499#ifdef HAVE_MONGOOSE6
16500 loop_mg();
16501 stop_mg();
16502#endif
16503
16504#ifdef HAVE_MONGOOSE616
16505 while (!_abort) {
16506
16507 /* cm_yield() is not thread safe, need to take a lock */
16508
16509 //status = ss_mutex_wait_for(request_mutex, 0);
16510 gMutex.lock();
16511
16512 /* check for shutdown message */
16513 status = cm_yield(0);
16514 if (status == RPC_SHUTDOWN)
16515 break;
16516
16517 gMutex.unlock();
16518 //status = ss_mutex_release(request_mutex);
16519
16520 //ss_sleep(10);
16521
16522 mongoose_poll(10);
16523 }
16524
16526#endif
16527
16528 if (gMh) {
16529 delete gMh;
16530 gMh = NULL;
16531 gMhkey = 0;
16532 }
16533
16534 mjsonrpc_exit();
16536 return 0;
16537}
16538
16539/* emacs
16540 * Local Variables:
16541 * tab-width: 8
16542 * c-basic-offset: 3
16543 * indent-tabs-mode: nil
16544 * End:
16545 */
#define FALSE
Definition cfortran.h:309
char * attachment_buffer[3]
Definition mhttpd.cxx:67
size_t attachment_size[3]
Definition mhttpd.cxx:68
~Attachment()
Definition mhttpd.cxx:77
void clear(int i)
Definition mhttpd.cxx:83
std::vector< AuthEntry > passwords
Definition mhttpd.cxx:13726
std::string passwd_filename
Definition mhttpd.cxx:13725
std::string realm
Definition mhttpd.cxx:13724
int Init()
Definition mhttpd.cxx:13733
virtual int hs_read(time_t start_time, time_t end_time, time_t interval, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], time_t *time_buffer[], double *data_buffer[], int status[])=0
see hs_read(), returns HS_SUCCESS
virtual int hs_disconnect()=0
disconnect from history, returns HS_SUCCESS
virtual int hs_get_events(time_t time_from, std::vector< std::string > *pevents)=0
get list of events that exist(ed) at given time and later (value 0 means "return all events from begi...
virtual int hs_get_tags(const char *event_name, time_t time_from, std::vector< TAG > *ptags)=0
get list of history variables for given event (use event names returned by hs_get_events()) that exis...
virtual int hs_get_last_written(time_t start_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], time_t last_written[])=0
virtual int hs_clear_cache()=0
clear internal cache, returns HS_SUCCESS
void initparam()
Definition mhttpd.cxx:717
void unsetparam(const char *param)
Definition mhttpd.cxx:817
const char * getparam(const char *param)
Definition mhttpd.cxx:774
char _param[MAX_PARAM][PARAM_LENGTH]
Definition mhttpd.cxx:702
void setparam(const char *param, const char *value)
Definition mhttpd.cxx:724
~Param()
Definition mhttpd.cxx:712
char * _value[MAX_PARAM]
Definition mhttpd.cxx:703
BOOL isparam(const char *param)
Definition mhttpd.cxx:803
void printparam()
Definition mhttpd.cxx:765
std::string xgetparam(const char *param)
Definition mhttpd.cxx:794
Param()
Definition mhttpd.cxx:707
void freeparam()
Definition mhttpd.cxx:754
char _text[TEXT_SIZE]
Definition mhttpd.cxx:704
MUTEX_T * fMutex
Definition mhttpd.cxx:438
void AddTrace(RequestTrace *t)
Definition mhttpd.cxx:456
void AddTraceMTS(RequestTrace *t)
Definition mhttpd.cxx:461
std::vector< RequestTrace * > fBuf
Definition mhttpd.cxx:439
std::string fQuery
Definition mhttpd.cxx:394
std::string fMethod
Definition mhttpd.cxx:392
void PrintTrace0() const
Definition mhttpd.cxx:411
std::string fUri
Definition mhttpd.cxx:393
double fTimeSent
Definition mhttpd.cxx:390
std::string fResource
Definition mhttpd.cxx:396
bool fCompleted
Definition mhttpd.cxx:391
double fTimeReceived
Definition mhttpd.cxx:386
std::string fRPC
Definition mhttpd.cxx:395
double fTimeUnlocked
Definition mhttpd.cxx:388
double fTimeLocked
Definition mhttpd.cxx:387
double fTimeProcessed
Definition mhttpd.cxx:389
Return()
Definition mhttpd.cxx:522
va_end(argptr)
~Return()
Definition mhttpd.cxx:532
else strcpy(return_buffer+strlen_retbuf, str)
int return_grow(size_t len)
Definition mhttpd.cxx:554
return_grow(strlen(str))
vsprintf(str,(char *) format, argptr)
void rread(const char *filename, int fh, int len)
Definition mhttpd.cxx:586
int strlen_retbuf
Definition mhttpd.cxx:518
size_t return_size
Definition mhttpd.cxx:515
void zero()
Definition mhttpd.cxx:547
void char str[10000]
Definition mhttpd.cxx:670
void rsprintf(const char *format,...) MATTRPRINTF(2
void rmemcpy(const void *buf, int len)
Definition mhttpd.cxx:576
va_start(argptr, format)
int return_length
Definition mhttpd.cxx:519
void rsputs2(const char *str)
Definition mhttpd.cxx:619
void rsputs(const char *str)
Definition mhttpd.cxx:600
void reset()
Definition mhttpd.cxx:542
char * return_buffer
Definition mhttpd.cxx:516
assert(strlen(str)< sizeof(str))
static bool exists(const std::string &name)
Definition odbxx.cxx:66
static void usage()
int done
TRIGGER_SETTINGS ts
INT al_get_alarms(std::string *presult)
Definition alarm.cxx:844
INT cm_yield(INT millisec)
Definition midas.cxx:5642
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
INT cm_connect_client(const char *client_name, HNDLE *hConn)
Definition midas.cxx:2766
INT cm_start_watchdog_thread()
Definition midas.cxx:7355
INT cm_connect_experiment1(const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
Definition midas.cxx:2297
std::string cm_expand_env(const char *str)
Definition midas.cxx:7710
int cm_exec_script(const char *odb_path_to_script)
Definition midas.cxx:5461
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
std::string cm_get_exptab_filename()
Definition midas.cxx:1788
std::string cm_get_path()
Definition midas.cxx:1537
std::string cm_get_history_path(const char *history_channel)
Definition midas.cxx:5843
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
const char * cm_get_version()
Definition midas.cxx:1476
std::string cm_get_experiment_name()
Definition midas.cxx:1580
const char * cm_get_revision()
Definition midas.cxx:1484
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7520
INT el_submit(int run, const char *author, const char *type, const char *syst, const char *subject, const char *text, const char *reply_to, const char *encoding, const char *afilename1, const char *buffer1, INT buffer_size1, const char *afilename2, const char *buffer2, INT buffer_size2, const char *afilename3, const char *buffer3, INT buffer_size3, char *tag, INT tag_size)
Definition elog.cxx:124
#define CM_SUCCESS
Definition midas.h:582
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_STRUCT_MISMATCH
Definition midas.h:654
#define DB_OUT_OF_RANGE
Definition midas.h:651
#define DB_INVALID_HANDLE
Definition midas.h:635
#define DB_NO_ACCESS
Definition midas.h:648
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_KEY
Definition midas.h:642
#define DB_NO_MORE_SUBKEYS
Definition midas.h:646
#define SS_SUCCESS
Definition midas.h:663
#define SS_FILE_ERROR
Definition midas.h:669
#define SS_CREATED
Definition midas.h:664
#define SS_SOCKET_ERROR
Definition midas.h:673
#define RPC_SHUTDOWN
Definition midas.h:707
#define RPC_SUCCESS
Definition midas.h:698
#define RPC_NET_ERROR
Definition midas.h:701
#define HS_UNDEFINED_VAR
Definition midas.h:733
#define HS_SUCCESS
Definition midas.h:727
#define HS_FILE_ERROR
Definition midas.h:728
#define EL_SUCCESS
Definition midas.h:745
unsigned short int WORD
Definition mcstd.h:49
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define TID_DOUBLE
Definition midas.h:343
#define TID_KEY
Definition midas.h:349
#define TID_BOOL
Definition midas.h:340
#define MODE_EXCLUSIVE
Definition midas.h:373
#define MT_INFO
Definition midas.h:543
#define TID_WORD
Definition midas.h:332
#define STATE_STOPPED
Definition midas.h:305
#define MINFO
Definition midas.h:560
#define MODE_DELETE
Definition midas.h:372
#define TID_LINK
Definition midas.h:350
#define TID_STRING
Definition midas.h:346
#define MODE_WRITE
Definition midas.h:371
#define MERROR
Definition midas.h:559
#define STATE_RUNNING
Definition midas.h:307
#define MODE_READ
Definition midas.h:370
#define TID_INT
Definition midas.h:338
#define TID_FLOAT
Definition midas.h:341
void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
Definition mgd.cxx:2471
void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
Definition mgd.cxx:2299
gdImagePtr gdImageCreate(int sx, int sy)
Definition mgd.cxx:417
void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, const char *s, int color)
Definition mgd.cxx:877
void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
Definition mgd.cxx:2307
void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
Definition mgd.cxx:638
gdImagePtr gdImageCreateFromGif(FILE *fd)
Definition mgd.cxx:1888
int w
Definition mgd.h:64
void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, const char *s, int color)
Definition mgd.cxx:888
void gdImageDestroy(gdImagePtr im)
Definition mgd.cxx:439
gdFontPtr gdFontMediumBold
Definition mgd.cxx:408
int h
Definition mgd.h:65
gdFontPtr gdFontGiant
Definition mgd.cxx:409
int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
Definition mgd.cxx:455
void gdImageGif(gdImagePtr im, gdGifBuffer *buffer)
Definition mgd.cxx:1118
void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
Definition mgd.cxx:738
int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
Definition mgd.cxx:492
void gdImageInterlace(gdImagePtr im, int interlaceArg)
Definition mgd.cxx:2619
gdFontPtr gdFontSmall
Definition mgd.cxx:410
void gdImageFill(gdImagePtr im, int x, int y, int color)
Definition mgd.cxx:964
void gdImageColorTransparent(gdImagePtr im, int color)
Definition mgd.cxx:533
void mjsonrpc_init()
MJsonNode * mjsonrpc_decode_post_data(const char *post_data)
MJsonNode * mjsonrpc_make_result(MJsonNode *node)
Definition mjsonrpc.cxx:135
void mjsonrpc_exit()
static MJSO * I()
Definition mjsonrpc.cxx:298
MJsonNode * mjsonrpc_get_schema()
void mjsonrpc_set_std_mutex(void *mutex)
std::string mjsonrpc_schema_to_text(const MJsonNode *schema)
void mjsonrpc_add_handler(const char *method, mjsonrpc_handler_t *handler, bool needs_locking)
#define MAX(a, b)
Definition midas.h:509
int mg_printf(struct mg_connection *, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
time_t mg_mgr_poll(struct mg_mgr *, int milli)
void mg_mgr_free(struct mg_mgr *)
char * cs_md5(char buf[33],...)
void * user_data
Definition mongoose6.h:1265
struct mg_str header_names[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2090
#define MG_MAX_HTTP_HEADERS
Definition mongoose6.h:2031
#define MG_F_CLOSE_IMMEDIATELY
Definition mongoose6.h:1289
void mbuf_remove(struct mbuf *, size_t data_size)
void mg_mgr_init(struct mg_mgr *mgr, void *user_data)
void mg_send_head(struct mg_connection *n, int status_code, int64_t content_length, const char *extra_headers)
struct mg_str uri
Definition mongoose6.h:2072
#define MG_EV_RECV
Definition mongoose6.h:1222
const char * mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert)
void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t)
struct mg_str header_values[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2091
union socket_address sa
Definition mongoose6.h:1253
struct mg_str method
Definition mongoose6.h:2071
size_t len
Definition mongoose6.h:1207
#define MG_F_LISTENING
Definition mongoose6.h:1278
void mg_send(struct mg_connection *, const void *buf, int len)
struct mg_connection * next
Definition mongoose6.h:1247
struct mbuf recv_mbuf
Definition mongoose6.h:1255
#define MG_EV_POLL
Definition mongoose6.h:1219
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler)
struct mg_str query_string
Definition mongoose6.h:2087
#define MG_EV_HTTP_CHUNK
Definition mongoose6.h:2116
struct sockaddr sin6
Definition mongoose6.h:1200
mg_event_handler_t f
Definition mongoose6.h:1272
void mg_set_protocol_http_websocket(struct mg_connection *nc)
#define MG_EV_SEND
Definition mongoose6.h:1223
unsigned long flags
Definition mongoose6.h:1276
struct mg_connection * listener
Definition mongoose6.h:1248
struct mg_str proto
Definition mongoose6.h:2073
struct mg_str body
Definition mongoose6.h:2094
struct sockaddr sa
Definition mongoose6.h:1195
struct mg_connection * mg_bind(struct mg_mgr *, const char *, mg_event_handler_t)
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size)
struct mg_str mg_mk_str(const char *s)
#define MG_EV_CLOSE
Definition mongoose6.h:1224
void mg_enable_multithreading(struct mg_connection *nc)
struct mg_str * mg_get_http_header(struct http_message *hm, const char *name)
const char * p
Definition mongoose6.h:1206
#define MG_EV_ACCEPT
Definition mongoose6.h:1220
struct mg_connection * mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t)
struct sockaddr_in sin
Definition mongoose6.h:1196
#define MG_F_SEND_AND_CLOSE
Definition mongoose6.h:1288
#define MG_EV_HTTP_REQUEST
Definition mongoose6.h:2114
#define O_BINARY
Definition msystem.h:219
std::string ss_gethostname()
Definition system.cxx:5706
INT ss_mutex_release(MUTEX_T *mutex)
Definition system.cxx:3157
int ss_isnan(double x)
Definition system.cxx:7961
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3365
DWORD ss_millitime()
Definition system.cxx:3393
int ss_file_exist(const char *path)
Definition system.cxx:7118
int ss_isfin(double x)
Definition system.cxx:7966
std::string ss_getcwd()
Definition system.cxx:5770
INT ss_getpid(void)
Definition system.cxx:1377
INT ss_mutex_create(MUTEX_T **mutex, BOOL recursive)
Definition system.cxx:2941
void ss_tzset()
Definition system.cxx:3355
INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
Definition system.cxx:5393
std::string ss_replace_env_variables(const std::string &inputPath)
Definition system.cxx:2212
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2001
DWORD ss_time()
Definition system.cxx:3462
INT ss_sleep(INT millisec)
Definition system.cxx:3628
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7891
void * ss_ctrlc_handler(void(*func)(int))
Definition system.cxx:3899
INT ss_timezone()
Definition system.cxx:3580
INT ss_mutex_wait_for(MUTEX_T *mutex, INT timeout)
Definition system.cxx:3037
INT cm_msg1(INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format,...)
Definition midas.cxx:973
INT EXPRT cm_msg_facilities(STRING_LIST *list)
Definition midas.cxx:504
std::string cm_get_error(INT code)
Definition midas.cxx:455
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:915
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition midas.cxx:1264
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition midas.cxx:539
#define TELL(fh)
Definition msystem.h:243
#define WORD_SWAP(x)
Definition msystem.h:65
#define DWORD_SWAP(x)
Definition msystem.h:74
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_sprintfh(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10983
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6893
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3856
INT db_find_link(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4274
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5415
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6361
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_set_link_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7425
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4990
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11805
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8217
INT db_set_link_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7754
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12972
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9037
INT db_scan_tree(HNDLE hDB, HNDLE hKey, INT level, INT(*callback)(HNDLE, HNDLE, KEY *, INT, void *), void *info)
Definition odb.cxx:4767
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6019
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6072
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:13934
INT db_sprintff(char *string, const char *format, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10919
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7648
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13813
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7215
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5725
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10843
INT db_copy_json_obsolete(HNDLE hDB, HNDLE hKey, char **buffer, int *buffer_size, int *buffer_end, int save_keys, int follow_links, int recurse)
Definition odb.cxx:10508
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5261
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_get_link_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6656
INT db_rename_key(HNDLE hDB, HNDLE hKey, const char *name)
Definition odb.cxx:6261
INT db_get_key_time(HNDLE hDB, HNDLE hKey, DWORD *delta)
Definition odb.cxx:6132
INT db_set_value_index(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT idx, DWORD type, BOOL trunc)
Definition odb.cxx:5365
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT EXPRT db_resize_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int num_values, int max_string_length)
Definition odb.cxx:14025
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12800
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition odb.cxx:11314
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7502
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3601
#define RPC_CNAF16
Definition mrpc.h:125
INT rpc_client_call(HNDLE hConn, DWORD routine_id,...)
Definition midas.cxx:13472
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11827
#define RPC_JRPC
Definition mrpc.h:130
static std::vector< RPC_LIST > rpc_list
Definition midas.cxx:11573
const char * rpc_tid_name(INT id)
Definition midas.cxx:11764
#define RPC_CNAF24
Definition mrpc.h:126
#define RPC_MANUAL_TRIG
Definition mrpc.h:128
INT rpc_tid_size(INT id)
Definition midas.cxx:11757
static std::string q(const char *s)
#define HS_GET_INACTIVE
Definition history.h:37
#define HS_GET_READER
Definition history.h:35
int hs_read_event_list(std::vector< std::string > *pevents)
int hs_find_reader_channel(HNDLE hDB, HNDLE *hKeyOut, int debug_flag)
int hs_get_history(HNDLE hDB, HNDLE hKey, int flags, int debug_flag, MidasHistoryInterface **mh)
int main()
Definition hwtest.cxx:23
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
INT run_number[2]
Definition mana.cxx:246
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
char param[10][256]
Definition mana.cxx:250
void * data
Definition mana.cxx:268
BOOL debug
debug printouts
Definition mana.cxx:254
BOOL daemon
Definition mana.cxx:258
INT type
Definition mana.cxx:269
HNDLE hDB
main ODB handle
Definition mana.cxx:207
char addr[128]
Definition mcnaf.cxx:104
double count
Definition mdump.cxx:33
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
char response[10000]
Definition melog.cxx:90
#define closesocket(s)
Definition melog.cxx:29
static int offset
Definition mgd.cxx:1500
static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
Definition mhttpd.cxx:14172
static bool trace_mg
Definition mhttpd.cxx:13705
static void SaveHistPlotToOdb(MVOdb *odb, const HistPlot &hp, const char *group, const char *panel)
Definition mhttpd.cxx:10405
static bool trace_mg_send
Definition mhttpd.cxx:13707
#define LOG2
Definition mhttpd.cxx:7629
BOOL is_editable(char *eq_name, char *var_name)
Definition mhttpd.cxx:2531
#define LN10
Definition mhttpd.cxx:7628
const unsigned char favicon_png[]
Definition mhttpd.cxx:215
#define WEB_BUFFER_SIZE
Definition mhttpd.cxx:509
void haxis(gdImagePtr im, gdFont *font, int col, int gcol, int x1, int y1, int width, int minor, int major, int text, int label, int grid, double xmin, double xmax)
Definition mhttpd.cxx:7632
static bool cmp_vars(const HistVar &a, const HistVar &b)
Definition mhttpd.cxx:10101
void output_key(Param *p, Return *r, HNDLE hkey, int index, const char *format)
Definition mhttpd.cxx:4368
static MVOdb * gOdb
Definition mhttpd.cxx:46
void get_elog_url(char *url, int len)
static void DeleteHistPlotDeleted(HistPlot &hp)
Definition mhttpd.cxx:10481
static BOOL history_mode
Definition mhttpd.cxx:93
static void LoadHistPlotFromParam(HistPlot *hp, Param *p)
Definition mhttpd.cxx:10300
static void add_rpc_functions()
Definition mhttpd.cxx:16202
#define RESPONSE_501
Definition mhttpd.cxx:14255
INT check_odb_records(MVOdb *odb)
Definition mhttpd.cxx:13389
static int handle_http_post(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14880
std::string get_content_type(const char *filename)
Definition mhttpd.cxx:1133
static const std::string find_header_mg(const struct http_message *msg, const char *name)
Definition mhttpd.cxx:14141
static std::mutex gMutex
Definition mhttpd.cxx:45
static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri, size_t uri_len, const char *ha1, size_t ha1_len, const char *nonce, size_t nonce_len, const char *nc, size_t nc_len, const char *cnonce, size_t cnonce_len, const char *qop, size_t qop_len, char *resp)
Definition mhttpd.cxx:13754
#define HTTP_ENCODING
Definition mhttpd.cxx:211
void strencode(Return *r, const char *text)
Definition mhttpd.cxx:2019
static MVOdb * gMimeTypesOdb
Definition mhttpd.cxx:177
void init_elog_odb()
Definition mhttpd.cxx:1978
static const char default_type_list[20][NAME_LENGTH]
Definition mhttpd.cxx:99
void show_eqtable_page(Param *pp, Return *r, int refresh)
Definition mhttpd.cxx:2558
static void history_watch_callback(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition mhttpd.cxx:8145
void show_custom_file(Return *r, const char *name)
Definition mhttpd.cxx:3609
void show_find_page(Return *r, const char *value)
Definition mhttpd.cxx:7567
#define MAX_GROUPS
Definition mhttpd.cxx:50
BOOL check_web_password(Return *r, HNDLE hDB, const char *dec_path, const char *password, const char *redir)
Definition mhttpd.cxx:6736
bool send_fp(Return *r, const std::string &path, FILE *fp)
Definition mhttpd.cxx:1164
std::vector< std::string > get_resource_paths()
Definition mhttpd.cxx:989
static void SplitEventAndTagNames(std::string var_name, std::string &event_name, std::string &tag_name)
Definition mhttpd.cxx:10151
void decode_cookies(Cookies *c, const http_message *msg)
Definition mhttpd.cxx:14206
char * stristr(const char *str, const char *pattern)
Definition mhttpd.cxx:339
void submit_elog(MVOdb *odb, Param *pp, Return *r, Attachment *a)
Definition mhttpd.cxx:2248
void show_query_page(Param *p, Return *r)
Definition mhttpd.cxx:9791
static void urlEncode(char *ps, int ps_size)
Definition mhttpd.cxx:919
static std::string NextHistPlotColour(const HistPlot &hp)
Definition mhttpd.cxx:10116
std::string strencode2(const char *text)
Definition mhttpd.cxx:2047
void decode_get(Return *rr, char *string, const Cookies *c, const char *url, const char *query_string, RequestTrace *t)
Definition mhttpd.cxx:13195
static MJsonNode * get_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16175
void show_error(Return *r, const char *error)
Definition mhttpd.cxx:1839
static HNDLE gMhkey
Definition mhttpd.cxx:8153
static bool read_passwords(Auth *auth)
Definition mhttpd.cxx:13796
void redirect2(Return *r, const char *path)
Definition mhttpd.cxx:1444
static void show_cnaf_page(Param *p, Return *rr)
Definition mhttpd.cxx:5653
static void SaveMimetypes(MVOdb *odb)
Definition mhttpd.cxx:201
#define MAX_PARAM
Definition mhttpd.cxx:695
#define DEFAULT_REFRESH
Definition mhttpd.cxx:39
void show_navigation_bar(Return *r, const char *cur_page)
Definition mhttpd.cxx:1867
#define LOG5
Definition mhttpd.cxx:7630
void ctrlc_handler(int sig)
Definition mhttpd.cxx:13453
static void PrintHistPlot(const HistPlot &hp)
Definition mhttpd.cxx:10106
void javascript_commands(Param *p, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:4443
#define MAX_VARS
Definition mhttpd.cxx:51
static int handle_decode_post(struct mg_connection *nc, const http_message *msg, const char *uri, const char *query_string, RequestTrace *t)
Definition mhttpd.cxx:14724
std::string time_to_string(time_t t)
Definition mhttpd.cxx:8133
static std::string mgstr(const mg_str *s)
Definition mhttpd.cxx:14136
int vaxis(gdImagePtr im, gdFont *font, int col, int gcol, int x1, int y1, int width, int minor, int major, int text, int label, int grid, double ymin, double ymax, BOOL logaxis)
Definition mhttpd.cxx:7906
static bool mongoose_passwords_enabled(const struct mg_connection *nc)
static bool verbose_mg
Definition mhttpd.cxx:13704
static int cmp_names(const void *a, const void *b)
Definition mhttpd.cxx:9975
INT sendmail(const char *from_host, const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
Definition mhttpd.cxx:1253
int find_file_mg(const char *filename, std::string &path, FILE **fpp, bool trace)
Definition mhttpd.cxx:13672
void decode_query(Param *pp, const char *query_string)
Definition mhttpd.cxx:13171
static bool gDoReloadHistory
Definition mhttpd.cxx:8143
static std::string check_digest_auth(struct http_message *hm, Auth *auth)
Definition mhttpd.cxx:13892
static MidasHistoryInterface * gMh
Definition mhttpd.cxx:8152
static bool gDoSetupHistoryWatch
Definition mhttpd.cxx:8142
int get_hist_last_written(MVOdb *odb, const char *group, const char *panel, time_t endtime, int index, int want_all, time_t *plastwritten)
Definition mhttpd.cxx:8521
void taxis(gdImagePtr im, gdFont *font, int col, int gcol, int x1, int y1, int width, int xr, int minor, int major, int text, int label, int grid, double xmin, double xmax)
Definition mhttpd.cxx:7785
void show_password_page(Return *r, const char *dec_path, const char *password)
Definition mhttpd.cxx:6702
time_t string_to_time(const char *str)
Definition mhttpd.cxx:8117
void show_header(Return *r, const char *title, const char *method, const char *path, int refresh)
Definition mhttpd.cxx:1779
bool send_resource(Return *r, const std::string &name, bool generate_404=true)
Definition mhttpd.cxx:1229
void strencode3(Return *r, const char *text)
Definition mhttpd.cxx:2078
static std::vector< std::string > gAllowedHosts
Definition mhttpd.cxx:13463
bool send_file(Return *r, const std::string &path, bool generate_404=true)
Definition mhttpd.cxx:1210
static int xmg_check_nonce(const char *nonce)
Definition mhttpd.cxx:13775
void show_text_header(Return *r)
Definition mhttpd.cxx:1827
char * find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
Definition mhttpd.cxx:3091
static std::string UrlDecode(const char *p)
Definition mhttpd.cxx:841
void strencode4(Return *r, const char *text)
Definition mhttpd.cxx:2103
void show_elog_attachment(Param *p, Return *r, const char *path)
Definition mhttpd.cxx:2483
void Unlock(RequestTrace *t)
Definition mhttpd.cxx:12246
int evaluate_src(char *key, char *src, double *fvalue)
Definition mhttpd.cxx:3497
void redirect(Return *r, const char *path)
Definition mhttpd.cxx:1407
static void urlDecode(char *p)
Definition mhttpd.cxx:880
static std::string add_param_to_url(const char *name, const char *value)
Definition mhttpd.cxx:9780
#define READ_HISTORY_DATA
Definition mhttpd.cxx:8320
bool starts_with(const std::string &s1, const char *s2)
Definition mhttpd.cxx:4427
static const char * cgif_bar_str[]
Definition mhttpd.cxx:3468
#define PARAM_LENGTH
Definition mhttpd.cxx:696
#define RESPONSE_QUEUED
Definition mhttpd.cxx:14254
static MidasHistoryInterface * get_history(bool reset=false)
Definition mhttpd.cxx:8157
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)
Definition mhttpd.cxx:3275
static int handle_http_get(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14797
#define READ_HISTORY_RUNMARKER
Definition mhttpd.cxx:8321
std::string add_custom_path(const std::string &filename)
Definition mhttpd.cxx:3570
void sec_to_label(char *result, int sec, int base, int force_date)
Definition mhttpd.cxx:7750
void show_odb_page(Param *pp, Return *r, const char *dec_path, int write_access)
Definition mhttpd.cxx:6793
void send_icon(Return *r, const char *icon)
Definition mhttpd.cxx:12188
static BOOL elog_mode
Definition mhttpd.cxx:92
void Lock(RequestTrace *t)
Definition mhttpd.cxx:12240
void show_set_page(Param *pp, Return *r, const char *group, int index, const char *value)
Definition mhttpd.cxx:7433
void decode_post(Return *rr, const char *header, const char *string, const char *boundary, int length, const Cookies *c, const char *url, RequestTrace *t)
Definition mhttpd.cxx:13233
#define DELETE(x)
Definition mhttpd.cxx:8235
void show_hist_config_page(MVOdb *odb, Param *p, Return *r, const char *hgroup, const char *hpanel)
Definition mhttpd.cxx:10519
static const std::string find_cookie_mg(const struct http_message *msg, const char *cookie_name)
Definition mhttpd.cxx:14154
void do_jrpc(Param *p, Return *r)
Definition mhttpd.cxx:4318
const unsigned char favicon_ico[]
Definition mhttpd.cxx:280
void init_mhttpd_odb(MVOdb *odb)
Definition mhttpd.cxx:1930
void check_obsolete_odb(HNDLE hDB, const char *odb_path)
Definition mhttpd.cxx:1881
void do_jrpc_rev1(Param *p, Return *r)
Definition mhttpd.cxx:4139
static RequestTraceBuf * gTraceBuf
Definition mhttpd.cxx:504
const char * mhttpd_revision(void)
Definition mhttpd.cxx:834
void show_hist_page(MVOdb *odb, Param *p, Return *r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
Definition mhttpd.cxx:11262
static int handle_decode_get(struct mg_connection *nc, const http_message *msg, const char *uri, const char *query_string, RequestTrace *t)
Definition mhttpd.cxx:14257
void gen_odb_attachment(Return *r, const char *path, std::string &bout)
Definition mhttpd.cxx:2134
#define RESPONSE_SENT
Definition mhttpd.cxx:14253
bool open_resource_file(const char *filename, std::string *ppath, FILE **pfp)
Definition mhttpd.cxx:1029
void redirect_307(Return *r, const char *path)
Definition mhttpd.cxx:1431
static std::string GetMimetype(const std::string &ext)
Definition mhttpd.cxx:179
static double GetTimeSec()
Definition mhttpd.cxx:374
void show_custom_page(Param *pp, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:5419
static MJsonNode * set_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16188
const bool cmp_tags(const TAG &a, const TAG &b)
Definition mhttpd.cxx:10043
const bool cmp_events1(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10038
#define READ_HISTORY_LAST_WRITTEN
Definition mhttpd.cxx:8322
int read_history(const HistPlot &hp, int index, int flags, time_t tstart, time_t tend, time_t scale, HistoryData *data)
Definition mhttpd.cxx:8356
static std::string toString(int i)
Definition mhttpd.cxx:55
const MimetypeTableEntry gMimetypeTable[]
Definition mhttpd.cxx:128
int time_to_sec(const char *str)
Definition mhttpd.cxx:8092
static BOOL verbose
Definition mhttpd.cxx:94
void show_help_page(Return *r, const char *dec_path)
Definition mhttpd.cxx:1540
void do_jrpc_rev0(Param *p, Return *r)
Definition mhttpd.cxx:4014
INT search_callback(HNDLE hDB, HNDLE hKey, KEY *key, INT level, void *info)
Definition mhttpd.cxx:1457
void init_menu_buttons(MVOdb *odb)
Definition mhttpd.cxx:1890
std::atomic_bool _abort
Definition mhttpd.cxx:13451
void generate_hist_graph(MVOdb *odb, Return *rr, const char *hgroup, const char *hpanel, char *buffer, int *buffer_size, int width, int height, time_t xendtime, int scale, int index, int labels, const char *bgcolor, const char *fgcolor, const char *gridcolor)
Definition mhttpd.cxx:8604
#define ALLOC(t, n)
Definition mhttpd.cxx:8234
static const char * cgif_label_str[]
Definition mhttpd.cxx:3428
time_t mktime_with_dst(const struct tm *ptms)
Definition mhttpd.cxx:9745
const char * mname[]
Definition midas.cxx:144
int try_file_mg(const char *try_dir, const char *filename, std::string &path, FILE **fpp, bool trace)
Definition mhttpd.cxx:13639
void export_hist(MVOdb *odb, Return *r, const char *group, const char *panel, time_t endtime, int scale, int index, int labels)
Definition mhttpd.cxx:11025
#define STRDUP(x)
Definition mhttpd.cxx:8237
static int http_trace
Definition mhttpd.cxx:433
static void xmg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
Definition mhttpd.cxx:13786
void interprete(Param *p, Return *r, Attachment *a, const Cookies *c, const char *dec_path, RequestTrace *t)
Definition mhttpd.cxx:12254
static const char default_system_list[20][NAME_LENGTH]
Definition mhttpd.cxx:114
static void handle_http_options_cors(struct mg_connection *nc, const http_message *msg, RequestTrace *t)
Definition mhttpd.cxx:15001
#define DELETEA(x, n)
Definition mhttpd.cxx:8236
static Auth * gAuthMg
Definition mhttpd.cxx:13752
static void SortHistPlotVars(HistPlot &hp)
Definition mhttpd.cxx:10498
const bool cmp_events(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10033
int xdb_get_data_index(HNDLE hDB, const char *str, void *value, int size, int index, int tid)
Definition mhttpd.cxx:10062
void show_error_404(Return *r, const char *error)
Definition mhttpd.cxx:1854
static void handle_http_message(struct mg_connection *nc, http_message *msg)
Definition mhttpd.cxx:15071
static int xdb_find_key(HNDLE hDB, HNDLE dir, const char *str, HNDLE *hKey, int tid, int size)
Definition mhttpd.cxx:10078
static void AddHistPlotSelectedParam(HistPlot &hp, Param *p)
Definition mhttpd.cxx:10377
void show_custom_gif(Return *rr, const char *name)
Definition mhttpd.cxx:3672
static void LoadHistPlotFromOdb(MVOdb *odb, HistPlot *hp, const char *group, const char *panel)
Definition mhttpd.cxx:10195
static bool trace_mg_recv
Definition mhttpd.cxx:13706
static int NextHistPlotOrder(const HistPlot &hp)
Definition mhttpd.cxx:10142
#define TEXT_SIZE
Definition mhttpd.cxx:697
bool ends_with_char(const std::string &s, char c)
Definition midas.cxx:403
std::string msprintf(const char *format,...)
Definition midas.cxx:410
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define M_MALLOC(x)
Definition midas.h:1552
#define RPC_OUT
Definition midas.h:1581
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
#define RPC_IN
Definition midas.h:1580
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define RPC_MAX_ID
Definition midas.h:1607
int INT
Definition midas.h:129
#define MATTRPRINTF(a, b)
Definition midas.h:221
#define CNAF_INHIBIT_SET
Definition midas.h:494
#define MAX_ODB_PATH
Definition midas.h:277
#define CNAF_CRATE_ZINIT
Definition midas.h:497
#define M_FREE(x)
Definition midas.h:1554
#define TRUE
Definition midas.h:182
#define CNAF
Definition midas.h:491
#define CNAF_CRATE_CLEAR
Definition midas.h:496
#define DEFAULT_ODB_SIZE
Definition midas.h:270
#define EQUIPMENT_COMMON_STR
Definition midas.h:1112
#define POINTER_T
Definition midas.h:166
std::vector< std::string > STRING_LIST
Definition midas.h:246
INT MUTEX_T
Definition midas.h:237
#define RUNINFO_STR(_name)
Definition midas.h:1410
#define NAME_LENGTH
Definition midas.h:272
#define CNAF_INHIBIT_CLEAR
Definition midas.h:495
MidasHistoryInterface * mh
#define end
#define read(n, a, f)
#define event_id
#define write(n, a, f, d)
#define name(x)
Definition midas_macro.h:24
static FILE * fp
#define SOMAXCONN
int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf, size_t buf_size)
int gettimeofday(struct timeval *tp, void *tzp)
timeval tv
Definition msysmon.cxx:1095
MUTEX_T * tm
Definition odbedit.cxx:39
char pwd[256]
Definition odbedit.cxx:24
double total[100]
Definition odbhist.cxx:42
INT j
Definition odbhist.cxx:40
double value[100]
Definition odbhist.cxx:42
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
char file_name[256]
Definition odbhist.cxx:41
DWORD status
Definition odbhist.cxx:39
char var_name[256]
Definition odbhist.cxx:41
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
Definition mhttpd.cxx:13716
std::string password
Definition mhttpd.cxx:13719
std::string username
Definition mhttpd.cxx:13717
std::string realm
Definition mhttpd.cxx:13718
double max
Definition mhttpd.cxx:3489
BOOL logscale
Definition mhttpd.cxx:3488
char format[32]
Definition mhttpd.cxx:3442
char src[256]
Definition mhttpd.cxx:3441
char bgcolor[8]
Definition mhttpd.cxx:3446
char font[32]
Definition mhttpd.cxx:3443
char fgcolor[8]
Definition mhttpd.cxx:3445
std::string cookie_pwd
Definition mhttpd.cxx:12231
int refresh
Definition mhttpd.cxx:12234
std::string cookie_wpwd
Definition mhttpd.cxx:12232
std::string cookie_cpwd
Definition mhttpd.cxx:12233
std::string timescale
Definition mhttpd.cxx:8340
bool enable_factor
Definition mhttpd.cxx:8349
bool show_fill
Definition mhttpd.cxx:8347
double minimum
Definition mhttpd.cxx:8341
double maximum
Definition mhttpd.cxx:8342
bool show_factor
Definition mhttpd.cxx:8348
bool zero_ylow
Definition mhttpd.cxx:8343
bool show_values
Definition mhttpd.cxx:8346
bool log_axis
Definition mhttpd.cxx:8344
std::vector< HistVar > vars
Definition mhttpd.cxx:8351
bool show_run_markers
Definition mhttpd.cxx:8345
double factor
Definition mhttpd.cxx:8333
std::string tag_name
Definition mhttpd.cxx:8327
double offset
Definition mhttpd.cxx:8334
int order
Definition mhttpd.cxx:8332
std::string formula
Definition mhttpd.cxx:8328
std::string label
Definition mhttpd.cxx:8330
double voffset
Definition mhttpd.cxx:8335
std::string colour
Definition mhttpd.cxx:8329
std::string event_name
Definition mhttpd.cxx:8326
bool show_raw_value
Definition mhttpd.cxx:8331
int * odb_index
Definition mhttpd.cxx:8246
time_t tstart
Definition mhttpd.cxx:8255
void Free()
Definition mhttpd.cxx:8277
int alloc_nvars
Definition mhttpd.cxx:8242
void Allocate(int xnvars)
Definition mhttpd.cxx:8259
time_t tend
Definition mhttpd.cxx:8256
double ** v
Definition mhttpd.cxx:8250
void Print() const
Definition mhttpd.cxx:8292
time_t ** t
Definition mhttpd.cxx:8249
char ** var_names
Definition mhttpd.cxx:8244
int * var_index
Definition mhttpd.cxx:8245
char ** event_names
Definition mhttpd.cxx:8243
int * status
Definition mhttpd.cxx:8247
bool have_last_written
Definition mhttpd.cxx:8252
time_t * last_written
Definition mhttpd.cxx:8253
int * num_entries
Definition mhttpd.cxx:8248
time_t scale
Definition mhttpd.cxx:8257
Definition midas.h:1026
INT num_values
Definition midas.h:1028
DWORD type
Definition midas.h:1027
INT total_size
Definition midas.h:1031
WORD access_mode
Definition midas.h:1033
INT last_written
Definition midas.h:1037
char name[NAME_LENGTH]
Definition midas.h:1029
INT item_size
Definition midas.h:1032
Definition mhttpd.cxx:123
std::string mimetype
Definition mhttpd.cxx:125
std::string ext
Definition mhttpd.cxx:124
Definition midas.h:1234
char name[NAME_LENGTH]
Definition midas.h:1235
Definition mgd.h:58
Definition mgd.h:120
Return * r
Definition mhttpd.cxx:1453
const char * search_name
Definition mhttpd.cxx:1454
double d
Definition system.cxx:1311
char c
Definition system.cxx:1310
static double e(void)
Definition tinyexpr.c:136
static te_expr * base(state *s)
Definition tinyexpr.c:357
static te_expr * list(state *s)
Definition tinyexpr.c:567