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
45#define OBSOLETE 1 // obsolete code scheduled for removal. K.O.
46
47static std::mutex gMutex;
48static MVOdb* gOdb = NULL;
49
50/*------------------------------------------------------------------*/
51
52#define MAX_GROUPS 32
53#define MAX_VARS 100
54
55/*------------------------------------------------------------------*/
56
57static std::string toString(int i)
58{
59 char buf[256];
60 sprintf(buf, "%d", i);
61 return buf;
62}
63
64/*------------------------------------------------------------------*/
65
67{
68public:
70 size_t attachment_size[3];
71public:
72 Attachment() // ctor
73 {
74 for (int i=0; i<3; i++) {
76 attachment_size[i] = 0;
77 }
78 }
79 ~Attachment() // dtor
80 {
81 for (int i=0; i<3; i++) {
82 clear(i);
83 }
84 }
85 void clear(int i)
86 {
87 if (attachment_size[i]) {
88 attachment_size[i] = 0;
89 free(attachment_buffer[i]);
91 }
92 }
93};
97
98// month name from midas.c
99extern const char *mname[];
100
101static const char default_type_list[20][NAME_LENGTH] = {
102 "Routine",
103 "Shift summary",
104 "Minor error",
105 "Severe error",
106 "Fix",
107 "Question",
108 "Info",
109 "Modification",
110 "Reply",
111 "Alarm",
112 "Test",
113 "Other"
114};
115
116static const char default_system_list[20][NAME_LENGTH] = {
117 "General",
118 "DAQ",
119 "Detector",
120 "Electronics",
121 "Target",
122 "Beamline"
123};
124
126 std::string ext;
127 std::string mimetype;
128};
129
131 { ".ASC", "text/plain" },
132 { ".CSS", "text/css" },
133 { ".CSV", "text/csv" },
134 { ".HTM", "text/html" },
135 { ".HTML", "text/html" },
136 { ".TXT", "text/plain" },
137
138 { ".BMP", "image/bmp" },
139 { ".GIF", "image/gif" },
140 { ".ICO", "image/x-icon" },
141 { ".JPEG", "image/jpeg" },
142 { ".JPG", "image/jpeg" },
143 { ".PNG", "image/png" },
144 { ".SVG", "image/svg+xml" },
145 { ".TIF", "image/tiff" },
146 { ".TIFF", "image/tiff" },
147
148 { ".MID", "audio/midi" },
149 { ".MP3", "audio/mpeg" },
150 { ".OGA", "audio/ogg" },
151 { ".OGG", "audio/ogg" },
152 { ".WAV", "audio/wav" },
153
154 { ".BIN", "application/octet-stream" },
155 { ".BZ", "application/x-bzip" },
156 { ".BZ2", "application/x-bzip2" },
157 { ".DOC", "application/msword" },
158 { ".EPS", "application/postscript" },
159 { ".GZ", "application/gzip" },
160 { ".JS", "application/javascript" },
161 { ".JSON", "application/json" },
162 { ".MJS", "application/javascript" },
163 { ".PDF", "application/pdf" },
164 { ".PHP", "application/x-httpd-php" },
165 { ".RTF", "application/rtf" },
166 { ".PS", "application/postscript" },
167 { ".ROOT", "application/octet-stream" },
168 { ".XLS", "application/x-msexcel" },
169 { ".XML", "application/xml" },
170 { ".ZIP", "application/zip" },
171
172 { ".ODP", "application/vnd.oasis.opendocument.presentation" },
173 { ".ODS", "application/vnd.oasis.opendocument.spreadsheet" },
174 { ".ODT", "application/vnd.oasis.opendocument.text" },
175
176 { "", "" }
177};
178
180
181static std::string GetMimetype(const std::string& ext)
182{
183 if (gMimeTypesOdb) {
184 std::string mimetype;
185 gMimeTypesOdb->RS(ext.c_str(), &mimetype);
186 if (mimetype.length() > 0) {
187 //printf("GetMimetype: %s -> %s from ODB\n", ext.c_str(), mimetype.c_str());
188 return mimetype;
189 }
190 }
191
192 for (int i=0; gMimetypeTable[i].ext[0]; i++) {
193 if (ext == gMimetypeTable[i].ext) {
194 //printf("GetMimetype: %s -> %s from built-in table\n", ext.c_str(), gMimetypeTable[i].mimetype.c_str());
195 return gMimetypeTable[i].mimetype;
196 }
197 }
198
199 //printf("GetMimetype: %s -> not found\n", ext.c_str());
200 return "";
201}
202
203static void SaveMimetypes(MVOdb* odb)
204{
205 gMimeTypesOdb = odb;
206
207 for (int i=0; gMimetypeTable[i].ext.length() > 0; i++) {
208 std::string tmp = gMimetypeTable[i].mimetype;
209 gMimeTypesOdb->RS(gMimetypeTable[i].ext.c_str(), &tmp, true);
210 }
211}
212
213#define HTTP_ENCODING "UTF-8"
214
215/*------------------------------------------------------------------*/
216
217const unsigned char favicon_png[] = {
218 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
219 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
220 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
221 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x91, 0x68,
222 0x36, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D,
223 0x45, 0x07, 0xD4, 0x0B, 0x1A, 0x08, 0x37, 0x07,
224 0x0D, 0x7F, 0x16, 0x5C, 0x00, 0x00, 0x00, 0x09,
225 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x2E, 0x23,
226 0x00, 0x00, 0x2E, 0x23, 0x01, 0x78, 0xA5, 0x3F,
227 0x76, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D,
228 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61,
229 0x05, 0x00, 0x00, 0x01, 0x7D, 0x49, 0x44, 0x41,
230 0x54, 0x78, 0xDA, 0x63, 0xFC, 0xFF, 0xFF, 0x3F,
231 0x03, 0x29, 0x80, 0x09, 0xAB, 0xE8, 0xD2, 0x65,
232 0x77, 0x36, 0x6F, 0x7E, 0x8A, 0x5D, 0xC7, 0x7F,
233 0x0C, 0x30, 0x67, 0xEE, 0x0D, 0x56, 0xCE, 0xCD,
234 0x5C, 0xBC, 0x3B, 0xB6, 0x6D, 0x7F, 0x81, 0x29,
235 0xCB, 0x88, 0xE6, 0x24, 0x20, 0x57, 0x50, 0x7C,
236 0xDD, 0xCF, 0x1F, 0x6C, 0x40, 0xCB, 0xB5, 0xB5,
237 0x05, 0xCF, 0x1C, 0xB7, 0x42, 0xB3, 0x80, 0x05,
238 0x8D, 0xCF, 0xC8, 0xC8, 0x58, 0x5A, 0x2A, 0xFB,
239 0xF6, 0x4D, 0x37, 0x1B, 0xAB, 0xA0, 0xB4, 0x4C,
240 0x0A, 0x51, 0x4E, 0x02, 0x82, 0x85, 0xCB, 0x12,
241 0x0E, 0x1D, 0xAB, 0xC7, 0x2A, 0xC5, 0x82, 0x69,
242 0xC4, 0xAF, 0x5F, 0x7F, 0x1E, 0x3F, 0xF8, 0xCD,
243 0xCB, 0xF1, 0xF5, 0xEF, 0xDF, 0x7F, 0xCC, 0xCC,
244 0x4C, 0x84, 0x6D, 0x98, 0x59, 0xD5, 0xEB, 0xCF,
245 0xA5, 0x16, 0xC4, 0xAB, 0x71, 0x72, 0xCB, 0x21,
246 0x4C, 0x59, 0x74, 0x03, 0x5E, 0x3F, 0x7F, 0xB3,
247 0x6B, 0xD6, 0x22, 0x46, 0xA6, 0x7F, 0x0C, 0x0C,
248 0x7F, 0xD7, 0x75, 0x4D, 0xFB, 0xF1, 0xFD, 0x27,
249 0x81, 0x78, 0xB8, 0x7D, 0xE9, 0x0A, 0xCB, 0xFF,
250 0xDF, 0x4C, 0x8C, 0x8C, 0x40, 0xF6, 0xAD, 0x4B,
251 0x67, 0x1F, 0xDE, 0xBD, 0x8B, 0x45, 0x03, 0x3C,
252 0x60, 0x8F, 0x9D, 0xD8, 0xB3, 0xEB, 0x74, 0xB5,
253 0x90, 0x26, 0x07, 0x03, 0x48, 0xE4, 0x3F, 0x8F,
254 0xF6, 0xFF, 0x1B, 0x0F, 0x9A, 0x1E, 0x3E, 0x3A,
255 0xFB, 0xF3, 0xDB, 0x8F, 0xB7, 0x0F, 0x9E, 0x43,
256 0x83, 0xF1, 0xCF, 0xDF, 0x3F, 0x8A, 0x29, 0xCE,
257 0x3F, 0x7F, 0xFD, 0xFC, 0xCF, 0xF0, 0xDF, 0x98,
258 0xE9, 0xB5, 0x8F, 0xBD, 0x8A, 0x3C, 0x6F, 0xEC,
259 0xB9, 0x2D, 0x47, 0xFE, 0xFC, 0xFF, 0x6F, 0x16,
260 0x6C, 0xF3, 0xEC, 0xD3, 0x1C, 0x2E, 0x96, 0xEF,
261 0xBF, 0xAB, 0x7E, 0x32, 0x7D, 0xE2, 0x10, 0xCE,
262 0x88, 0xF4, 0x69, 0x2B, 0x60, 0xFC, 0xF4, 0xF5,
263 0x97, 0x78, 0x8A, 0x36, 0xD8, 0x44, 0x86, 0x18,
264 0x0D, 0xD7, 0x29, 0x95, 0x13, 0xD8, 0xD9, 0x58,
265 0xE1, 0x0E, 0xF8, 0xF1, 0xF3, 0xDB, 0xC6, 0xD6,
266 0xEC, 0x5F, 0x53, 0x8E, 0xBF, 0xFE, 0xC3, 0x70,
267 0x93, 0x8D, 0x6D, 0xDA, 0xCB, 0x0B, 0x4C, 0x3F,
268 0xFF, 0xFC, 0xFA, 0xCF, 0x0C, 0xB4, 0x09, 0x84,
269 0x54, 0xD5, 0x74, 0x91, 0x55, 0x03, 0x01, 0x07,
270 0x3B, 0x97, 0x96, 0x6E, 0xC8, 0x17, 0xFE, 0x7F,
271 0x4F, 0xF8, 0xFE, 0xBC, 0x95, 0x16, 0x60, 0x62,
272 0x62, 0x64, 0xE1, 0xE6, 0x60, 0x73, 0xD1, 0xB2,
273 0x7A, 0xFA, 0xE2, 0xF1, 0xDF, 0x3F, 0xFF, 0xC4,
274 0x78, 0x44, 0x31, 0xA3, 0x45, 0x2B, 0xD0, 0xE3,
275 0xF6, 0xD9, 0xE3, 0x2F, 0x2E, 0x9D, 0x29, 0xA9,
276 0xAC, 0x07, 0xA6, 0x03, 0xF4, 0xB4, 0x44, 0x10,
277 0x00, 0x00, 0x75, 0x65, 0x12, 0xB0, 0x49, 0xFF,
278 0x3F, 0x68, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
279 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
280};
281
282const unsigned char favicon_ico[] = {
283 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10,
284 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x28, 0x01,
285 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
286 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00,
287 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x0F,
291 0x0A, 0x00, 0x5C, 0x86, 0x4C, 0x00, 0x2F, 0x5E,
292 0x1A, 0x00, 0xBF, 0xD3, 0xD7, 0x00, 0x29, 0x17,
293 0x8D, 0x00, 0x50, 0xA7, 0xA4, 0x00, 0x59, 0x57,
294 0x7F, 0x00, 0xC6, 0xA3, 0xAC, 0x00, 0xFC, 0xFE,
295 0xFC, 0x00, 0x28, 0x12, 0x53, 0x00, 0x58, 0x7D,
296 0x72, 0x00, 0xC4, 0x3A, 0x34, 0x00, 0x3C, 0x3D,
297 0x69, 0x00, 0xC5, 0xB6, 0xB9, 0x00, 0x94, 0x92,
298 0x87, 0x00, 0x7E, 0x7A, 0xAA, 0x00, 0x88, 0x88,
299 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x81, 0x22,
300 0xD8, 0x88, 0x88, 0x88, 0xF6, 0xD8, 0x82, 0x22,
301 0xE8, 0x88, 0x88, 0x8D, 0x44, 0x98, 0x82, 0x22,
302 0xA8, 0x88, 0x88, 0x8F, 0x44, 0x48, 0x82, 0x22,
303 0x25, 0x76, 0x67, 0x55, 0x44, 0xF8, 0x88, 0x88,
304 0x3A, 0xC9, 0x9C, 0x53, 0x83, 0x88, 0x88, 0x88,
305 0x8D, 0x99, 0x99, 0x38, 0x88, 0x88, 0x88, 0x88,
306 0x88, 0x99, 0x9C, 0x88, 0x88, 0x88, 0x88, 0x88,
307 0x88, 0xF9, 0x9D, 0x88, 0x88, 0x88, 0x88, 0x88,
308 0x88, 0x8A, 0x58, 0x88, 0x88, 0x88, 0x88, 0x88,
309 0x88, 0x85, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
310 0x88, 0xEA, 0xAE, 0x88, 0x88, 0x88, 0x88, 0x88,
311 0x88, 0x00, 0x0B, 0x88, 0x88, 0x88, 0x88, 0x88,
312 0x88, 0x70, 0x0D, 0x88, 0x88, 0x88, 0x88, 0x88,
313 0x88, 0x87, 0xD8, 0x88, 0x88, 0x88, 0x88, 0x88,
314 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
323};
324
325/*------------------------------------------------------------------*/
326
327class Param;
328class Return;
329void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh);
330int vaxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
331 int minor, int major, int text, int label, int grid, double ymin, double ymax,
332 BOOL logaxis);
333void haxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
334 int minor, int major, int text, int label, int grid, double xmin, double xmax);
335void get_elog_url(char *url, int len);
336void show_header(Return* r, const char *title, const char *method, const char *path, int refresh);
337void show_navigation_bar(Return* r, const char *cur_page);
338
339/*------------------------------------------------------------------*/
340
341char *stristr(const char *str, const char *pattern)
342{
343 char c1, c2, *ps, *pp;
344
345 if (str == NULL || pattern == NULL)
346 return NULL;
347
348 while (*str) {
349 ps = (char *) str;
350 pp = (char *) pattern;
351 c1 = *ps;
352 c2 = *pp;
353 if (toupper(c1) == toupper(c2)) {
354 while (*pp) {
355 c1 = *ps;
356 c2 = *pp;
357
358 if (toupper(c1) != toupper(c2))
359 break;
360
361 ps++;
362 pp++;
363 }
364
365 if (!*pp)
366 return (char *) str;
367 }
368 str++;
369 }
370
371 return NULL;
372}
373
374/*------------------------------------------------------------------*/
375
376static double GetTimeSec()
377{
378 struct timeval tv;
380 return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
381}
382
383/*------------------------------------------------------------------*/
384
386{
387public:
388 double fTimeReceived; // time request received
389 double fTimeLocked; // time lock is taken
390 double fTimeUnlocked; // time lock is released
391 double fTimeProcessed; // time processing of request is done
392 double fTimeSent; // time sending the request is done
393 bool fCompleted; // flag the request completed, it's RequestTrace is safe to delete
394 std::string fMethod; // request HTTP method
395 std::string fUri; // request URL/URI
396 std::string fQuery; // request query string
397 std::string fRPC; // request RPC
398 std::string fResource; // request file resource, with full path
399 bool fAuthOk; // password check passed
400
401public:
402 RequestTrace() // ctor
403 {
404 fTimeReceived = 0;
405 fTimeLocked = 0;
406 fTimeUnlocked = 0;
407 fTimeProcessed = 0;
408 fTimeSent = 0;
409 fCompleted = false;
410 fAuthOk = false;
411 }
412
413 void PrintTrace0() const
414 {
415 printf("%.3f ", fTimeReceived);
420 printf("A ");
421 printf("%d ", fAuthOk);
422 printf("T ");
426 printf("M %s ", fMethod.c_str());
427 printf("URL %s ", fUri.c_str());
428 if (fRPC.length() > 0) {
429 printf("RPC %s ", fRPC.c_str());
430 }
431 printf("\n");
432 };
433};
434
435static int http_trace = 0;
436
438{
439public:
441 std::vector<RequestTrace*> fBuf;
442
443public:
445 {
446 int status;
448 assert(status==SS_SUCCESS || status==SS_CREATED);
449 }
450
451 //RequestTrace* NewTrace() // RequestTrace factory
452 //{
453 // RequestTrace* t = new RequestTrace;
454 // fBuf.push_back(t);
455 // return t;
456 //}
457
459 {
460 fBuf.push_back(t);
461 }
462
464 {
466 if (http_trace) {
467 t->PrintTrace0();
468 }
469 delete t;
470 //AddTrace(t);
472 }
473
474 void Clear() // clear all completed requests
475 {
476 // delete all completed requests
477 for (unsigned i=0; i<fBuf.size(); i++) {
478 if (fBuf[i] && fBuf[i]->fCompleted) {
479 delete fBuf[i];
480 fBuf[i] = NULL;
481 }
482 }
483
484 // compact all non-completed requests
485 unsigned k = 0;
486 for (unsigned i=0; i<fBuf.size(); i++) {
487 if (fBuf[i]) {
488 if (fBuf[k] != NULL) {
489 for (; k<i; k++) {
490 if (fBuf[k] == NULL) {
491 break;
492 }
493 }
494 }
495 // if we found an empty spot between "k" and "i" move "i" there
496 // if there is no empty spot, then "i" does not need to be moved
497 if (fBuf[k] == NULL) {
498 fBuf[k] = fBuf[i];
499 fBuf[i] = NULL;
500 }
501 }
502 }
503 }
504};
505
507
508/*------------------------------------------------------------------*/
509
510/* size of buffer for incoming data, must fit sum of all attachments */
511#define WEB_BUFFER_SIZE (6*1024*1024)
512
514{
515public:
516
519
522
523public:
524 Return() // ctor
525 {
529
530 strlen_retbuf = 0;
531 return_length = 0;
532 }
533
534 ~Return() // dtor
535 {
536 if (return_buffer)
537 free(return_buffer);
539 return_size = 0;
540 strlen_retbuf = 0;
541 return_length = 0;
542 }
543
544 void reset()
545 {
546 strlen_retbuf = 0;
547 }
548
549 void zero()
550 {
552 strlen_retbuf = 0;
553 return_length = 0;
554 }
555
556int return_grow(size_t len)
557{
558 //printf("size %d, grow %d, room %d\n", return_size, len, return_size - strlen_retbuf);
559
560 for (int i=0; i<1000; i++) { // infinite loop with protection against infinite looping
561 if (strlen_retbuf + len < return_size-40)
562 return SUCCESS;
563
564 return_size *= 2;
566
568
569 //printf("new size %d\n", return_size);
570 }
571
572 assert(!"Cannot happen!"); // does not return
573 return 0;
574}
575
576/*------------------------------------------------------------------*/
577
578void rmemcpy(const void *buf, int len)
579{
580 return_grow(len);
582 strlen_retbuf += len;
584}
585
586/*------------------------------------------------------------------*/
587
588void rread(const char* filename, int fh, int len)
589{
590 return_grow(len);
591 int rd = read(fh, return_buffer + strlen_retbuf, len);
592 if (rd != len) {
593 cm_msg(MERROR, "rread", "Cannot read file \'%s\', read of %d returned %d, errno %d (%s)", filename, len, rd, errno, strerror(errno));
595 }
596 strlen_retbuf += len;
598}
599
600/*------------------------------------------------------------------*/
601
602void rsputs(const char *str)
603{
604 size_t len = strlen(str);
605
606 return_grow(len);
607
608 if (strlen_retbuf + len > return_size-40) {
609 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
611 } else {
613 strlen_retbuf += len;
614 }
615
617}
618
619/*------------------------------------------------------------------*/
620
621void rsputs2(const char *str)
622{
623 size_t len = strlen(str);
624
625 return_grow(len);
626
627 if (strlen_retbuf + len > return_size) {
628 mstrlcpy(return_buffer, "<H1>Error: return buffer too small</H1>", return_size);
630 } else {
631 int j = strlen_retbuf;
632 for (size_t i = 0; i < len; i++) {
633 if (strncmp(str + i, "http://", 7) == 0) {
634 int k;
635 char link[256];
636 char* p = (char *) (str + i + 7);
637
638 i += 7;
639 for (k = 0; *p && *p != ' ' && *p != '\n'; k++, i++)
640 link[k] = *p++;
641 link[k] = 0;
642
643 sprintf(return_buffer + j, "<a href=\"http://%s\">http://%s</a>", link, link);
644 j += strlen(return_buffer + j);
645 } else
646 switch (str[i]) {
647 case '<':
649 j += 4;
650 break;
651 case '>':
653 j += 4;
654 break;
655 default:
656 return_buffer[j++] = str[i];
657 }
658 }
659
660 return_buffer[j] = 0;
662 }
663
665}
666
667/*------------------------------------------------------------------*/
668
669void rsprintf(const char *format, ...) MATTRPRINTF(2,3)
670{
672 char str[10000];
673
674 va_start(argptr, format);
675 vsprintf(str, (char *) format, argptr);
677
678 // catch array overrun. better too late than never...
679 assert(strlen(str) < sizeof(str));
680
682
684 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
685 else
687
690}
691};
692
693/*------------------------------------------------------------------*/
694
695/* Parameter handling functions similar to setenv/getenv */
696
697#define MAX_PARAM 500
698#define PARAM_LENGTH 256
699#define TEXT_SIZE 50000
700
701class Param
702{
703public:
707
708public:
709 Param() // ctor
710 {
711 initparam();
712 }
713
714 ~Param() // dtor
715 {
716 freeparam();
717 }
718
720 {
721 memset(_param, 0, sizeof(_param));
722 memset(_value, 0, sizeof(_value));
723 _text[0] = 0;
724 }
725
726 void setparam(const char *param, const char *value)
727 {
728 int i;
729
730 if (equal_ustring(param, "text")) {
731 if (strlen(value) >= TEXT_SIZE)
732 printf("Error: parameter value too big\n");
733
735 _text[TEXT_SIZE - 1] = 0;
736 return;
737 }
738
739 for (i = 0; i < MAX_PARAM; i++)
740 if (_param[i][0] == 0)
741 break;
742
743 if (i < MAX_PARAM) {
745
746 int size = strlen(value)+1;
747 _value[i] = (char*)malloc(size);
748 mstrlcpy(_value[i], value, size);
749 _value[i][strlen(value)] = 0;
750
751 } else {
752 printf("Error: parameter array too small\n");
753 }
754 }
755
757 {
758 int i;
759
760 for (i=0 ; i<MAX_PARAM ; i++)
761 if (_value[i] != NULL) {
762 free(_value[i]);
763 _value[i] = NULL;
764 }
765 }
766
768 {
769 int i;
770
771 for (i = 0; i < MAX_PARAM && _param[i][0]; i++) {
772 printf("param %d name [%s] value [%s]\n", i, _param[i], _value[i]);;
773 }
774 }
775
776 const char *getparam(const char *param)
777 {
778 int i;
779
780 if (equal_ustring(param, "text"))
781 return _text;
782
783 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
785 break;
786
787 if (i == MAX_PARAM)
788 return NULL;
789
790 if (_value[i] == NULL)
791 return "";
792
793 return _value[i];
794 }
795
796 std::string xgetparam(const char *param)
797 {
798 const char* s = getparam(param);
799 if (s)
800 return s;
801 else
802 return "";
803 }
804
805 BOOL isparam(const char *param)
806 {
807 int i;
808
809 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
811 break;
812
813 if (i < MAX_PARAM && _param[i][0])
814 return TRUE;
815
816 return FALSE;
817 }
818
819 void unsetparam(const char *param)
820 {
821 int i;
822
823 for (i = 0; i < MAX_PARAM; i++)
825 break;
826
827 if (i < MAX_PARAM) {
828 _param[i][0] = 0;
829 _value[i][0] = 0;
830 }
831 }
832};
833
834/*------------------------------------------------------------------*/
835
836const char *mhttpd_revision(void)
837{
838 return cm_get_revision();
839}
840
841/*------------------------------------------------------------------*/
842
843static std::string UrlDecode(const char* p)
844/********************************************************************\
845 Decode the given string in-place by expanding %XX escapes
846\********************************************************************/
847{
848 std::string s;
849
850 //printf("URL decode: [%s] --> ", p);
851
852 while (*p) {
853 if (*p == '%') {
854 /* Escape: next 2 chars are hex representation of the actual character */
855 p++;
856 if (isxdigit(p[0]) && isxdigit(p[1])) {
857 int i = 0;
858 char str[3];
859 str[0] = p[0];
860 str[1] = p[1];
861 str[2] = 0;
862 sscanf(str, "%02X", &i);
863
864 s += (char) i;
865 p += 2;
866 } else
867 s += '%';
868 } else if (*p == '+') {
869 /* convert '+' to ' ' */
870 s += ' ';
871 p++;
872 } else {
873 s += *p++;
874 }
875 }
876
877 //printf("[%s]\n", s.c_str());
878
879 return s;
880}
881
882static void urlDecode(char *p)
883/********************************************************************\
884 Decode the given string in-place by expanding %XX escapes
885\********************************************************************/
886{
887 //char *px = p;
888 char *pD, str[3];
889 int i;
890
891 //printf("URL decode: [%s] --> ", p);
892
893 pD = p;
894 while (*p) {
895 if (*p == '%') {
896 /* Escape: next 2 chars are hex representation of the actual character */
897 p++;
898 if (isxdigit(p[0]) && isxdigit(p[1])) {
899 str[0] = p[0];
900 str[1] = p[1];
901 str[2] = 0;
902 sscanf(str, "%02X", &i);
903
904 *pD++ = (char) i;
905 p += 2;
906 } else
907 *pD++ = '%';
908 } else if (*p == '+') {
909 /* convert '+' to ' ' */
910 *pD++ = ' ';
911 p++;
912 } else {
913 *pD++ = *p++;
914 }
915 }
916 *pD = '\0';
917
918 //printf("[%s]\n", px);
919}
920
921static void urlEncode(char *ps, int ps_size)
922/*
923 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
924 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
925*/
926{
927 char *pd, *p;
928 int len = strlen(ps);
929 char *str = (char*)malloc(len*3 + 10); // at worst, each input character is expanded into 3 output characters
930
931 pd = str;
932 p = ps;
933 while (*p) {
934 if (isalnum(*p)) {
935 *pd++ = *p++;
936 } else {
937 sprintf(pd, "%%%02X", (*p)&0xFF);
938 pd += 3;
939 p++;
940 }
941 }
942 *pd = '\0';
943
944 if (/* DISABLES CODE */ (0)) {
945 printf("urlEncode [");
946 for (p=ps; *p!=0; p++)
947 printf("0x%02x ", (*p)&0xFF);
948 printf("]\n");
949
950 printf("urlEncode [%s] -> [%s]\n", ps, str);
951 }
952
954 free(str);
955}
956
957static std::string urlEncode(const char *text)
958/*
959 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
960 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
961*/
962{
963 std::string encoded;
964
965 const char* p = text;
966 while (*p) {
967 if (isalnum(*p)) {
968 encoded += *p++;
969 } else {
970 char buf[16];
971 sprintf(buf, "%%%02X", (*p)&0xFF);
972 encoded += buf;
973 p++;
974 }
975 }
976
977 if (/* DISABLES CODE */ (0)) {
978 printf("urlEncode [");
979 for (p=text; *p!=0; p++)
980 printf("0x%02x ", (*p)&0xFF);
981 printf("]\n");
982
983 printf("urlEncode [%s] -> [%s]\n", text, encoded.c_str());
984 }
985
986 return encoded;
987}
988
989/*------------------------------------------------------------------*/
990
991std::vector<std::string> get_resource_paths()
992{
993 HNDLE hDB;
994 int status;
995
997
998 std::vector<std::string> paths;
999
1000 // add /Experiment/Resources
1001 std::string buf;
1002 status = db_get_value_string(hDB, 0, "/Experiment/Resources", 0, &buf, TRUE);
1003 if (status == DB_SUCCESS && buf.length() > 0)
1004 paths.push_back(buf);
1005
1006 // add "/Logger/History/IMAGE/History dir"
1007 paths.push_back(cm_get_history_path("IMAGE"));
1008
1009 // add /Logger/Data dir
1010 status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &buf, TRUE);
1011 if (status == DB_SUCCESS && buf.length() > 0)
1012 paths.push_back(buf);
1013
1014 std::string cwd = ss_getcwd();
1015 if (!cwd.empty()) {
1016 paths.push_back(cwd + "/");
1017 paths.push_back(cwd + "/resources/");
1018 }
1019 paths.push_back(cm_get_path());
1020 paths.push_back(cm_get_path() + "resources/");
1021 char *m = getenv("MIDASSYS");
1022 if (m) {
1023 paths.push_back(std::string(m) + "/resources/");
1024 }
1025
1026 return paths;
1027}
1028
1029/*------------------------------------------------------------------*/
1030
1031bool open_resource_file(const char *filename, std::string* ppath, FILE** pfp)
1032{
1033 // resource file names should not start with a directory separator "/"
1034 // or contain ".." as this will allow them to escape the mhttpd filename "jail"
1035 // by asking file files names like "../../etc/passwd", etc.
1036
1037 if (strlen(filename) < 1) {
1038 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' is too short",
1039 filename);
1040 return false;
1041 }
1042
1043 if (filename[0] == DIR_SEPARATOR) {
1044 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' starting with \'%c\' which is not allowed",
1045 filename, DIR_SEPARATOR);
1046 return false;
1047 }
1048
1049 if (strstr(filename, "..") != NULL) {
1050 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' containing \'..\' which is not allowed",
1051 filename);
1052 return false;
1053 }
1054
1055 std::vector<std::string> paths = get_resource_paths();
1056
1057 std::vector<std::string> paths_not_found;
1058
1059 for (unsigned i=0; i<paths.size(); i++) {
1060 std::string path = paths[i];
1061 if (path.length() < 1)
1062 continue;
1063 if (path[0] == '#')
1064 continue;
1065
1066 // expand env.variables before we add the filename.
1067 // the filename comes from the URL and if the URL
1068 // has '$' characters we will try to expand them
1069 // as an env.variable and maybe escape the file jail.
1070
1071 std::string xpath = cm_expand_env(path.c_str());
1072
1073 if (xpath[xpath.length()-1] != DIR_SEPARATOR)
1075 xpath += filename;
1076
1077 //printf("path [%s] [%s] [%s]\n", paths[i].c_str(), path.c_str(), xpath.c_str());
1078
1079 FILE* fp = fopen(xpath.c_str(), "r");
1080 if (fp) {
1081 struct stat statbuf;
1082 int status = fstat(fileno(fp), &statbuf);
1083 if (status != 0) {
1084 cm_msg(MERROR, "open_resource_file", "Cannot fstat() file \'%s\', error %d (%s)", xpath.c_str(), errno, strerror(errno));
1085 fclose(fp);
1086 fp = NULL;
1087 }
1088
1089 if (statbuf.st_mode & S_IFREG) {
1090 // good, normal file
1091 //printf("%s: regular!\n", xpath.c_str());
1092 //} else if (statbuf.st_mode & S_IFLNK) {
1093 // symlink
1094 //printf("%s: symlink!\n", xpath.c_str());
1095 } else if (statbuf.st_mode & S_IFDIR) {
1096 cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is a directory", xpath.c_str(), filename);
1097 fclose(fp);
1098 fp = NULL;
1099 } else {
1100 cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is not a regular file, st_mode is 0x%08x", xpath.c_str(), filename, statbuf.st_mode);
1101 fclose(fp);
1102 fp = NULL;
1103 }
1104
1105 if (fp) {
1106 if (ppath)
1107 *ppath = xpath;
1108 if (pfp) {
1109 *pfp = fp;
1110 } else {
1111 fclose(fp);
1112 fp = NULL;
1113 }
1114 //cm_msg(MINFO, "open_resource_file", "Resource file \'%s\' is \'%s\'", filename, xpath.c_str());
1115 return true;
1116 }
1117 }
1118
1119 paths_not_found.push_back(xpath);
1120 }
1121
1122 std::string s;
1123 for (unsigned i=0; i<paths_not_found.size(); i++) {
1124 if (i>0)
1125 s += ", ";
1126 s += paths_not_found[i];
1127 }
1128
1129 cm_msg(MERROR, "open_resource_file", "Cannot find resource file \'%s\', tried %s", filename, s.c_str());
1130 return false;
1131}
1132
1133/*------------------------------------------------------------------*/
1134
1135std::string get_content_type(const char* filename)
1136{
1137 std::string ext_upper;
1138 const char* p = filename;
1139 const char* last_dot = NULL;
1140 for (; *p; p++) {
1141 if (*p == '.')
1142 last_dot = p;
1143 if (*p == DIR_SEPARATOR)
1144 last_dot = NULL;
1145 }
1146
1147 if (last_dot) {
1148 p = last_dot;
1149 for (; *p; p++)
1150 ext_upper += toupper(*p);
1151 }
1152
1153 //printf("filename: [%s], ext [%s]\n", filename, ext_upper.c_str());
1154
1155 std::string type = GetMimetype(ext_upper);
1156 if (type.length() > 0)
1157 return type;
1158
1159 cm_msg(MERROR, "get_content_type", "Unknown HTTP Content-Type for resource file \'%s\', file extension \'%s\'", filename, ext_upper.c_str());
1160
1161 return "text/plain";
1162}
1163
1164/*------------------------------------------------------------------*/
1165
1166bool send_fp(Return* r, const std::string& path, FILE* fp)
1167{
1168 assert(fp != NULL);
1169
1170 // send HTTP headers
1171
1172 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1173 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1174 r->rsprintf("Accept-Ranges: bytes\r\n");
1175
1176 // send HTTP cache control headers
1177
1178 time_t now = time(NULL);
1179 now += (int) (3600 * 24);
1180 struct tm gmt_tms;
1181 gmtime_r(&now, &gmt_tms);
1182 const char* format = "%A, %d-%b-%y %H:%M:%S GMT";
1183
1184 char str[256];
1185 strftime(str, sizeof(str), format, &gmt_tms);
1186 r->rsprintf("Expires: %s\r\n", str);
1187
1188 // send Content-Type header
1189
1190 r->rsprintf("Content-Type: %s\r\n", get_content_type(path.c_str()).c_str());
1191
1192 // send Content-Length header
1193
1194 struct stat stat_buf;
1195 fstat(fileno(fp), &stat_buf);
1196 int length = stat_buf.st_size;
1197 r->rsprintf("Content-Length: %d\r\n", length);
1198
1199 // send end of headers
1200
1201 r->rsprintf("\r\n");
1202
1203 // send file data
1204
1205 r->rread(path.c_str(), fileno(fp), length);
1206
1207 fclose(fp);
1208
1209 return true;
1210}
1211
1212bool send_file(Return* r, const std::string& path, bool generate_404 = true)
1213{
1214 FILE *fp = fopen(path.c_str(), "rb");
1215
1216 if (!fp) {
1217 if (generate_404) {
1218 /* header */
1219 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1220 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1221 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1222 r->rsprintf("\r\n");
1223 r->rsprintf("Error: Cannot read \"%s\", fopen() errno %d (%s)\n", path.c_str(), errno, strerror(errno));
1224 }
1225 return false;
1226 }
1227
1228 return send_fp(r, path, fp);
1229}
1230
1231bool send_resource(Return* r, const std::string& name, bool generate_404 = true)
1232{
1233 std::string path;
1234 FILE *fp = NULL;
1235
1236 bool found = open_resource_file(name.c_str(), &path, &fp);
1237
1238 if (!found) {
1239 if (generate_404) {
1240 /* header */
1241 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1242 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1243 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1244 r->rsprintf("\r\n");
1245 r->rsprintf("Error: resource file \"%s\" not found, see messages\n", name.c_str());
1246 }
1247 return false;
1248 }
1249
1250 return send_fp(r, path, fp);
1251}
1252
1253/*------------------------------------------------------------------*/
1254
1255INT sendmail(const char* from_host, const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
1256{
1257 struct sockaddr_in bind_addr;
1258 struct hostent *phe;
1259 int i, s, strsize, offset;
1260 char *str, buf[256];
1261
1262 if (verbose)
1263 printf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
1264
1265 /* create a new socket for connecting to remote server */
1266 s = socket(AF_INET, SOCK_STREAM, 0);
1267 if (s == -1)
1268 return -1;
1269
1270 /* connect to remote node port 25 */
1271 memset(&bind_addr, 0, sizeof(bind_addr));
1272 bind_addr.sin_family = AF_INET;
1273 bind_addr.sin_port = htons((short) 25);
1274
1276 if (phe == NULL)
1277 return -1;
1278 memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
1279
1280 if (connect(s, (const sockaddr*)&bind_addr, sizeof(bind_addr)) < 0) {
1281 closesocket(s);
1282 return -1;
1283 }
1284
1285 strsize = TEXT_SIZE + 1000;
1286 str = (char*)malloc(strsize);
1287
1288 recv_string(s, str, strsize, 3000);
1289 if (verbose)
1290 puts(str);
1291
1292 /* drain server messages */
1293 do {
1294 str[0] = 0;
1295 recv_string(s, str, strsize, 300);
1296 if (verbose)
1297 puts(str);
1298 } while (str[0]);
1299
1300 sprintf(str, "HELO %s\r\n", from_host);
1301 send(s, str, strlen(str), 0);
1302 if (verbose)
1303 puts(str);
1304 recv_string(s, str, strsize, 3000);
1305 if (verbose)
1306 puts(str);
1307
1308 if (strchr(from, '<')) {
1309 mstrlcpy(buf, strchr(from, '<') + 1, sizeof(buf));
1310 if (strchr(buf, '>'))
1311 *strchr(buf, '>') = 0;
1312 } else
1313 mstrlcpy(buf, from, sizeof(buf));
1314
1315 sprintf(str, "MAIL FROM: %s\n", buf);
1316 send(s, str, strlen(str), 0);
1317 if (verbose)
1318 puts(str);
1319 recv_string(s, str, strsize, 3000);
1320 if (verbose)
1321 puts(str);
1322
1323 sprintf(str, "RCPT TO: <%s>\r\n", to);
1324 send(s, str, strlen(str), 0);
1325 if (verbose)
1326 puts(str);
1327 recv_string(s, str, strsize, 3000);
1328 if (verbose)
1329 puts(str);
1330
1331 sprintf(str, "DATA\r\n");
1332 send(s, str, strlen(str), 0);
1333 if (verbose)
1334 puts(str);
1335 recv_string(s, str, strsize, 3000);
1336 if (verbose)
1337 puts(str);
1338
1339 sprintf(str, "To: %s\r\nFrom: %s\r\nSubject: %s\r\n", to, from, subject);
1340 send(s, str, strlen(str), 0);
1341 if (verbose)
1342 puts(str);
1343
1344 sprintf(str, "X-Mailer: mhttpd revision %s\r\n", mhttpd_revision());
1345 send(s, str, strlen(str), 0);
1346 if (verbose)
1347 puts(str);
1348
1349 ss_tzset(); // required for localtime_r()
1350 time_t now;
1351 time(&now);
1352 struct tm tms;
1353 localtime_r(&now, &tms);
1354 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", &tms);
1355 offset = (-(int) timezone);
1356 if (tms.tm_isdst)
1357 offset += 3600;
1358 sprintf(str, "Date: %s %+03d%02d\r\n", buf, (int) (offset / 3600),
1359 (int) ((abs((int) offset) / 60) % 60));
1360 send(s, str, strlen(str), 0);
1361 if (verbose)
1362 puts(str);
1363
1364 sprintf(str, "Content-Type: TEXT/PLAIN; charset=US-ASCII\r\n\r\n");
1365 send(s, str, strlen(str), 0);
1366 if (verbose)
1367 puts(str);
1368
1369 /* analyze text for "." at beginning of line */
1370 const char* p = text;
1371 str[0] = 0;
1372 while (strstr(p, "\r\n.\r\n")) {
1373 i = (POINTER_T) strstr(p, "\r\n.\r\n") - (POINTER_T) p + 1;
1374 mstrlcat(str, p, i);
1375 p += i + 4;
1376 mstrlcat(str, "\r\n..\r\n", strsize);
1377 }
1378 mstrlcat(str, p, strsize);
1379 mstrlcat(str, "\r\n", strsize);
1380 send(s, str, strlen(str), 0);
1381 if (verbose)
1382 puts(str);
1383
1384 /* send ".<CR>" to signal end of message */
1385 sprintf(str, ".\r\n");
1386 send(s, str, strlen(str), 0);
1387 if (verbose)
1388 puts(str);
1389 recv_string(s, str, strsize, 3000);
1390 if (verbose)
1391 puts(str);
1392
1393 sprintf(str, "QUIT\n");
1394 send(s, str, strlen(str), 0);
1395 if (verbose)
1396 puts(str);
1397 recv_string(s, str, strsize, 3000);
1398 if (verbose)
1399 puts(str);
1400
1401 closesocket(s);
1402 free(str);
1403
1404 return 1;
1405}
1406
1407/*------------------------------------------------------------------*/
1408
1409void redirect(Return *r, const char *path)
1410{
1411 char str[256];
1412
1413 //printf("redirect to [%s]\n", path);
1414
1415 mstrlcpy(str, path, sizeof(str));
1416 if (str[0] == 0)
1417 strcpy(str, "./");
1418
1419 /* redirect */
1420 r->rsprintf("HTTP/1.1 302 Found\r\n");
1421 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1422 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1423
1424 if (strncmp(path, "http:", 5) == 0)
1425 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1426 else if (strncmp(path, "https:", 6) == 0)
1427 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1428 else {
1429 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1430 }
1431}
1432
1433void redirect_307(Return *r, const char *path)
1434{
1435 //printf("redirect_307 to [%s]\n", path);
1436
1437 /* redirect */
1438 r->rsprintf("HTTP/1.1 307 Temporary Redirect\r\n");
1439 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1440 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1441 r->rsprintf("Location: %s\r\n", path);
1442 r->rsprintf("\r\n");
1443 r->rsprintf("<html>redirect to %s</html>\r\n", path);
1444}
1445
1446void redirect2(Return* r, const char *path)
1447{
1448 redirect(r, path);
1449}
1450
1451/*------------------------------------------------------------------*/
1452
1454{
1456 const char* search_name;
1457};
1458
1460{
1462 int i;
1463 INT size, status;
1464
1465 Return* r = sinfo->r;
1466 const char* search_name = sinfo->search_name;
1467
1468 /* convert strings to uppercase */
1469
1470 char xstr1[MAX_ODB_PATH];
1471 for (i = 0; key->name[i]; i++)
1472 xstr1[i] = toupper(key->name[i]);
1473 xstr1[i] = 0;
1474
1475 char str2[MAX_ODB_PATH];
1476 for (i = 0; search_name[i] ; i++)
1477 str2[i] = toupper(search_name[i]);
1478 str2[i] = 0;
1479
1480 if (strstr(xstr1, str2) != NULL) {
1481 char data[10000];
1482 std::string path = db_get_path(hDB, hKey).substr(1);
1483 std::string path_encoded = urlEncode(path.c_str());
1484
1485 if (key->type == TID_KEY || key->type == TID_LINK) {
1486 /* for keys, don't display data value */
1487 r->rsprintf("<tr><td class=\"ODBkey\"><a href=\"?cmd=odb&odb_path=/%s\">/%s</a></tr>\n", path_encoded.c_str(), path.c_str());
1488 } else {
1489 /* strip variable name from path */
1490 char* p = const_cast<char *>(path.data() + path.length() - 1);
1491 while (*p && *p != '/')
1492 *p-- = 0;
1493 if (*p == '/')
1494 *p = 0;
1495
1496 /* display single value */
1497 if (key->num_values == 1) {
1498 size = sizeof(data);
1499 status = db_get_data(hDB, hKey, data, &size, key->type);
1500 std::string data_str;
1501 if (status == DB_NO_ACCESS)
1502 data_str = "<no read access>";
1503 else
1505
1506 r->rsprintf("<tr><td class=\"ODBkey\">");
1507 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s</a></td>", path_encoded.c_str(), path.c_str(), key->name);
1508 r->rsprintf("<td class=\"ODBvalue\">%s</td></tr>\n", data_str.c_str());
1509 } else {
1510 /* display first value */
1511 i = key->num_values;
1512 if (i > 10)
1513 i = 11;
1514 r->rsprintf("<tr><td rowspan=%d class=\"ODBkey\">", i);
1515 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s\n", path_encoded.c_str(), path.c_str(), key->name);
1516
1517 for (int i = 0; i < key->num_values; i++) {
1518 size = sizeof(data);
1519 db_get_data_index(hDB, hKey, data, &size, i, key->type);
1520
1521 std::string data_str = db_sprintf(data, key->item_size, 0, key->type);
1522
1523 if (i > 0)
1524 r->rsprintf("<tr>");
1525
1526 r->rsprintf("<td class=\"ODBvalue\">[%d] %s</td></tr>\n", i, data_str.c_str());
1527
1528 if (i > 8) {
1529 r->rsprintf("<tr><td class=\"ODBvalue\">... [%d] values ...</td></tr>\n", key->num_values - i - 1);
1530 break;
1531 }
1532 }
1533 }
1534 }
1535 }
1536
1537 return SUCCESS;
1538}
1539
1540/*------------------------------------------------------------------*/
1541
1542void show_help_page(Return* r, const char* dec_path)
1543{
1544 const char *s;
1545 char str[256];
1546 int status;
1547
1548 show_header(r, "Help", "", "./", 0);
1549 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
1550 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
1551 show_navigation_bar(r, "Help");
1552
1553 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1554 r->rsprintf(" <tr>\n");
1555 r->rsprintf(" <td class=\"mtableheader\">MIDAS Help Page</td>\n");
1556 r->rsprintf(" </tr>\n");
1557 r->rsprintf(" <tr>\n");
1558 r->rsprintf(" <td>\n");
1559 r->rsprintf(" <table>\n");
1560
1561 r->rsprintf(" <tr>\n");
1562 r->rsprintf(" <td style=\"text-align:right;\">Documentation:</td>\n");
1563 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca\">https://midas.triumf.ca</a></td>\n");
1564 r->rsprintf(" </tr>\n");
1565 r->rsprintf(" <tr>\n");
1566 r->rsprintf(" <td style=\"text-align:right;\">Discussion Forum:</td>\n");
1567 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca/forum/\">https://midas.triumf.ca/forum/</a></td>\n");
1568 r->rsprintf(" </tr>\n");
1569 r->rsprintf(" <tr>\n");
1570 r->rsprintf(" <td style=\"text-align:right;\">Code:</td>\n");
1571 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/\">https://bitbucket.org/tmidas/midas/</a></td>\n");
1572 r->rsprintf(" </tr>\n");
1573 r->rsprintf(" <tr>\n");
1574 r->rsprintf(" <td style=\"text-align:right;\">Report a bug:</td>\n");
1575 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/issues/\">https://bitbucket.org/tmidas/midas/issues/</a></td>\n");
1576 r->rsprintf(" </tr>\n");
1577
1578 r->rsprintf(" <tr>\n");
1579 r->rsprintf(" <td style=\"text-align:right;\">Version:</td>\n");
1580 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_version());
1581 r->rsprintf(" </tr>\n");
1582 r->rsprintf(" <tr>\n");
1583 r->rsprintf(" <td style=\"text-align:right;\">Revision:</td>\n");
1584 std::string rev = cm_get_revision();
1585 std::string url = "https://bitbucket.org/tmidas/midas/commits/";
1586 // rev format looks like this:
1587 // Fri Nov 24 10:15:54 2017 -0800 - midas-2017-07-c-171-gb8928d5c-dirty on branch develop
1588 // -gXXX is the commit hash
1589 // -dirty should be removed from the hash url, if present
1590 // " " before "on branch" should be removed from the hash url
1591 std::string::size_type pos = rev.find("-g");
1592 if (pos != std::string::npos) {
1593 std::string hash = rev.substr(pos+2);
1594 pos = hash.find("-dirty");
1595 if (pos != std::string::npos) {
1596 hash = hash.substr(0, pos);
1597 }
1598 pos = hash.find(" ");
1599 if (pos != std::string::npos) {
1600 hash = hash.substr(0, pos);
1601 }
1602 url += hash;
1603 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"%s\">%s</a></td>\n", url.c_str(), rev.c_str());
1604 } else {
1605 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", rev.c_str());
1606 }
1607 r->rsprintf(" </tr>\n");
1608
1609 r->rsprintf(" <tr>\n");
1610 r->rsprintf(" <td style=\"text-align:right;\">MIDASSYS:</td>\n");
1611 s = getenv("MIDASSYS");
1612 if (!s) s = "(unset)";
1613 mstrlcpy(str, s, sizeof(str));
1614 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", str);
1615 r->rsprintf(" </tr>\n");
1616
1617 r->rsprintf(" <tr>\n");
1618 r->rsprintf(" <td style=\"text-align:right;\">mhttpd current directory:</td>\n");
1619 std::string cwd = ss_getcwd();
1620 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cwd.c_str());
1621 r->rsprintf(" </tr>\n");
1622
1623 r->rsprintf(" <tr>\n");
1624 r->rsprintf(" <td style=\"text-align:right;\">Exptab file:</td>\n");
1625 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_exptab_filename().c_str());
1626 r->rsprintf(" </tr>\n");
1627
1628 r->rsprintf(" <tr>\n");
1629 r->rsprintf(" <td style=\"text-align:right;\">Experiment:</td>\n");
1630 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_experiment_name().c_str());
1631 r->rsprintf(" </tr>\n");
1632
1633 r->rsprintf(" <tr>\n");
1634 r->rsprintf(" <td style=\"text-align:right;\">Experiment directory:</td>\n");
1635 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_path().c_str());
1636 r->rsprintf(" </tr>\n");
1637
1640
1641 if (status == CM_SUCCESS) {
1642 if (list.size() == 1) {
1643 r->rsprintf(" <tr>\n");
1644 r->rsprintf(" <td style=\"text-align:right;\">System logfile:</td>\n");
1645 std::string s;
1646 cm_msg_get_logfile("midas", 0, &s, NULL, NULL);
1647 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", s.c_str());
1648 r->rsprintf(" </tr>\n");
1649 } else {
1650 r->rsprintf(" <tr>\n");
1651 r->rsprintf(" <td style=\"text-align:right;\">Logfiles:</td>\n");
1652 r->rsprintf(" <td style=\"text-align:left;\">\n");
1653 for (unsigned i=0 ; i<list.size() ; i++) {
1654 if (i>0)
1655 r->rsputs("<br />\n");
1656 std::string s;
1657 cm_msg_get_logfile(list[i].c_str(), 0, &s, NULL, NULL);
1658 r->rsputs(s.c_str());
1659 }
1660 r->rsprintf("\n </td>\n");
1661 r->rsprintf(" </tr>\n");
1662 }
1663 }
1664
1665 r->rsprintf(" <tr>\n");
1666 r->rsprintf(" <td style=\"text-align:right;\">Image history:</td>\n");
1667 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_history_path("IMAGE").c_str());
1668 r->rsprintf(" </tr>\n");
1669
1670 r->rsprintf(" <tr>\n");
1671 r->rsprintf(" <td style=\"text-align:right;\">Resource paths:</td>\n");
1672 r->rsprintf(" <td style=\"text-align:left;\">");
1673 std::vector<std::string> resource_paths = get_resource_paths();
1674 for (unsigned i=0; i<resource_paths.size(); i++) {
1675 if (i>0)
1676 r->rsputs("<br>");
1678 std::string exp = cm_expand_env(resource_paths[i].c_str());
1679 //printf("%d %d [%s] [%s]\n", resource_paths[i].length(), exp.length(), resource_paths[i].c_str(), exp.c_str());
1680 if (exp != resource_paths[i]) {
1681 r->rsputs(" (");
1682 r->rsputs(exp.c_str());
1683 r->rsputs(")");
1684 }
1685 }
1686 r->rsprintf(" </td>\n");
1687 r->rsprintf(" </tr>\n");
1688
1689 std::string path;
1690
1691 r->rsprintf(" <tr>\n");
1692 r->rsprintf(" <td style=\"text-align:right;\">midas.css:</td>\n");
1693 if (open_resource_file("midas.css", &path, NULL))
1694 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1695 else
1696 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1697 r->rsprintf(" </tr>\n");
1698
1699 r->rsprintf(" <tr>\n");
1700 r->rsprintf(" <td style=\"text-align:right;\">midas.js:</td>\n");
1701 if (open_resource_file("midas.js", &path, NULL))
1702 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1703 else
1704 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1705 r->rsprintf(" </tr>\n");
1706
1707 r->rsprintf(" <tr>\n");
1708 r->rsprintf(" <td style=\"text-align:right;\">controls.js:</td>\n");
1709 if (open_resource_file("controls.js", &path, NULL))
1710 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1711 else
1712 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1713 r->rsprintf(" </tr>\n");
1714
1715 r->rsprintf(" <tr>\n");
1716 r->rsprintf(" <td style=\"text-align:right;\">mhttpd.js:</td>\n");
1717 if (open_resource_file("mhttpd.js", &path, NULL))
1718 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1719 else
1720 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1721 r->rsprintf(" </tr>\n");
1722
1723 r->rsprintf(" <tr>\n");
1724 r->rsprintf(" <td style=\"text-align:right;\">obsolete.js:</td>\n");
1725 if (open_resource_file("obsolete.js", &path, NULL))
1726 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1727 else
1728 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1729 r->rsprintf(" </tr>\n");
1730
1731 r->rsprintf(" <tr>\n");
1732 r->rsprintf(" <td style=\"text-align:right;\">Obsolete mhttpd.css:</td>\n");
1733 if (open_resource_file("mhttpd.css", &path, NULL))
1734 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1735 else
1736 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1737 r->rsprintf(" </tr>\n");
1738
1739 r->rsprintf(" <tr>\n");
1740 r->rsprintf(" <td style=\"text-align:right;\">JSON-RPC schema:</td>\n");
1741 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?mjsonrpc_schema\">json format</a> or <a href=\"?mjsonrpc_schema_text\">text table format</a></td>\n");
1742 r->rsprintf(" </tr>\n");
1743
1744 r->rsprintf(" <tr>\n");
1745 r->rsprintf(" <td style=\"text-align:right;\">JavaScript examples:</td>\n");
1746 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=example\">example.html</a></td>\n");
1747 r->rsprintf(" </tr>\n");
1748
1749 r->rsprintf(" <tr>\n");
1750 r->rsprintf(" <td style=\"text-align:right;\">Custom page example:</td>\n");
1751 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=custom_example\">custom_example.html</a></td>\n");
1752 r->rsprintf(" </tr>\n");
1753
1754 r->rsprintf(" <tr>\n");
1755 r->rsprintf(" <td style=\"text-align:right;\">MPlot custom plot examples:</td>\n");
1756 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=plot_example\">plot_example.html</a></td>\n");
1757 r->rsprintf(" </tr>\n");
1758
1759 r->rsprintf(" </table>\n");
1760 r->rsprintf(" </td>\n");
1761 r->rsprintf(" </tr>\n");
1762 r->rsprintf("</table>\n");
1763
1764 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1765 r->rsprintf(" <tr>\n");
1766 r->rsprintf(" <td class=\"mtableheader\">Contributions</td>\n");
1767 r->rsprintf(" </tr>\n");
1768 r->rsprintf(" <tr>\n");
1769 r->rsprintf(" <td>\n");
1770 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");
1771 r->rsprintf(" </td>\n");
1772 r->rsprintf(" </tr>\n");
1773 r->rsprintf("</table>\n");
1774
1775 r->rsprintf("</div></form>\n");
1776 r->rsprintf("</body></html>\r\n");
1777}
1778
1779/*------------------------------------------------------------------*/
1780
1781void show_header(Return* r, const char *title, const char *method, const char *path, int refresh)
1782{
1783 HNDLE hDB;
1784 time_t now;
1785 char str[256];
1786
1788
1789 /* header */
1790 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1791 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1792 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1793 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1794 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1795
1796 r->rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
1797 r->rsprintf("<html><head>\n");
1798
1799 /* style sheet */
1800 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
1801 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1802 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
1803
1804 /* auto refresh */
1805 if (refresh > 0)
1806 r->rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
1807
1808 r->rsprintf("<title>%s</title></head>\n", title);
1809
1810 mstrlcpy(str, path, sizeof(str));
1811 urlEncode(str, sizeof(str));
1812
1813 if (equal_ustring(method, "POST"))
1814 r->rsprintf
1815 ("<body><form name=\"form1\" method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n\n",
1816 str);
1817 else if (equal_ustring(method, "GET"))
1818 r->rsprintf("<body><form name=\"form1\" method=\"GET\" action=\"%s\">\n\n", str);
1819
1820 /* title row */
1821
1822 std::string exptname;
1823 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
1824 time(&now);
1825}
1826
1827/*------------------------------------------------------------------*/
1828
1830{
1831 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1832 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1833 r->rsprintf("Access-Control-Allow-Origin: *\r\n");
1834 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1835 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1836 r->rsprintf("Content-Type: text/plain; charset=%s\r\n\r\n", HTTP_ENCODING);
1837}
1838
1839/*------------------------------------------------------------------*/
1840
1841void show_error(Return* r, const char *error)
1842{
1843 /* header */
1844 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1845 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1846 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1847
1848 r->rsprintf("<html><head>\n");
1849 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1850 r->rsprintf("<title>MIDAS error</title></head>\n");
1851 r->rsprintf("<body><H1>%s</H1></body></html>\n", error);
1852}
1853
1854/*------------------------------------------------------------------*/
1855
1856void show_error_404(Return* r, const char *error)
1857{
1858 /* header */
1859 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1860 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1861 r->rsprintf("Content-Type: text/plain\r\n");
1862 r->rsprintf("\r\n");
1863
1864 r->rsprintf("MIDAS error: %s\n", error);
1865}
1866
1867/*------------------------------------------------------------------*/
1868
1870{
1871 r->rsprintf("<script>\n");
1872 r->rsprintf("window.addEventListener(\"load\", function(e) { mhttpd_init('%s', 1000); });\n", cur_page);
1873 r->rsprintf("</script>\n");
1874
1875 r->rsprintf("<!-- header and side navigation will be filled in mhttpd_init -->\n");
1876 r->rsprintf("<div id=\"mheader\"></div>\n");
1877 r->rsprintf("<div id=\"msidenav\"></div>\n");
1878 r->rsprintf("<div id=\"mmain\">\n");
1879}
1880
1881/*------------------------------------------------------------------*/
1882
1883void check_obsolete_odb(HNDLE hDB, const char* odb_path)
1884{
1885 HNDLE hKey;
1886 int status = db_find_key(hDB, 0, odb_path, &hKey);
1887 if (status == DB_SUCCESS) {
1888 cm_msg(MERROR, "check_obsolete_odb", "ODB \"%s\" is obsolete, please delete it.", odb_path);
1889 }
1890}
1891
1893{
1894 HNDLE hDB;
1897 int size = sizeof(true_value);
1899 db_get_value(hDB, 0, "/Experiment/Menu/Status", &true_value, &size, TID_BOOL, TRUE);
1900 db_get_value(hDB, 0, "/Experiment/Menu/Start", &false_value, &size, TID_BOOL, TRUE);
1901 db_get_value(hDB, 0, "/Experiment/Menu/Transition", &true_value, &size, TID_BOOL, TRUE);
1902 db_get_value(hDB, 0, "/Experiment/Menu/ODB", &true_value, &size, TID_BOOL, TRUE);
1903 db_get_value(hDB, 0, "/Experiment/Menu/OldODB", &true_value, &size, TID_BOOL, TRUE);
1904 db_get_value(hDB, 0, "/Experiment/Menu/Messages", &true_value, &size, TID_BOOL, TRUE);
1905 db_get_value(hDB, 0, "/Experiment/Menu/Chat", &true_value, &size, TID_BOOL, TRUE);
1906 db_get_value(hDB, 0, "/Experiment/Menu/Elog", &true_value, &size, TID_BOOL, TRUE);
1907 db_get_value(hDB, 0, "/Experiment/Menu/Alarms", &true_value, &size, TID_BOOL, TRUE);
1908 db_get_value(hDB, 0, "/Experiment/Menu/Programs", &true_value, &size, TID_BOOL, TRUE);
1909 db_get_value(hDB, 0, "/Experiment/Menu/Buffers", &true_value, &size, TID_BOOL, TRUE);
1910 db_get_value(hDB, 0, "/Experiment/Menu/History", &true_value, &size, TID_BOOL, TRUE);
1911 db_get_value(hDB, 0, "/Experiment/Menu/OldHistory", &true_value, &size, TID_BOOL, TRUE);
1912 db_get_value(hDB, 0, "/Experiment/Menu/MSCB", &true_value, &size, TID_BOOL, TRUE);
1913 db_get_value(hDB, 0, "/Experiment/Menu/Sequencer", &true_value, &size, TID_BOOL, TRUE);
1914 db_get_value(hDB, 0, "/Experiment/Menu/PySequencer",&true_value, &size, TID_BOOL, TRUE);
1915 db_get_value(hDB, 0, "/Experiment/Menu/Event Dump", &true_value, &size, TID_BOOL, TRUE);
1916 db_get_value(hDB, 0, "/Experiment/Menu/Config", &true_value, &size, TID_BOOL, TRUE);
1917 db_get_value(hDB, 0, "/Experiment/Menu/Example", &false_value, &size, TID_BOOL, TRUE);
1918 db_get_value(hDB, 0, "/Experiment/Menu/Help", &true_value, &size, TID_BOOL, TRUE);
1919
1920 //std::string buf;
1921 //status = db_get_value_string(hDB, 0, "/Experiment/Menu buttons", 0, &buf, FALSE);
1922 //if (status == DB_SUCCESS) {
1923 // cm_msg(MERROR, "init_menu_buttons", "ODB \"/Experiment/Menu buttons\" is obsolete, please delete it.");
1924 //}
1925
1926 check_obsolete_odb(hDB, "/Experiment/Menu buttons");
1927 check_obsolete_odb(hDB, "/Experiment/Menu/OldSequencer");
1928 check_obsolete_odb(hDB, "/Experiment/Menu/NewSequencer");
1929}
1930
1931/*------------------------------------------------------------------*/
1932
1934{
1935 HNDLE hDB;
1936 HNDLE hKey;
1937 int status;
1938 std::string s;
1940
1941 status = db_find_key(hDB, 0, "/Experiment/Base URL", &hKey);
1942 if (status == DB_SUCCESS) {
1943 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Base URL\" is obsolete, please delete it.");
1944 }
1945
1946 status = db_find_key(hDB, 0, "/Experiment/CSS File", &hKey);
1947 if (status == DB_SUCCESS) {
1948 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/CSS File\" is obsolete, please delete it.");
1949 }
1950
1951 status = db_find_key(hDB, 0, "/Experiment/JS File", &hKey);
1952 if (status == DB_SUCCESS) {
1953 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/JS File\" is obsolete, please delete it.");
1954 }
1955
1956 status = db_find_key(hDB, 0, "/Experiment/Start-Stop Buttons", &hKey);
1957 if (status == DB_SUCCESS) {
1958 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Start-Stop Buttons\" is obsolete, please delete it.");
1959 }
1960
1961 bool xdefault = true;
1962 odb->RB("Experiment/Pause-Resume Buttons", &xdefault, true);
1963
1964#ifdef HAVE_MONGOOSE616
1965 check_obsolete_odb(hDB, "/Experiment/midas http port");
1966 check_obsolete_odb(hDB, "/Experiment/midas https port");
1967 check_obsolete_odb(hDB, "/Experiment/http redirect to https");
1968 check_obsolete_odb(hDB, "/Experiment/Security/mhttpd hosts");
1969#endif
1970
1971 status = db_find_key(hDB, 0, "/Logger/Message file", &hKey);
1972 if (status == DB_SUCCESS) {
1973 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Logger/Message file\" is obsolete, please delete it and use \"/Logger/Message dir\" and \"/Logger/message file date format\" instead.");
1974 }
1975
1976 check_obsolete_odb(hDB, "/Logger/Watchdog timeout");
1977}
1978
1979/*------------------------------------------------------------------*/
1980
1982{
1983 HNDLE hDB;
1984 int size;
1985 HNDLE hkey;
1987
1989 std::string external_elog_url;
1990
1991 size = sizeof(external_elog);
1992 db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
1993 db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
1994
1997 size = sizeof(BOOL);
1998 db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
1999 db_get_value(hDB, 0, "/Elog/Allow edit", &allow_edit, &size, TID_BOOL, TRUE);
2000 //db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL, TRUE);
2001
2002 if (db_find_key(hDB, 0, "/Elog/Buttons", &hkey) != DB_SUCCESS) {
2003 const char def_button[][NAME_LENGTH] = { "8h", "24h", "7d" };
2004 db_set_value(hDB, 0, "/Elog/Buttons", def_button, NAME_LENGTH*3, 3, TID_STRING);
2005 }
2006
2007
2008 /* get type list from ODB */
2009 size = 20 * NAME_LENGTH;
2010 if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS) {
2011 db_set_value(hDB, 0, "/Elog/Types", default_type_list, NAME_LENGTH * 20, 20, TID_STRING);
2012 }
2013
2014 /* get system list from ODB */
2015 size = 20 * NAME_LENGTH;
2016 if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
2017 db_set_value(hDB, 0, "/Elog/Systems", default_system_list, NAME_LENGTH * 20, 20, TID_STRING);
2018}
2019
2020/*------------------------------------------------------------------*/
2021
2022void strencode(Return* r, const char *text)
2023{
2024 size_t len = strlen(text);
2025 for (size_t i = 0; i < len; i++) {
2026 switch (text[i]) {
2027 case '\n':
2028 r->rsprintf("<br>\n");
2029 break;
2030 case '<':
2031 r->rsprintf("&lt;");
2032 break;
2033 case '>':
2034 r->rsprintf("&gt;");
2035 break;
2036 case '&':
2037 r->rsprintf("&amp;");
2038 break;
2039 case '\"':
2040 r->rsprintf("&quot;");
2041 break;
2042 default:
2043 r->rsprintf("%c", text[i]);
2044 }
2045 }
2046}
2047
2048/*------------------------------------------------------------------*/
2049
2050std::string strencode2(const char *text)
2051{
2052 std::string b;
2053 size_t len = strlen(text);
2054 for (size_t i = 0; i < len; i++) {
2055 switch (text[i]) {
2056 case '\n':
2057 b += "<br>\n";
2058 break;
2059 case '<':
2060 b += "&lt;";
2061 break;
2062 case '>':
2063 b += "&gt;";
2064 break;
2065 case '&':
2066 b += "&amp;";
2067 break;
2068 case '\"':
2069 b += "&quot;";
2070 break;
2071 default:
2072 b += text[i];
2073 break;
2074 }
2075 }
2076 return b;
2077}
2078
2079/*------------------------------------------------------------------*/
2080
2081void strencode3(Return* r, const char *text)
2082{
2083 size_t len = strlen(text);
2084 for (size_t i = 0; i < len; i++) {
2085 switch (text[i]) {
2086 case '<':
2087 r->rsprintf("&lt;");
2088 break;
2089 case '>':
2090 r->rsprintf("&gt;");
2091 break;
2092 case '&':
2093 r->rsprintf("&amp;");
2094 break;
2095 case '\"':
2096 r->rsprintf("&quot;");
2097 break;
2098 default:
2099 r->rsprintf("%c", text[i]);
2100 }
2101 }
2102}
2103
2104/*------------------------------------------------------------------*/
2105
2106void strencode4(Return* r, const char *text)
2107{
2108 size_t len = strlen(text);
2109 for (size_t i = 0; i < len; i++) {
2110 switch (text[i]) {
2111 case '\n':
2112 r->rsprintf("<br>\n");
2113 break;
2114 case '<':
2115 r->rsprintf("&lt;");
2116 break;
2117 case '>':
2118 r->rsprintf("&gt;");
2119 break;
2120 case '&':
2121 r->rsprintf("&amp;");
2122 break;
2123 case '\"':
2124 r->rsprintf("&quot;");
2125 break;
2126 case ' ':
2127 r->rsprintf("&nbsp;");
2128 break;
2129 default:
2130 r->rsprintf("%c", text[i]);
2131 }
2132 }
2133}
2134
2135/*------------------------------------------------------------------*/
2136
2137void gen_odb_attachment(Return* r, const char *path, std::string& bout)
2138{
2140 KEY key;
2141 INT i, j, size;
2142 char data[1024];
2143 time_t now;
2144
2146 db_find_key(hDB, 0, path, &hkeyroot);
2147 assert(hkeyroot);
2148
2149 /* title row */
2150 //size = sizeof(str);
2151 //str[0] = 0;
2152 //db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
2153 time(&now);
2154
2155 bout += "<table border=3 cellpadding=1 class=\"dialogTable\">\n";
2156 char ctimebuf[32];
2157 ctime_r(&now, ctimebuf);
2158 bout += msprintf("<tr><th colspan=2>%s</tr>\n", ctimebuf);
2159 bout += msprintf("<tr><th colspan=2>%s</tr>\n", path);
2160
2161 /* enumerate subkeys */
2162 for (i = 0;; i++) {
2164 if (!hkey)
2165 break;
2166 db_get_key(hDB, hkey, &key);
2167
2168 /* resolve links */
2169 if (key.type == TID_LINK) {
2171 db_get_key(hDB, hkey, &key);
2172 }
2173
2174 if (key.type == TID_KEY) {
2175 /* for keys, don't display data value */
2176 bout += msprintf("<tr><td colspan=2>%s</td></tr>\n", key.name);
2177 } else {
2178 /* display single value */
2179 if (key.num_values == 1) {
2180 size = sizeof(data);
2181 db_get_data(hDB, hkey, data, &size, key.type);
2182 //printf("data size %d [%s]\n", size, data);
2183 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2184 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2185
2186 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2187 data_str = "(empty)";
2188 hex_str = "";
2189 }
2190
2191 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2192 //sprintf(b, "<tr><td>%s</td><td>%s (%s)</td></tr>\n", key.name, data_str, hex_str);
2193 bout += "<tr><td>";
2194 bout += key.name;
2195 bout += "</td><td>";
2196 bout += data_str;
2197 bout += " (";
2198 bout += hex_str;
2199 bout += ")</td></tr>\n";
2200 } else {
2201 bout += msprintf("<tr><td>%s</td><td>", key.name);
2202 bout += strencode2(data_str.c_str());
2203 bout += "</td></tr>\n";
2204 }
2205 } else {
2206 /* display first value */
2207 bout += msprintf("<tr><td rowspan=%d>%s</td>\n", key.num_values, key.name);
2208
2209 for (j = 0; j < key.num_values; j++) {
2210 size = sizeof(data);
2211 db_get_data_index(hDB, hkey, data, &size, j, key.type);
2212 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2213 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2214
2215 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2216 data_str = "(empty)";
2217 hex_str = "";
2218 }
2219
2220 if (j > 0) {
2221 bout += "<tr>";
2222 }
2223
2224 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2225 //sprintf(b, "<td>[%d] %s (%s)<br></td></tr>\n", j, data_str, hex_str);
2226 bout += "<td>[";
2227 bout += toString(j);
2228 bout += "] ";
2229 bout += data_str;
2230 bout += " (";
2231 bout += hex_str;
2232 bout += ")<br></td></tr>\n";
2233 } else {
2234 //sprintf(b, "<td>[%d] %s<br></td></tr>\n", j, data_str);
2235 bout += "<td>[";
2236 bout += toString(j);
2237 bout += "] ";
2238 bout += data_str;
2239 bout += "<br></td></tr>\n";
2240 }
2241 }
2242 }
2243 }
2244 }
2245
2246 bout += "</table>\n";
2247}
2248
2249/*------------------------------------------------------------------*/
2250
2252{
2253 char path[256], path1[256];
2254 char mail_to[256], mail_from[256], mail_list[256],
2255 smtp_host[256], tag[80], mail_param[1000];
2256 char *p, *pitem;
2257 HNDLE hDB, hkey;
2258 char att_file[3][256];
2259 int fh, size, n_mail;
2260 char mhttpd_full_url[256];
2261
2263 mstrlcpy(att_file[0], pp->getparam("attachment0"), sizeof(att_file[0]));
2264 mstrlcpy(att_file[1], pp->getparam("attachment1"), sizeof(att_file[1]));
2265 mstrlcpy(att_file[2], pp->getparam("attachment2"), sizeof(att_file[2]));
2266
2267 /* check for valid attachment files */
2268 for (int i = 0; i < 3; i++) {
2269 char str[256];
2270 sprintf(str, "attachment%d", i);
2271 //printf("submit_elog: att %d, [%s] param [%s], size %d\n", i, str, pp->getparam(str), a->_attachment_size[i]);
2272 if (pp->getparam(str) && *pp->getparam(str) && a->attachment_size[i] == 0) {
2273 /* replace '\' by '/' */
2274 mstrlcpy(path, pp->getparam(str), sizeof(path));
2275 mstrlcpy(path1, path, sizeof(path1));
2276 while (strchr(path, '\\'))
2277 *strchr(path, '\\') = '/';
2278
2279 /* check if valid ODB tree */
2280 if (db_find_key(hDB, 0, path, &hkey) == DB_SUCCESS) {
2281 std::string bout;
2282 gen_odb_attachment(r, path, bout);
2283 int bufsize = bout.length()+1;
2284 char* buf = (char*)M_MALLOC(bufsize);
2285 memcpy(buf, bout.c_str(), bufsize);
2286 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2287 mstrlcat(att_file[i], ".html", sizeof(att_file[0]));
2288 a->attachment_buffer[i] = buf;
2290 }
2291 /* check if local file */
2292 else if ((fh = open(path1, O_RDONLY | O_BINARY)) >= 0) {
2293 size = lseek(fh, 0, SEEK_END);
2294 char* buf = (char*)M_MALLOC(size);
2295 lseek(fh, 0, SEEK_SET);
2296 int rd = read(fh, buf, size);
2297 if (rd < 0)
2298 rd = 0;
2299 close(fh);
2300 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2301 a->attachment_buffer[i] = buf;
2302 a->attachment_size[i] = rd;
2303 } else if (strncmp(path, "/HS/", 4) == 0) {
2304 char* buf = (char*)M_MALLOC(100000);
2305 size = 100000;
2306 mstrlcpy(str, path + 4, sizeof(str));
2307 if (strchr(str, '?')) {
2308 p = strchr(str, '?') + 1;
2309 p = strtok(p, "&");
2310 while (p != NULL) {
2311 pitem = p;
2312 p = strchr(p, '=');
2313 if (p != NULL) {
2314 *p++ = 0;
2315 urlDecode(pitem); // parameter name
2316 urlDecode(p); // parameter value
2317
2318 pp->setparam(pitem, p);
2319
2320 p = strtok(NULL, "&");
2321 }
2322 }
2323 *strchr(str, '?') = 0;
2324 }
2325 show_hist_page(odb, pp, r, "image.gif", buf, &size, 0);
2326 mstrlcpy(att_file[i], str, sizeof(att_file[0]));
2327 a->attachment_buffer[i] = buf;
2328 a->attachment_size[i] = size;
2329 pp->unsetparam("scale");
2330 pp->unsetparam("offset");
2331 pp->unsetparam("width");
2332 pp->unsetparam("index");
2333 } else {
2334 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2335 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2336 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
2337
2338 r->rsprintf("<html><head>\n");
2339 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
2340 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
2341 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
2342 r->rsprintf("<title>ELog Error</title></head>\n");
2343 r->rsprintf("<i>Error: Attachment file <i>%s</i> not valid.</i><p>\n", pp->getparam(str));
2344 r->rsprintf("Please go back and enter a proper filename (use the <b>Browse</b> button).\n");
2345 r->rsprintf("<body></body></html>\n");
2346 return;
2347 }
2348 }
2349 }
2350
2351 int edit = atoi(pp->getparam("edit"));
2352 //printf("submit_elog: edit [%s] %d, orig [%s]\n", pp->getparam("edit"), edit, pp->getparam("orig"));
2353
2354 tag[0] = 0;
2355 if (edit) {
2356 mstrlcpy(tag, pp->getparam("orig"), sizeof(tag));
2357 }
2358
2359 int status = el_submit(atoi(pp->getparam("run")),
2360 pp->getparam("author"),
2361 pp->getparam("type"),
2362 pp->getparam("system"),
2363 pp->getparam("subject"),
2364 pp->getparam("text"),
2365 pp->getparam("orig"),
2366 *pp->getparam("html") ? "HTML" : "plain",
2370 tag, sizeof(tag));
2371
2372 //printf("el_submit status %d, tag [%s]\n", status, tag);
2373
2374 if (status != EL_SUCCESS) {
2375 cm_msg(MERROR, "submit_elog", "el_submit() returned status %d", status);
2376 }
2377
2378 /* supersede host name with "/Elog/Host name" */
2379 std::string elog_host_name;
2380 db_get_value_string(hDB, 0, "/Elog/Host name", 0, &elog_host_name, TRUE);
2381
2382 // K.O. FIXME: we cannot guess the Elog URL like this because
2383 // we do not know if access is through a proxy or redirect
2384 // we do not know if it's http: or https:, etc. Better
2385 // to read the whole "mhttpd_full_url" string from ODB.
2386 sprintf(mhttpd_full_url, "http://%s/", elog_host_name.c_str());
2387
2388 /* check for mail submissions */
2389 mail_param[0] = 0;
2390 n_mail = 0;
2391
2392 for (int index = 0; index <= 1; index++) {
2393 std::string str;
2394 str += "/Elog/Email ";
2395 if (index == 0)
2396 str += pp->getparam("type");
2397 else
2398 str += pp->getparam("system");
2399
2400 if (db_find_key(hDB, 0, str.c_str(), &hkey) == DB_SUCCESS) {
2401 size = sizeof(mail_list);
2403
2404 if (db_find_key(hDB, 0, "/Elog/SMTP host", &hkey) != DB_SUCCESS) {
2405 show_error(r, "No SMTP host defined under /Elog/SMTP host");
2406 return;
2407 }
2408 size = sizeof(smtp_host);
2410
2411 p = strtok(mail_list, ",");
2412 while (1) {
2413 mstrlcpy(mail_to, p, sizeof(mail_to));
2414
2415 std::string exptname;
2416 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
2417
2418 sprintf(mail_from, "MIDAS %s <MIDAS@%s>", exptname.c_str(), elog_host_name.c_str());
2419
2420 std::string mail_text;
2421 mail_text += "A new entry has been submitted by ";
2422 mail_text += pp->getparam("author");
2423 mail_text += "\n";
2424 mail_text += "\n";
2425
2426 mail_text += "Experiment : ";
2427 mail_text += exptname.c_str();
2428 mail_text += "\n";
2429
2430 mail_text += "Type : ";
2431 mail_text += pp->getparam("type");
2432 mail_text += "\n";
2433
2434 mail_text += "System : ";
2435 mail_text += pp->getparam("system");
2436 mail_text += "\n";
2437
2438 mail_text += "Subject : ";
2439 mail_text += pp->getparam("subject");
2440 mail_text += "\n";
2441
2442 mail_text += "Link : ";
2444 mail_text += "/EL/";
2445 mail_text += tag;
2446 mail_text += "\n";
2447
2448 mail_text += "\n";
2449
2450 mail_text += pp->getparam("text");
2451 mail_text += "\n";
2452
2453 sendmail(elog_host_name.c_str(), smtp_host, mail_from, mail_to, pp->getparam("type"), mail_text.c_str());
2454
2455 if (mail_param[0] == 0)
2456 mstrlcpy(mail_param, "?", sizeof(mail_param));
2457 else
2458 mstrlcat(mail_param, "&", sizeof(mail_param));
2459 sprintf(mail_param + strlen(mail_param), "mail%d=%s", n_mail++, mail_to);
2460
2461 p = strtok(NULL, ",");
2462 if (!p)
2463 break;
2464 while (*p == ' ')
2465 p++;
2466 }
2467 }
2468 }
2469
2470 r->rsprintf("HTTP/1.1 302 Found\r\n");
2471 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2472
2473 //if (mail_param[0])
2474 // r->rsprintf("Location: ../EL/%s?%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2475 //else
2476 // r->rsprintf("Location: ../EL/%s\n\n<html>redir</html>\r\n", tag);
2477
2478 if (mail_param[0])
2479 r->rsprintf("Location: ?cmd=Show+elog&tag=%s&%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2480 else
2481 r->rsprintf("Location: ?cmd=Show+elog&tag=%s\n\n<html>redir</html>\r\n", tag);
2482}
2483
2484/*------------------------------------------------------------------*/
2485
2486void show_elog_attachment(Param* p, Return* r, const char* path)
2487{
2488 HNDLE hDB;
2489 int size;
2490 int status;
2491 char file_name[256];
2492
2494 file_name[0] = 0;
2495 if (hDB > 0) {
2496 size = sizeof(file_name);
2497 memset(file_name, 0, size);
2498
2499 status = db_get_value(hDB, 0, "/Logger/Elog dir", file_name, &size, TID_STRING, FALSE);
2500 if (status != DB_SUCCESS)
2501 db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
2502
2503 if (file_name[0] != 0)
2506 }
2507 mstrlcat(file_name, path, sizeof(file_name));
2508
2509 int fh = open(file_name, O_RDONLY | O_BINARY);
2510 if (fh > 0) {
2511 lseek(fh, 0, SEEK_END);
2512 int length = TELL(fh);
2513 lseek(fh, 0, SEEK_SET);
2514
2515 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2516 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2517 r->rsprintf("Accept-Ranges: bytes\r\n");
2518 //r->rsprintf("Content-disposition: attachment; filename=%s\r\n", path);
2519
2520 r->rsprintf("Content-Type: %s\r\n", get_content_type(file_name).c_str());
2521
2522 r->rsprintf("Content-Length: %d\r\n\r\n", length);
2523
2524 r->rread(file_name, fh, length);
2525
2526 close(fh);
2527 }
2528
2529 return;
2530}
2531
2532/*------------------------------------------------------------------*/
2533
2535{
2536 HNDLE hDB, hkey;
2537 KEY key;
2538 char str[256];
2539 int i, size;
2540
2542 sprintf(str, "/Equipment/%s/Settings/Editable", eq_name);
2543 db_find_key(hDB, 0, str, &hkey);
2544
2545 /* if no editable entry found, use default */
2546 if (!hkey) {
2547 return (equal_ustring(var_name, "Demand") ||
2548 equal_ustring(var_name, "Output") || strncmp(var_name, "D_", 2) == 0);
2549 }
2550
2551 db_get_key(hDB, hkey, &key);
2552 for (i = 0; i < key.num_values; i++) {
2553 size = sizeof(str);
2556 return TRUE;
2557 }
2558 return FALSE;
2559}
2560
2561#ifdef OBSOLETE
2562void show_eqtable_page(Param* pp, Return* r, int refresh)
2563{
2564 int i, j, k, colspan, size, n_var, i_edit, i_set, line;
2565 char eq_name[32], group[32];
2566 char group_name[MAX_GROUPS][32], data[256], style[80];
2567 HNDLE hDB;
2568 char odb_path[256];
2569
2571
2572 /* check if variable to edit */
2573 i_edit = -1;
2574 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2575 i_edit = atoi(pp->getparam("index"));
2576
2577 /* check if variable to set */
2578 i_set = -1;
2579 if (equal_ustring(pp->getparam("cmd"), "Set"))
2580 i_set = atoi(pp->getparam("index"));
2581
2582 /* get equipment and group */
2583 if (pp->getparam("eq"))
2584 mstrlcpy(eq_name, pp->getparam("eq"), sizeof(eq_name));
2585 mstrlcpy(group, "All", sizeof(group));
2586 if (pp->getparam("group") && *pp->getparam("group"))
2587 mstrlcpy(group, pp->getparam("group"), sizeof(group));
2588
2589#if 0
2590 /* check for "names" in settings */
2591 if (eq_name[0]) {
2592 sprintf(str, "/Equipment/%s/Settings", eq_name);
2593 HNDLE hkeyset;
2594 db_find_key(hDB, 0, str, &hkeyset);
2595 HNDLE hkeynames = 0;
2596 if (hkeyset) {
2597 for (i = 0;; i++) {
2599
2600 if (!hkeynames)
2601 break;
2602
2603 KEY key;
2605
2606 if (strncmp(key.name, "Names", 5) == 0)
2607 break;
2608 }
2609 }
2610
2611 /* redirect if no names found */
2612 if (!hkeyset || !hkeynames) {
2613 /* redirect */
2614 sprintf(str, "?cmd=odb&odb_path=/Equipment/%s/Variables", eq_name);
2615 redirect(r, str);
2616 return;
2617 }
2618 }
2619#endif
2620
2621 show_header(r, "MIDAS slow control", "", group, i_edit == -1 ? refresh : 0);
2622 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
2623 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
2624 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
2625 show_navigation_bar(r, "SC");
2626
2627 /*---- menu buttons ----*/
2628
2629 r->rsprintf("<tr><td colspan=15>\n");
2630
2631 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2632 r->rsprintf("<input type=submit name=cmd value=Set>\n");
2633
2634 r->rsprintf("</tr>\n\n");
2635 r->rsprintf("</table>"); //end header table
2636
2637 r->rsprintf("<table class=\"ODBtable\" style=\"max-width:700px;\">"); //body table
2638
2639 /*---- enumerate SC equipment ----*/
2640
2641 r->rsprintf("<tr><td class=\"subStatusTitle\" colspan=15><i>Equipment:</i> &nbsp;&nbsp;\n");
2642
2644 db_find_key(hDB, 0, "/Equipment", &hkeyeqroot);
2645 if (hkeyeqroot)
2646 for (i = 0;; i++) {
2647 HNDLE hkeyeq;
2649
2650 if (!hkeyeq)
2651 break;
2652
2653 KEY eqkey;
2655
2656 HNDLE hkeyset;
2657 db_find_key(hDB, hkeyeq, "Settings", &hkeyset);
2658 if (hkeyset) {
2659 for (j = 0;; j++) {
2662
2663 if (!hkeynames)
2664 break;
2665
2666 KEY key;
2668
2669 if (strncmp(key.name, "Names", 5) == 0) {
2670 if (equal_ustring(eq_name, eqkey.name))
2671 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", eqkey.name);
2672 else {
2673 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">%s</a> &nbsp;&nbsp;", urlEncode(eqkey.name).c_str(), eqkey.name);
2674 }
2675 break;
2676 }
2677 }
2678 }
2679 }
2680 r->rsprintf("</tr>\n");
2681
2682 if (!eq_name[0]) {
2683 r->rsprintf("</table>");
2684 return;
2685 }
2686
2687 /*---- display SC ----*/
2688
2689 n_var = 0;
2690 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2692 db_find_key(hDB, 0, names_path.c_str(), &hkeyeqnames);
2693
2694 if (hkeyeqnames) {
2695
2696 /*---- single name array ----*/
2697 r->rsprintf("<tr><td colspan=15><i>Groups:</i> &nbsp;&nbsp;");
2698
2699 /* "all" group */
2700 if (equal_ustring(group, "All"))
2701 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2702 else
2703 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2704
2705 /* collect groups */
2706
2707 memset(group_name, 0, sizeof(group_name));
2708 KEY key;
2710
2711 for (int level = 0; ; level++) {
2712 bool next_level = false;
2713 for (i = 0; i < key.num_values; i++) {
2714 char name_str[256];
2715 size = sizeof(name_str);
2717
2718 char *s = strchr(name_str, '%');
2719 for (int k=0; s && k<level; k++)
2720 s = strchr(s+1, '%');
2721
2722 if (s) {
2723 *s = 0;
2724 if (strchr(s+1, '%'))
2725 next_level = true;
2726
2727 //printf("try group [%s] name [%s], level %d, %d\n", name_str, s+1, level, next_level);
2728
2729 for (j = 0; j < MAX_GROUPS; j++) {
2730 if (equal_ustring(group_name[j], name_str) || group_name[j][0] == 0)
2731 break;
2732 }
2733 if ((j < MAX_GROUPS) && (group_name[j][0] == 0))
2734 mstrlcpy(group_name[j], name_str, sizeof(group_name[0]));
2735 }
2736 }
2737
2738 if (!next_level)
2739 break;
2740 }
2741
2742 for (i = 0; i < MAX_GROUPS && group_name[i][0]; i++) {
2744 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", group_name[i]);
2745 else {
2746 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]);
2747 }
2748 }
2749
2750 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2751 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2752 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2753 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2754 r->rsprintf("</tr>\n");
2755
2756 /* count variables */
2757 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2758 HNDLE hkeyvar;
2759 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2760 if (!hkeyvar) {
2761 r->rsprintf("</table>");
2762 return;
2763 }
2764 for (i = 0;; i++) {
2765 HNDLE hkey;
2767 if (!hkey)
2768 break;
2769 }
2770
2771 if (i == 0 || i > 15) {
2772 r->rsprintf("</table>");
2773 return;
2774 }
2775
2776 /* title row */
2777 colspan = 15 - i;
2778 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=%d>Names", colspan);
2779
2780 /* display entries for this group */
2781 for (int i = 0;; i++) {
2782 HNDLE hkey;
2784
2785 if (!hkey)
2786 break;
2787
2788 KEY key;
2789 db_get_key(hDB, hkey, &key);
2790 r->rsprintf("<th>%s", key.name);
2791 }
2792
2793 r->rsprintf("</tr>\n");
2794
2795 /* data for current group */
2796 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2797 int num_values = 0;
2799 db_find_key(hDB, 0, names_path.c_str(), &hnames_key);
2800 if (hnames_key) {
2801 KEY names_key;
2803 num_values = names_key.num_values;
2804 }
2805 for (int i = 0; i < num_values; i++) {
2806 char names_str[256];
2807 size = sizeof(names_str);
2809
2810 char name[NAME_LENGTH+32];
2811 mstrlcpy(name, names_str, sizeof(name));
2812
2813 //printf("group [%s], name [%s], str [%s]\n", group, name, names_str);
2814
2815 if (!equal_ustring(group, "All")) {
2816 // check if name starts with the name of the group we want to display
2817 char *s = strstr(name, group);
2818 if (s != name)
2819 continue;
2820 if (name[strlen(group)] != '%')
2821 continue;
2822 }
2823
2824 if (strlen(name) < 1)
2825 sprintf(name, "[%d]", i);
2826
2827 if (i % 2 == 0)
2828 r->rsprintf("<tr class=\"ODBtableEven\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2829 else
2830 r->rsprintf("<tr class=\"ODBtableOdd\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2831
2832 for (int j = 0;; j++) {
2833 HNDLE hkey;
2835 if (!hkey)
2836 break;
2837
2838 KEY varkey;
2840
2841 /* check if "variables" array is shorter than the "names" array */
2842 if (i >= varkey.num_values)
2843 continue;
2844
2845 size = sizeof(data);
2846 db_get_data_index(hDB, hkey, data, &size, i, varkey.type);
2847 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
2848
2849 if (is_editable(eq_name, varkey.name)) {
2850 if (n_var == i_set) {
2851 /* set value */
2852 char str[256];
2853 mstrlcpy(str, pp->getparam("value"), sizeof(str));
2854 db_sscanf(str, data, &size, 0, varkey.type);
2855 db_set_data_index(hDB, hkey, data, size, i, varkey.type);
2856
2857 /* redirect (so that 'reload' does not reset value) */
2858 r->reset();
2859 redirect(r, group);
2860 return;
2861 }
2862 if (n_var == i_edit) {
2863 r->rsprintf("<td align=center>");
2864 r->rsprintf("<input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
2865 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
2866 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
2867 n_var++;
2868 } else {
2869 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, i);
2870 r->rsprintf("<td align=center>");
2871 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
2872 n_var++;
2873 }
2874 } else
2875 r->rsprintf("<td align=center>%s", data_str.c_str());
2876 }
2877
2878 r->rsprintf("</tr>\n");
2879 }
2880 } else {
2881 /*---- multiple name arrays ----*/
2882 r->rsprintf("<tr><td colspan=15><i>Groups:</i> ");
2883
2884 /* "all" group */
2885 if (equal_ustring(group, "All"))
2886 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2887 else
2888 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", eq_name);
2889
2890 /* groups from Variables tree */
2891
2892 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2893 HNDLE hkeyvar;
2894 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2895
2896 if (hkeyvar) {
2897 for (int i = 0;; i++) {
2898 HNDLE hkey;
2900
2901 if (!hkey)
2902 break;
2903
2904 KEY key;
2905 db_get_key(hDB, hkey, &key);
2906
2907 if (equal_ustring(key.name, group)) {
2908 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", key.name);
2909 } else {
2910 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);
2911 }
2912 }
2913 }
2914
2915 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2916 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2917 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2918 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2919 r->rsprintf("</tr>\n");
2920
2921 /* enumerate variable arrays */
2922 line = 0;
2923 for (i = 0;; i++) {
2924 HNDLE hkey;
2926
2927 if (line % 2 == 0)
2928 mstrlcpy(style, "ODBtableEven", sizeof(style));
2929 else
2930 mstrlcpy(style, "ODBtableOdd", sizeof(style));
2931
2932 if (!hkey)
2933 break;
2934
2935 KEY varkey;
2937
2938 if (!equal_ustring(group, "All") && !equal_ustring(varkey.name, group))
2939 continue;
2940
2941 /* title row */
2942 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=9>Names<th>%s</tr>\n", varkey.name);
2943
2944 if (varkey.type == TID_KEY) {
2946
2947 /* enumerate subkeys */
2948 for (j = 0;; j++) {
2950 if (!hkey)
2951 break;
2952
2953 KEY key;
2954 db_get_key(hDB, hkey, &key);
2955
2956 if (key.type == TID_KEY) {
2957 /* for keys, don't display data value */
2958 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<br></tr>\n", style, key.name);
2959 } else {
2960 /* display single value */
2961 if (key.num_values == 1) {
2962 size = sizeof(data);
2963 db_get_data(hDB, hkey, data, &size, key.type);
2964
2965 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2966 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2967
2968 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2969 data_str = "(empty)";
2970 hex_str = "";
2971 }
2972
2973 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
2974 r->rsprintf
2975 ("<tr class=\"%s\" ><td colspan=9>%s<td align=center>%s (%s)<br></tr>\n",
2976 style, key.name, data_str.c_str(), hex_str.c_str());
2977 else
2978 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center>%s<br></tr>\n",
2979 style, key.name, data_str.c_str());
2980 line++;
2981 } else {
2982 /* display first value */
2983 r->rsprintf("<tr class=\"%s\"><td colspan=9 rowspan=%d>%s\n", style, key.num_values,
2984 key.name);
2985
2986 for (k = 0; k < key.num_values; k++) {
2987 size = sizeof(data);
2988 db_get_data_index(hDB, hkey, data, &size, k, key.type);
2989 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2990 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2991
2992 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2993 data_str = "(empty)";
2994 hex_str = "";
2995 }
2996
2997 if (k > 0)
2998 r->rsprintf("<tr>");
2999
3000 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
3001 r->rsprintf("<td>[%d] %s (%s)<br></tr>\n", k, data_str.c_str(), hex_str.c_str());
3002 else
3003 r->rsprintf("<td>[%d] %s<br></tr>\n", k, data_str.c_str());
3004 line++;
3005 }
3006 }
3007 }
3008 }
3009 } else {
3010 /* data for current group */
3011 std::string names_path = msprintf("/Equipment/%s/Settings/Names %s", eq_name, varkey.name);
3012 HNDLE hkeyset;
3013 db_find_key(hDB, 0, names_path.c_str(), &hkeyset);
3014 KEY key;
3015 if (hkeyset)
3017
3018 if (varkey.num_values > 1000)
3019 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center><i>... %d values ...</i>",
3020 style, varkey.name, varkey.num_values);
3021 else {
3022 for (j = 0; j < varkey.num_values; j++) {
3023
3024 if (line % 2 == 0)
3025 mstrlcpy(style, "ODBtableEven", sizeof(style));
3026 else
3027 mstrlcpy(style, "ODBtableOdd", sizeof(style));
3028
3029 char name[NAME_LENGTH+32];
3030 if (hkeyset && j<key.num_values) {
3031 size = sizeof(name);
3033 } else {
3034 sprintf(name, "%s[%d]", varkey.name, j);
3035 }
3036
3037 if (strlen(name) < 1) {
3038 sprintf(name, "%s[%d]", varkey.name, j);
3039 }
3040
3041 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s", style, name);
3042
3043 size = sizeof(data);
3044 db_get_data_index(hDB, hkey, data, &size, j, varkey.type);
3045 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
3046
3047 if (is_editable(eq_name, varkey.name)) {
3048 if (n_var == i_set) {
3049 /* set value */
3050 char str[256];
3051 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3052 db_sscanf(str, data, &size, 0, varkey.type);
3053 db_set_data_index(hDB, hkey, data, size, j, varkey.type);
3054
3055 /* redirect (so that 'reload' does not reset value) */
3056 r->reset();
3057 sprintf(str, "%s", group);
3058 redirect(r, str);
3059 return;
3060 }
3061 if (n_var == i_edit) {
3062 r->rsprintf("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
3063 r->rsprintf("<input type=submit size=20 name=cmd value=Set></tr>\n");
3064 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
3065 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3066 n_var++;
3067 } else {
3068 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, j);
3069
3070 r->rsprintf("<td align=cernter>");
3071 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
3072 n_var++;
3073 }
3074
3075 } else
3076 r->rsprintf("<td align=center>%s\n", data_str.c_str());
3077 r->rsprintf("</tr>\n");
3078 line++;
3079 }
3080 }
3081
3082 r->rsprintf("</tr>\n");
3083 }
3084 }
3085 }
3086
3087 r->rsprintf("</table>\n");
3088 r->rsprintf("</div>\n"); // closing for <div id="mmain">
3089 r->rsprintf("</form>\n");
3090 r->rsprintf("</body></html>\r\n");
3091}
3092#endif
3093
3094/*------------------------------------------------------------------*/
3095
3096char *find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
3097{
3098 char str[256], *ps, *pt;
3100
3101 *edit = 0;
3102 *tail = 0;
3103 *format = 0;
3104 pwd[0] = 0;
3105 in_script = FALSE;
3106 strcpy(type, "text");
3107 do {
3108 while (*p && *p != '<')
3109 p++;
3110
3111 /* return if end of string reached */
3112 if (!*p)
3113 return NULL;
3114
3115 p++;
3116 while (*p && ((*p == ' ') || iscntrl(*p)))
3117 p++;
3118
3119 strncpy(str, p, 6);
3120 str[6] = 0;
3121 if (equal_ustring(str, "script"))
3122 in_script = TRUE;
3123
3124 strncpy(str, p, 7);
3125 str[7] = 0;
3126 if (equal_ustring(str, "/script"))
3127 in_script = FALSE;
3128
3129 strncpy(str, p, 4);
3130 str[4] = 0;
3131 if (equal_ustring(str, "odb ")) {
3132 ps = p - 1;
3133 p += 4;
3134 while (*p && ((*p == ' ') || iscntrl(*p)))
3135 p++;
3136
3137 do {
3138 strncpy(str, p, 7);
3139 str[7] = 0;
3140 if (equal_ustring(str, "format=")) {
3141 p += 7;
3142 if (*p == '\"') {
3143 p++;
3144 while (*p && *p != '\"')
3145 *format++ = *p++;
3146 *format = 0;
3147 if (*p == '\"')
3148 p++;
3149 } else {
3150 while (*p && *p != ' ' && *p != '>')
3151 *format++ = *p++;
3152 *format = 0;
3153 }
3154
3155 } else {
3156
3157 strncpy(str, p, 4);
3158 str[4] = 0;
3159 if (equal_ustring(str, "src=")) {
3160 p += 4;
3161 if (*p == '\"') {
3162 p++;
3163 while (*p && *p != '\"')
3164 *path++ = *p++;
3165 *path = 0;
3166 if (*p == '\"')
3167 p++;
3168 } else {
3169 while (*p && *p != ' ' && *p != '>')
3170 *path++ = *p++;
3171 *path = 0;
3172 }
3173 } else {
3174
3175 if (in_script)
3176 break;
3177
3178 strncpy(str, p, 5);
3179 str[5] = 0;
3180 if (equal_ustring(str, "edit=")) {
3181 p += 5;
3182
3183 if (*p == '\"') {
3184 p++;
3185 *edit = atoi(p);
3186 if (*p == '\"')
3187 p++;
3188 } else {
3189 *edit = atoi(p);
3190 while (*p && *p != ' ' && *p != '>')
3191 p++;
3192 }
3193
3194 } else {
3195
3196 strncpy(str, p, 5);
3197 str[5] = 0;
3198 if (equal_ustring(str, "type=")) {
3199 p += 5;
3200 if (*p == '\"') {
3201 p++;
3202 while (*p && *p != '\"')
3203 *type++ = *p++;
3204 *type = 0;
3205 if (*p == '\"')
3206 p++;
3207 } else {
3208 while (*p && *p != ' ' && *p != '>')
3209 *type++ = *p++;
3210 *type = 0;
3211 }
3212 } else {
3213 strncpy(str, p, 4);
3214 str[4] = 0;
3215 if (equal_ustring(str, "pwd=")) {
3216 p += 4;
3217 if (*p == '\"') {
3218 p++;
3219 while (*p && *p != '\"')
3220 *pwd++ = *p++;
3221 *pwd = 0;
3222 if (*p == '\"')
3223 p++;
3224 } else {
3225 while (*p && *p != ' ' && *p != '>')
3226 *pwd++ = *p++;
3227 *pwd = 0;
3228 }
3229 } else {
3230 if (strchr(p, '=')) {
3231 mstrlcpy(str, p, sizeof(str));
3232 pt = strchr(str, '=')+1;
3233 if (*pt == '\"') {
3234 pt++;
3235 while (*pt && *pt != '\"')
3236 pt++;
3237 if (*pt == '\"')
3238 pt++;
3239 *pt = 0;
3240 } else {
3241 while (*pt && *pt != ' ' && *pt != '>')
3242 pt++;
3243 *pt = 0;
3244 }
3245 if (tail[0]) {
3246 mstrlcat(tail, " ", 256);
3247 mstrlcat(tail, str, 256);
3248 } else {
3249 mstrlcat(tail, str, 256);
3250 }
3251 p += strlen(str);
3252 }
3253 }
3254 }
3255 }
3256 }
3257 }
3258
3259 while (*p && ((*p == ' ') || iscntrl(*p)))
3260 p++;
3261
3262 if (*p == '<') {
3263 cm_msg(MERROR, "find_odb_tag", "Invalid odb tag '%s'", ps);
3264 return NULL;
3265 }
3266 } while (*p != '>');
3267
3268 return ps;
3269 }
3270
3271 while (*p && *p != '>')
3272 p++;
3273
3274 } while (1);
3275
3276}
3277
3278/*------------------------------------------------------------------*/
3279
3280void show_odb_tag(Param* pp, Return* r, const char *path, const char *keypath1, const char *format, int n_var, int edit, char *type, char *pwd, char *tail)
3281{
3282 int size, index, i_edit, i_set;
3283 char data[TEXT_SIZE], full_keypath[256], keypath[256], *p;
3284 HNDLE hDB, hkey;
3285 KEY key;
3286
3287 /* check if variable to edit */
3288 i_edit = -1;
3289 if (equal_ustring(pp->getparam("cmd"), "Edit"))
3290 i_edit = atoi(pp->getparam("index"));
3291
3292 /* check if variable to set */
3293 i_set = -1;
3294 if (equal_ustring(pp->getparam("cmd"), "Set"))
3295 i_set = atoi(pp->getparam("index"));
3296
3297 /* check if path contains index */
3299 mstrlcpy(keypath, keypath1, sizeof(keypath));
3300 index = 0;
3301
3302 if (strchr(keypath, '[') && strchr(keypath, ']')) {
3303 for (p = strchr(keypath, '[') + 1; *p && *p != ']'; p++)
3304 if (!isdigit(*p))
3305 break;
3306
3307 if (*p && *p == ']') {
3308 index = atoi(strchr(keypath, '[') + 1);
3309 *strchr(keypath, '[') = 0;
3310 }
3311 }
3312
3314 db_find_key(hDB, 0, keypath, &hkey);
3315 if (!hkey)
3316 r->rsprintf("<b>Key \"%s\" not found in ODB</b>\n", keypath);
3317 else {
3318 db_get_key(hDB, hkey, &key);
3319 size = sizeof(data);
3321
3322 std::string data_str;
3323 if (format && strlen(format)>0)
3324 data_str = db_sprintff(format, data, key.item_size, 0, key.type);
3325 else
3327
3328 if (equal_ustring(type, "checkbox")) {
3329
3330 if (pp->isparam("cbi"))
3331 i_set = atoi(pp->getparam("cbi"));
3332 if (n_var == i_set) {
3333 /* toggle state */
3334 if (key.type == TID_BOOL) {
3335 if (data_str[0] == 'y')
3336 data_str = "n";
3337 else
3338 data_str = "y";
3339 } else {
3340 if (atoi(data_str.c_str()) > 0)
3341 data_str = "0";
3342 else
3343 data_str = "1";
3344 }
3345
3346 db_sscanf(data_str.c_str(), data, &size, 0, key.type);
3348 }
3349
3350 std::string options;
3351 if (data_str[0] == 'y' || atoi(data_str.c_str()) > 0)
3352 options += "checked ";
3353 if (!edit)
3354 options += "disabled ";
3355 else {
3356 if (edit == 1) {
3357 options += "onClick=\"o=document.createElement('input');o.type='hidden';o.name='cbi';o.value='";
3358 options += msprintf("%d", n_var);
3359 options += "';document.form1.appendChild(o);";
3360 options += "document.form1.submit();\" ";
3361 }
3362 }
3363
3364 if (tail[0])
3365 options += tail;
3366
3367 r->rsprintf("<input type=\"checkbox\" %s>\n", options.c_str());
3368
3369 } else { // checkbox
3370
3371 if (edit == 1) {
3372 if (n_var == i_set) {
3373 /* set value */
3374 char str[256];
3375 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3376 db_sscanf(str, data, &size, 0, key.type);
3378
3379 /* read back value */
3380 size = sizeof(data);
3383 }
3384
3385 if (n_var == i_edit) {
3386 r->rsprintf("<input type=text size=10 maxlength=80 name=value value=\"%s\">\n", data_str.c_str());
3387 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
3388 r->rsprintf("<input type=hidden name=index value=%d>\n", n_var);
3389 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3390 } else {
3391 if (edit == 2) {
3392 /* edit handling through user supplied JavaScript */
3393 r->rsprintf("<a href=\"#\" %s>", tail);
3394 } else {
3395 /* edit handling through form submission */
3396 if (pwd[0]) {
3397 r->rsprintf("<a onClick=\"promptpwd('%s?cmd=Edit&index=%d&pnam=%s')\" href=\"#\">", path, n_var, pwd);
3398 } else {
3399 r->rsprintf("<a href=\"%s?cmd=Edit&index=%d\" %s>", path, n_var, tail);
3400 }
3401 }
3402
3403 r->rsputs(data_str.c_str());
3404 r->rsprintf("</a>");
3405 }
3406 } else if (edit == 2) {
3407 r->rsprintf("<a href=\"#\" onclick=\"ODBEdit('%s')\">\n", full_keypath);
3408 r->rsputs(data_str.c_str());
3409 r->rsprintf("</a>");
3410 }
3411 else
3412 r->rsputs(data_str.c_str());
3413 }
3414 }
3415}
3416
3417/*------------------------------------------------------------------*/
3418
3419/* add labels using following syntax under /Custom/Images/<name.gif>/Labels/<name>:
3420
3421 [Name] [Description] [Example]
3422
3423 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3424 Format Formt for float/double %1.2f Deg. C
3425 Font Font to use small | medium | giant
3426 X X-position in pixel 90
3427 Y Y-position from top 67
3428 Align horizontal align left/center/right left
3429 FGColor Foreground color RRGGBB 000000
3430 BGColor Background color RRGGBB FFFFFF
3431*/
3432
3433static const char *cgif_label_str[] = {
3434 "Src = STRING : [256] ",
3435 "Format = STRING : [32] %1.1f",
3436 "Font = STRING : [32] Medium",
3437 "X = INT : 0",
3438 "Y = INT : 0",
3439 "Align = INT : 0",
3440 "FGColor = STRING : [8] 000000",
3441 "BGColor = STRING : [8] FFFFFF",
3442 NULL
3443};
3444
3445typedef struct {
3446 char src[256];
3447 char format[32];
3448 char font[32];
3449 int x, y, align;
3450 char fgcolor[8];
3451 char bgcolor[8];
3452} CGIF_LABEL;
3453
3454/* add labels using following syntax under /Custom/Images/<name.gif>/Bars/<name>:
3455
3456 [Name] [Description] [Example]
3457
3458 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3459 X X-position in pixel 90
3460 Y Y-position from top 67
3461 Width Width in pixel 20
3462 Height Height in pixel 100
3463 Direction 0(vertical)/1(horiz.) 0
3464 Axis Draw axis 0(none)/1(left)/2(right) 1
3465 Logscale Draw logarithmic axis n
3466 Min Min value for axis 0
3467 Max Max value for axis 10
3468 FGColor Foreground color RRGGBB 000000
3469 BGColor Background color RRGGBB FFFFFF
3470 BDColor Border color RRGGBB 808080
3471*/
3472
3473static const char *cgif_bar_str[] = {
3474 "Src = STRING : [256] ",
3475 "X = INT : 0",
3476 "Y = INT : 0",
3477 "Width = INT : 10",
3478 "Height = INT : 100",
3479 "Direction = INT : 0",
3480 "Axis = INT : 1",
3481 "Logscale = BOOL : n",
3482 "Min = DOUBLE : 0",
3483 "Max = DOUBLE : 10",
3484 "FGColor = STRING : [8] 000000",
3485 "BGColor = STRING : [8] FFFFFF",
3486 "BDColor = STRING : [8] 808080",
3487 NULL
3488};
3489
3490typedef struct {
3491 char src[256];
3492 int x, y, width, height, direction, axis;
3494 double min, max;
3495 char fgcolor[8];
3496 char bgcolor[8];
3497 char bdcolor[8];
3498} CGIF_BAR;
3499
3500/*------------------------------------------------------------------*/
3501
3502int evaluate_src(char *key, char *src, double *fvalue)
3503{
3504 HNDLE hDB, hkeyval;
3505 KEY vkey;
3506 int i, n, size, ivalue;
3507 char str[256], data[256];
3508
3510
3511 /* separate source from operators */
3512 for (i=0 ; i<(int)strlen(src) ; i++)
3513 if (src[i] == '>' || src[i] == '&')
3514 break;
3515 strncpy(str, src, i);
3516 str[i] = 0;
3517
3518 /* strip trailing blanks */
3519 while (strlen(str) > 0 && str[strlen(str)-1] == ' ')
3520 str[strlen(str)-1] = 0;
3521
3522 db_find_key(hDB, 0, str, &hkeyval);
3523 if (!hkeyval) {
3524 cm_msg(MERROR, "evaluate_src", "Invalid Src key \"%s\" for Fill \"%s\"",
3525 src, key);
3526 return 0;
3527 }
3528
3530 size = sizeof(data);
3531 db_get_value(hDB, 0, src, data, &size, vkey.type, FALSE);
3532 std::string value = db_sprintf(data, size, 0, vkey.type);
3533 if (equal_ustring(value.c_str(), "NAN"))
3534 return 0;
3535
3536 if (vkey.type == TID_BOOL) {
3537 *fvalue = (value[0] == 'y');
3538 } else
3539 *fvalue = atof(value.c_str());
3540
3541 /* evaluate possible operators */
3542 do {
3543 if (src[i] == '>' && src[i+1] == '>') {
3544 i+=2;
3545 n = atoi(src+i);
3546 while (src[i] == ' ' || isdigit(src[i]))
3547 i++;
3548 ivalue = (int)*fvalue;
3549 ivalue >>= n;
3550 *fvalue = ivalue;
3551 }
3552
3553 if (src[i] == '&') {
3554 i+=1;
3555 while (src[i] == ' ')
3556 i++;
3557 if (src[i] == '0' && src[i+1] == 'x')
3558 sscanf(src+2+i, "%x", &n);
3559 else
3560 n = atoi(src+i);
3561 while (src[i] == ' ' || isxdigit(src[i]) || src[i] == 'x')
3562 i++;
3563 ivalue = (int)*fvalue;
3564 ivalue &= n;
3565 *fvalue = ivalue;
3566 }
3567
3568 } while (src[i]);
3569
3570 return 1;
3571}
3572
3573/*------------------------------------------------------------------*/
3574
3575std::string add_custom_path(const std::string& filename)
3576{
3577 // do not append custom path to absolute filenames
3578
3579 if (filename[0] == '/')
3580 return filename;
3581 if (filename[0] == DIR_SEPARATOR)
3582 return filename;
3583
3584 HNDLE hDB;
3586
3587 std::string custom_path = "";
3588
3589 int status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
3590
3591 if (status != DB_SUCCESS)
3592 return filename;
3593
3594 if (custom_path.length() < 1)
3595 return filename;
3596
3598 cm_msg(MERROR, "add_custom_path", "ODB /Custom/Path has a forbidden value \"%s\", please change it", custom_path.c_str());
3599 return filename;
3600 }
3601
3603
3604 std::string full_filename = custom_path;
3605 if (full_filename[full_filename.length()-1] != DIR_SEPARATOR)
3607 full_filename += filename;
3608
3609 return full_filename;
3610}
3611
3612/*------------------------------------------------------------------*/
3613
3614void show_custom_file(Return* r, const char *name)
3615{
3616 char str[256];
3617 std::string filename;
3618 HNDLE hDB;
3619
3621
3622 HNDLE hkey;
3623 sprintf(str, "/Custom/%s", name);
3624 db_find_key(hDB, 0, str, &hkey);
3625
3626 if (!hkey) {
3627 sprintf(str, "/Custom/%s&", name);
3628 db_find_key(hDB, 0, str, &hkey);
3629 if (!hkey) {
3630 sprintf(str, "/Custom/%s!", name);
3631 db_find_key(hDB, 0, str, &hkey);
3632 }
3633 }
3634
3635 if(!hkey){
3636 sprintf(str,"show_custom_file: Invalid custom page: \"/Custom/%s\" not found in ODB", name);
3637 show_error_404(r, str);
3638 return;
3639 }
3640
3641 int status;
3642 KEY key;
3643
3645
3646 if (status != DB_SUCCESS) {
3647 char errtext[512];
3648 sprintf(errtext, "show_custom_file: Error: db_get_key() for \"%s\" status %d", str, status);
3650 return;
3651 }
3652
3653 int size = key.total_size;
3654 char* ctext = (char*)malloc(size);
3655
3657
3658 if (status != DB_SUCCESS) {
3659 char errtext[512];
3660 sprintf(errtext, "show_custom_file: Error: db_get_data() for \"%s\" status %d", str, status);
3662 free(ctext);
3663 return;
3664 }
3665
3666 filename = add_custom_path(ctext);
3667
3668 free(ctext);
3669
3670 send_file(r, filename, true);
3671
3672 return;
3673}
3674
3675/*------------------------------------------------------------------*/
3676
3677void show_custom_gif(Return* rr, const char *name)
3678{
3679 char str[256], data[256], src[256];
3680 int i, index, length, status, size, width, height, bgcol, fgcol, bdcol, r, g, b, x, y;
3682 double fvalue, ratio;
3683 KEY key, vkey;
3684 gdImagePtr im;
3687 FILE *f;
3688 CGIF_LABEL label;
3689 CGIF_BAR bar;
3690
3692
3693 /* find image description in ODB */
3694 sprintf(str, "/Custom/Images/%s", name);
3695 db_find_key(hDB, 0, str, &hkeygif);
3696 if (!hkeygif) {
3697
3698 // If we don't have Images directory,
3699 // then just treat this like any other custom file.
3701 return;
3702 }
3703
3704 /* load background image */
3705 std::string filename;
3706 db_get_value_string(hDB, hkeygif, "Background", 0, &filename, FALSE);
3707
3708 std::string full_filename = add_custom_path(filename);
3709
3710 f = fopen(full_filename.c_str(), "rb");
3711 if (f == NULL) {
3712 sprintf(str, "show_custom_gif: Cannot open file \"%s\"", full_filename.c_str());
3714 return;
3715 }
3716
3718 fclose(f);
3719
3720 if (im == NULL) {
3721 sprintf(str, "show_custom_gif: File \"%s\" is not a GIF image", filename.c_str());
3723 return;
3724 }
3725
3727
3728 /*---- draw labels ----------------------------------------------*/
3729
3730 db_find_key(hDB, hkeygif, "Labels", &hkeyroot);
3731 if (hkeyroot) {
3732 for (index = 0;; index++) {
3734 if (!hkey)
3735 break;
3736 db_get_key(hDB, hkey, &key);
3737
3738 size = sizeof(label);
3739 status = db_get_record1(hDB, hkey, &label, &size, 0, strcomb1(cgif_label_str).c_str());
3740 if (status != DB_SUCCESS) {
3741 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for label \"%s\"",
3742 key.name);
3743 continue;
3744 }
3745
3746 if (label.src[0] == 0) {
3747 cm_msg(MERROR, "show_custom_gif", "Empty Src key for label \"%s\"", key.name);
3748 continue;
3749 }
3750
3751 db_find_key(hDB, 0, label.src, &hkeyval);
3752 if (!hkeyval) {
3753 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for label \"%s\"",
3754 label.src, key.name);
3755 continue;
3756 }
3757
3759 size = sizeof(data);
3760 status = db_get_value(hDB, 0, label.src, data, &size, vkey.type, FALSE);
3761
3762 std::string value;
3763
3764 if (label.format[0]) {
3765 if (vkey.type == TID_FLOAT)
3766 value = msprintf(label.format, *(((float *) data)));
3767 else if (vkey.type == TID_DOUBLE)
3768 value = msprintf(label.format, *(((double *) data)));
3769 else if (vkey.type == TID_INT)
3770 value = msprintf(label.format, *(((INT *) data)));
3771 else if (vkey.type == TID_BOOL) {
3772 if (strstr(label.format, "%c"))
3773 value = msprintf(label.format, *(((INT *) data)) ? 'y' : 'n');
3774 else
3775 value = msprintf(label.format, *(((INT *) data)));
3776 } else
3777 value = db_sprintf(data, size, 0, vkey.type);
3778 } else
3779 value = db_sprintf(data, size, 0, vkey.type);
3780
3781 sscanf(label.fgcolor, "%02x%02x%02x", &r, &g, &b);
3782 fgcol = gdImageColorAllocate(im, r, g, b);
3783 if (fgcol == -1)
3784 fgcol = gdImageColorClosest(im, r, g, b);
3785
3786 sscanf(label.bgcolor, "%02x%02x%02x", &r, &g, &b);
3787 bgcol = gdImageColorAllocate(im, r, g, b);
3788 if (bgcol == -1)
3789 bgcol = gdImageColorClosest(im, r, g, b);
3790
3791 /* select font */
3792 if (equal_ustring(label.font, "Small"))
3794 else if (equal_ustring(label.font, "Medium"))
3796 else if (equal_ustring(label.font, "Giant"))
3798 else
3800
3801 width = value.length() * pfont->w + 5 + 5;
3802 height = pfont->h + 2 + 2;
3803
3804 if (label.align == 0) {
3805 /* left */
3806 gdImageFilledRectangle(im, label.x, label.y, label.x + width,
3807 label.y + height, bgcol);
3808 gdImageRectangle(im, label.x, label.y, label.x + width, label.y + height,
3809 fgcol);
3810 gdImageString(im, pfont, label.x + 5, label.y + 2, value.c_str(), fgcol);
3811 } else if (label.align == 1) {
3812 /* center */
3813 gdImageFilledRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3814 label.y + height, bgcol);
3815 gdImageRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3816 label.y + height, fgcol);
3817 gdImageString(im, pfont, label.x + 5 - width / 2, label.y + 2, value.c_str(), fgcol);
3818 } else {
3819 /* right */
3820 gdImageFilledRectangle(im, label.x - width, label.y, label.x,
3821 label.y + height, bgcol);
3822 gdImageRectangle(im, label.x - width, label.y, label.x, label.y + height,
3823 fgcol);
3824 gdImageString(im, pfont, label.x - width + 5, label.y + 2, value.c_str(), fgcol);
3825 }
3826 }
3827 }
3828
3829 /*---- draw bars ------------------------------------------------*/
3830
3831 db_find_key(hDB, hkeygif, "Bars", &hkeyroot);
3832 if (hkeyroot) {
3833 for (index = 0;; index++) {
3835 if (!hkey)
3836 break;
3837 db_get_key(hDB, hkey, &key);
3838
3839 size = sizeof(bar);
3841 if (status != DB_SUCCESS) {
3842 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for bar \"%s\"",
3843 key.name);
3844 continue;
3845 }
3846
3847 if (bar.src[0] == 0) {
3848 cm_msg(MERROR, "show_custom_gif", "Empty Src key for bar \"%s\"", key.name);
3849 continue;
3850 }
3851
3852 db_find_key(hDB, 0, bar.src, &hkeyval);
3853 if (!hkeyval) {
3854 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for bar \"%s\"",
3855 bar.src, key.name);
3856 continue;
3857 }
3858
3860 size = sizeof(data);
3861 status = db_get_value(hDB, 0, bar.src, data, &size, vkey.type, FALSE);
3862 std::string value = db_sprintf(data, size, 0, vkey.type);
3863 if (equal_ustring(value.c_str(), "NAN"))
3864 continue;
3865
3866 fvalue = atof(value.c_str());
3867
3868 sscanf(bar.fgcolor, "%02x%02x%02x", &r, &g, &b);
3869 fgcol = gdImageColorAllocate(im, r, g, b);
3870 if (fgcol == -1)
3871 fgcol = gdImageColorClosest(im, r, g, b);
3872
3873 sscanf(bar.bgcolor, "%02x%02x%02x", &r, &g, &b);
3874 bgcol = gdImageColorAllocate(im, r, g, b);
3875 if (bgcol == -1)
3876 bgcol = gdImageColorClosest(im, r, g, b);
3877
3878 sscanf(bar.bdcolor, "%02x%02x%02x", &r, &g, &b);
3879 bdcol = gdImageColorAllocate(im, r, g, b);
3880 if (bdcol == -1)
3881 bdcol = gdImageColorClosest(im, r, g, b);
3882
3883 if (bar.min == bar.max)
3884 bar.max += 1;
3885
3886 if (bar.logscale) {
3887 if (fvalue < 1E-20)
3888 fvalue = 1E-20;
3889 ratio = (log(fvalue) - log(bar.min)) / (log(bar.max) - log(bar.min));
3890 } else
3891 ratio = (fvalue - bar.min) / (bar.max - bar.min);
3892 if (ratio < 0)
3893 ratio = 0;
3894 if (ratio > 1)
3895 ratio = 1;
3896
3897 if (bar.direction == 0) {
3898 /* vertical */
3899 ratio = (bar.height - 2) - ratio * (bar.height - 2);
3900 r = (int) (ratio + 0.5);
3901
3902 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.width,
3903 bar.y + bar.height, bgcol);
3904 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.width, bar.y + bar.height,
3905 bdcol);
3906 gdImageFilledRectangle(im, bar.x + 1, bar.y + r + 1, bar.x + bar.width - 1,
3907 bar.y + bar.height - 1, fgcol);
3908
3909 if (bar.axis == 1)
3910 vaxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.height, bar.height, -3,
3911 -5, -7, -8, 0, bar.min, bar.max, bar.logscale);
3912 else if (bar.axis == 2)
3913 vaxis(im, gdFontSmall, bdcol, 0, bar.x + bar.width, bar.y + bar.height,
3914 bar.height, 3, 5, 7, 10, 0, bar.min, bar.max, bar.logscale);
3915
3916 } else {
3917 /* horizontal */
3918 ratio = ratio * (bar.height - 2);
3919 r = (int) (ratio + 0.5);
3920
3921 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.height,
3922 bar.y + bar.width, bgcol);
3923 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.height, bar.y + bar.width,
3924 bdcol);
3925 gdImageFilledRectangle(im, bar.x + 1, bar.y + 1, bar.x + r,
3926 bar.y + bar.width - 1, fgcol);
3927
3928 if (bar.axis == 1)
3929 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y, bar.height, -3, -5, -7, -18,
3930 0, bar.min, bar.max);
3931 else if (bar.axis == 2)
3932 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.width, bar.height, 3,
3933 5, 7, 8, 0, bar.min, bar.max);
3934 }
3935 }
3936 }
3937
3938 /*---- draw fills -----------------------------------------------*/
3939
3940 db_find_key(hDB, hkeygif, "Fills", &hkeyroot);
3941 if (hkeyroot) {
3942 for (index = 0;; index++) {
3944 if (!hkey)
3945 break;
3946 db_get_key(hDB, hkey, &key);
3947
3948 size = sizeof(src);
3949 src[0] = 0;
3950 db_get_value(hDB, hkey, "Src", src, &size, TID_STRING, TRUE);
3951
3952 if (src[0] == 0) {
3953 cm_msg(MERROR, "show_custom_gif", "Empty Src key for Fill \"%s\"", key.name);
3954 continue;
3955 }
3956
3957 if (!evaluate_src(key.name, src, &fvalue))
3958 continue;
3959
3960 x = y = 0;
3961 size = sizeof(x);
3962 db_get_value(hDB, hkey, "X", &x, &size, TID_INT, TRUE);
3963 db_get_value(hDB, hkey, "Y", &y, &size, TID_INT, TRUE);
3964
3965 size = sizeof(data);
3966 status = db_get_value(hDB, hkey, "Limits", data, &size, TID_DOUBLE, FALSE);
3967 if (status != DB_SUCCESS) {
3968 cm_msg(MERROR, "show_custom_gif", "No \"Limits\" entry for Fill \"%s\"",
3969 key.name);
3970 continue;
3971 }
3972 for (i = 0; i < size / (int) sizeof(double); i++)
3973 if (*((double *) data + i) > fvalue)
3974 break;
3975 if (i > 0)
3976 i--;
3977
3978 db_find_key(hDB, hkey, "Fillcolors", &hkeyval);
3979 if (!hkeyval) {
3980 cm_msg(MERROR, "show_custom_gif", "No \"Fillcolors\" entry for Fill \"%s\"",
3981 key.name);
3982 continue;
3983 }
3984
3985 size = sizeof(data);
3986 strcpy(data, "FFFFFF");
3988 if (status == DB_SUCCESS) {
3989 sscanf(data, "%02x%02x%02x", &r, &g, &b);
3990 fgcol = gdImageColorAllocate(im, r, g, b);
3991 if (fgcol == -1)
3992 fgcol = gdImageColorClosest(im, r, g, b);
3993 gdImageFill(im, x, y, fgcol);
3994 }
3995 }
3996 }
3997
3998 /* generate GIF */
3999 gdImageInterlace(im, 1);
4000 gdImageGif(im, &gb);
4002 length = gb.size;
4003
4004 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
4005 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
4006
4007 rr->rsprintf("Content-Type: image/gif\r\n");
4008 rr->rsprintf("Content-Length: %d\r\n", length);
4009 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
4010 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
4011
4012 rr->rmemcpy(gb.data, length);
4013}
4014
4015
4016
4017/*------------------------------------------------------------------*/
4018
4020{
4021 static RPC_LIST rpc_list[] = {
4022 { 9999, "mhttpd_jrpc_rev0", {
4023 {TID_STRING, RPC_IN}, // arg0
4024 {TID_STRING, RPC_IN}, // arg1
4025 {TID_STRING, RPC_IN}, // arg2
4026 {TID_STRING, RPC_IN}, // arg3
4027 {TID_STRING, RPC_IN}, // arg4
4028 {TID_STRING, RPC_IN}, // arg5
4029 {TID_STRING, RPC_IN}, // arg6
4030 {TID_STRING, RPC_IN}, // arg7
4031 {TID_STRING, RPC_IN}, // arg8
4032 {TID_STRING, RPC_IN}, // arg9
4033 {0}} },
4034 { 0 }
4035 };
4036
4037 int count = 0, substring = 0, rpc;
4038
4039 const char *xname = p->getparam("name");
4040 const char *srpc = p->getparam("rpc");
4041
4042 if (!srpc || !xname) {
4044 r->rsprintf("<INVALID_ARGUMENTS>");
4045 return;
4046 }
4047
4048 char sname[256];
4049 mstrlcpy(sname, xname, sizeof(sname));
4050
4051 if (sname[strlen(sname)-1]=='*') {
4052 sname[strlen(sname)-1] = 0;
4053 substring = 1;
4054 }
4055
4056 rpc = atoi(srpc);
4057
4060 r->rsprintf("<INVALID_RPC_ID>");
4061 return;
4062 }
4063
4064 rpc_list[0].id = rpc;
4066
4068 r->rsprintf("calling rpc %d | ", rpc);
4069
4070 if (1) {
4071 int status, i;
4072 char str[256];
4074
4076
4077 /* find client which exports FCNA function */
4078 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4079 if (status == DB_SUCCESS) {
4080 for (i=0; ; i++) {
4083 break;
4084
4085 sprintf(str, "RPC/%d", rpc);
4087 if (status == DB_SUCCESS) {
4088 char client_name[NAME_LENGTH];
4089 HNDLE hconn;
4090 int size;
4091
4092 size = sizeof(client_name);
4093 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4094 if (status != DB_SUCCESS)
4095 continue;
4096
4097 if (strlen(sname) > 0) {
4098 if (substring) {
4099 if (strstr(client_name, sname) != client_name)
4100 continue;
4101 } else {
4102 if (strcmp(sname, client_name) != 0)
4103 continue;
4104 }
4105 }
4106
4107 count++;
4108
4109 r->rsprintf("client %s", client_name);
4110
4111 status = cm_connect_client(client_name, &hconn);
4112 r->rsprintf(" %d", status);
4113
4114 if (status == RPC_SUCCESS) {
4116 p->getparam("arg0"),
4117 p->getparam("arg1"),
4118 p->getparam("arg2"),
4119 p->getparam("arg3"),
4120 p->getparam("arg4"),
4121 p->getparam("arg5"),
4122 p->getparam("arg6"),
4123 p->getparam("arg7"),
4124 p->getparam("arg8"),
4125 p->getparam("arg9")
4126 );
4127 r->rsprintf(" %d", status);
4128
4129 //status = cm_disconnect_client(hconn, FALSE);
4130 r->rsprintf(" %d", status);
4131 }
4132
4133 r->rsprintf(" | ");
4134 }
4135 }
4136 }
4137 }
4138
4139 r->rsprintf("rpc %d, called %d clients\n", rpc, count);
4140}
4141
4142/*------------------------------------------------------------------*/
4143
4145{
4146 static RPC_LIST rpc_list[] = {
4147 { 9998, "mhttpd_jrpc_rev1", {
4148 {TID_STRING, RPC_OUT}, // return string
4149 {TID_INT, RPC_IN}, // return string max length
4150 {TID_STRING, RPC_IN}, // arg0
4151 {TID_STRING, RPC_IN}, // arg1
4152 {TID_STRING, RPC_IN}, // arg2
4153 {TID_STRING, RPC_IN}, // arg3
4154 {TID_STRING, RPC_IN}, // arg4
4155 {TID_STRING, RPC_IN}, // arg5
4156 {TID_STRING, RPC_IN}, // arg6
4157 {TID_STRING, RPC_IN}, // arg7
4158 {TID_STRING, RPC_IN}, // arg8
4159 {TID_STRING, RPC_IN}, // arg9
4160 {0}} },
4161 { 0 }
4162 };
4163
4164 int status, substring = 0, rpc;
4165
4166 const char *xname = p->getparam("name");
4167 const char *srpc = p->getparam("rpc");
4168
4169 if (!srpc || !xname) {
4171 r->rsprintf("<INVALID_ARGUMENTS>");
4172 return;
4173 }
4174
4175 char sname[256];
4176 mstrlcpy(sname, xname, sizeof(sname));
4177
4178 if (sname[strlen(sname)-1]=='*') {
4179 sname[strlen(sname)-1] = 0;
4180 substring = 1;
4181 }
4182
4183 rpc = atoi(srpc);
4184
4187 r->rsprintf("<INVALID_RPC_ID>");
4188 return;
4189 }
4190
4191 rpc_list[0].id = rpc;
4193
4194 //printf("cm_register_functions() for format \'%s\' status %d\n", sformat, status);
4195
4197
4198 std::string reply_header;
4199 std::string reply_body;
4200
4201 //r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4202 //r->rsprintf("<!-- created by MHTTPD on (timestamp) -->\n");
4203 //r->rsprintf("<jrpc_rev1>\n");
4204 //r->rsprintf(" <rpc>%d</rpc>\n", rpc);
4205
4206 if (1) {
4208
4210
4211 int buf_length = 1024;
4212
4213 int max_reply_length = atoi(p->getparam("max_reply_length"));
4216
4217 char* buf = (char*)malloc(buf_length);
4218
4219 assert(buf != NULL);
4220
4221 /* find client which exports our RPC function */
4222 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4223 if (status == DB_SUCCESS) {
4224 for (int i=0; ; i++) {
4227 break;
4228
4229 char str[256];
4230 sprintf(str, "RPC/%d", rpc);
4232 if (status == DB_SUCCESS) {
4233 char client_name[NAME_LENGTH];
4234 HNDLE hconn;
4235 int size;
4236
4237 size = sizeof(client_name);
4238 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4239 if (status != DB_SUCCESS)
4240 continue;
4241
4242 if (strlen(sname) > 0) {
4243 if (substring) {
4244 if (strstr(client_name, sname) != client_name)
4245 continue;
4246 } else {
4247 if (strcmp(sname, client_name) != 0)
4248 continue;
4249 }
4250 }
4251
4252 //r->rsprintf(" <client>\n");
4253 //r->rsprintf(" <name>%s</name>\n", client_name);
4254
4255 int connect_status = -1;
4256 int call_status = -1;
4257 int call_length = 0;
4258 int disconnect_status = -1;
4259
4260 connect_status = cm_connect_client(client_name, &hconn);
4261
4262 //r->rsprintf(" <connect_status>%d</connect_status>\n", status);
4263
4264 if (connect_status == RPC_SUCCESS) {
4265 buf[0] = 0;
4266
4268 buf,
4269 buf_length,
4270 p->getparam("arg0"),
4271 p->getparam("arg1"),
4272 p->getparam("arg2"),
4273 p->getparam("arg3"),
4274 p->getparam("arg4"),
4275 p->getparam("arg5"),
4276 p->getparam("arg6"),
4277 p->getparam("arg7"),
4278 p->getparam("arg8"),
4279 p->getparam("arg9")
4280 );
4281
4282 //r->rsprintf(" <rpc_status>%d</rpc_status>\n", status);
4284 //r->rsputs("<data>");
4285 //r->rsputs(buf);
4286 //r->rsputs("</data>\n");
4287
4288 if (call_status == RPC_SUCCESS) {
4289 call_length = strlen(buf);
4290 reply_body += buf;
4291 }
4292
4293 //disconnect_status = cm_disconnect_client(hconn, FALSE);
4294 //r->rsprintf(" <disconnect_status>%d</disconnect_status>\n", status);
4295 }
4296
4297 //r->rsprintf(" </client>\n");
4298
4299 if (reply_header.length() > 0)
4300 reply_header += " | ";
4301
4302 char tmp[256];
4303 sprintf(tmp, "%s %d %d %d %d", client_name, connect_status, call_status, disconnect_status, call_length);
4304 reply_header += tmp;
4305 }
4306 }
4307 }
4308
4309 free(buf);
4310 }
4311
4312 //r->rsprintf(" <called_clients>%d</called_clients>\n", count);
4313 //r->rsprintf("</jrpc_rev1>\n");
4314
4315 if (reply_header.length() > 0) {
4316 r->rsputs(reply_header.c_str());
4317 r->rsputs(" || ");
4318 r->rsputs(reply_body.c_str());
4319 r->rsputs("\n");
4320 }
4321}
4322
4323/*------------------------------------------------------------------*/
4324
4326{
4327 int status;
4328
4329 const char *name = p->getparam("name");
4330 const char *cmd = p->getparam("rcmd");
4331 const char *args = p->getparam("rarg");
4332
4333 if (!name || !cmd || !args) {
4335 r->rsprintf("<INVALID_ARGUMENTS>");
4336 return;
4337 }
4338
4340
4341 int buf_length = 1024;
4342
4343 int max_reply_length = atoi(p->getparam("max_reply_length"));
4346
4347 char* buf = (char*)malloc(buf_length);
4348 assert(buf != NULL);
4349
4350 buf[0] = 0;
4351
4352 HNDLE hconn;
4353
4355
4356 if (status != RPC_SUCCESS) {
4357 r->rsprintf("<RPC_CONNECT_ERROR>%d</RPC_CONNECT_ERROR>", status);
4358 free(buf);
4359 return;
4360 }
4361
4363
4364 if (status != RPC_SUCCESS) {
4365 r->rsprintf("<RPC_CALL_ERROR>%d</RPC_CALL_ERROR>", status);
4366 free(buf);
4367 return;
4368 }
4369
4370 r->rsprintf("%s", buf);
4371
4372 //status = cm_disconnect_client(hconn, FALSE);
4373
4374 free(buf);
4375}
4376
4377/*------------------------------------------------------------------*/
4378
4379void output_key(Param* p, Return* r, HNDLE hkey, int index, const char *format)
4380{
4381 int size, i;
4382 HNDLE hDB, hsubkey;
4383 KEY key;
4384 char data[TEXT_SIZE];
4385
4387
4388 db_get_key(hDB, hkey, &key);
4389 if (key.type == TID_KEY) {
4390 for (i=0 ; ; i++) {
4392 if (!hsubkey)
4393 break;
4394 output_key(p, r, hsubkey, -1, format);
4395 }
4396 } else {
4397 if (key.item_size <= (int)sizeof(data)) {
4398 size = sizeof(data);
4399 db_get_data(hDB, hkey, data, &size, key.type);
4400 if (index == -1) {
4401 for (i=0 ; i<key.num_values ; i++) {
4402 if (p->isparam("name") && atoi(p->getparam("name")) == 1) {
4403 if (key.num_values == 1)
4404 r->rsprintf("%s:", key.name);
4405 else
4406 r->rsprintf("%s[%d]:", key.name, i);
4407 }
4408 std::string data_str;
4409 if (format && format[0])
4411 else
4413 r->rsputs(data_str.c_str());
4414 if (i<key.num_values-1)
4415 r->rsputs("\n");
4416 }
4417 } else {
4418 if (p->isparam("name") && atoi(p->getparam("name")) == 1)
4419 r->rsprintf("%s[%d]:", key.name, index);
4420 if (index >= key.num_values)
4421 r->rsputs("<DB_OUT_OF_RANGE>");
4422 else {
4423 std::string data_str;
4424 if (p->isparam("format"))
4426 else
4428 r->rsputs(data_str.c_str());
4429 }
4430 }
4431 r->rsputs("\n");
4432 }
4433 }
4434}
4435
4436/*------------------------------------------------------------------*/
4437
4438bool starts_with(const std::string& s1, const char* s2)
4439{
4440 if (s1.length() < strlen(s2))
4441 return false;
4442 return (strncasecmp(s1.c_str(), s2, strlen(s2)) == 0);
4443}
4444
4445//static bool ends_with_char(const std::string& s, char c)
4446//{
4447// if (s.length() < 1)
4448// return false;
4449// return s[s.length()-1] == c;
4450//}
4451
4452/*------------------------------------------------------------------*/
4453
4454void javascript_commands(Param* p, Return* r, const char *cookie_cpwd)
4455{
4456 int status;
4457 int size, i, n, index, type;
4458 unsigned int t;
4459 char str[TEXT_SIZE], format[256], facility[256], user[256];
4460 HNDLE hDB, hkey;
4461 KEY key;
4462 char data[TEXT_SIZE];
4463
4465
4466 // process common parameters
4467
4468 const int ENCODING_NONE = 0;
4469 const int ENCODING_ODB = 1;
4470 const int ENCODING_XML = 2;
4471 const int ENCODING_JSON = 3;
4472
4473 std::string cmd_parameter;
4474 std::string encoding_parameter;
4475 int encoding = ENCODING_NONE; // default encoding
4476 bool jsonp = false; // default is no JSONP wrapper
4477 std::string jsonp_callback; // default is no JSONP
4478 bool single = false; // single encoding
4479 bool multiple = false; // multiple encoding
4480 std::vector<std::string> odb; // multiple odb parameters
4481 //HNDLE hodb; // ODB handle for single odb parameter
4482 //std::vector<HNDLE> hodbm; // ODB handle for multiple odb parameter
4483
4484 if (p->isparam("cmd")) {
4485 cmd_parameter = p->getparam("cmd");
4486 }
4487
4488 if (p->isparam("encoding")) {
4489 encoding_parameter = p->getparam("encoding");
4490 }
4491
4492 if (encoding_parameter.length() > 0) {
4493 if (starts_with(encoding_parameter, "odb"))
4495 else if (starts_with(encoding_parameter, "xml"))
4497 else if (starts_with(encoding_parameter, "json"))
4499 }
4500
4501 if (encoding == ENCODING_JSON) {
4502 if (p->isparam("callback")) {
4503 jsonp = true;
4504 jsonp_callback = p->getparam("callback");
4505 }
4506 }
4507
4508 if (p->isparam("odb")) {
4509 single = true;
4510 odb.push_back(p->getparam("odb"));
4511 }
4512
4513 if (p->isparam("odb0")) {
4514 multiple = true;
4515 for (int i=0 ; ; i++) {
4516 char ppath[256];
4517 sprintf(ppath, "odb%d", i);
4518 if (!p->isparam(ppath))
4519 break;
4520 odb.push_back(p->getparam(ppath));
4521 }
4522 }
4523
4524 if (/* DISABLES CODE */ (0)) {
4525 printf("command [%s], encoding %d [%s], jsonp %d, single %d, multiple %d, odb array size %d\n", cmd_parameter.c_str(), encoding, encoding_parameter.c_str(), jsonp, single, multiple, (int)odb.size());
4526 }
4527
4528 /* process "jset" command */
4529 if (equal_ustring(p->getparam("cmd"), "jset")) {
4530
4531 if (*p->getparam("pnam")) {
4532 std::string ppath;
4533 ppath += "/Custom/Pwd/";
4534 ppath += p->getparam("pnam");
4535 str[0] = 0;
4536 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
4537 if (!equal_ustring(cookie_cpwd, str)) {
4539 r->rsprintf("Invalid password!");
4540 return;
4541 }
4542 }
4543 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4544 if (strchr(str, '[')) {
4545 if (*(strchr(str, '[')+1) == '*')
4546 index = -1;
4547 else
4548 index = atoi(strchr(str, '[')+1);
4549 *strchr(str, '[') = 0;
4550 } else
4551 index = 0;
4552
4553 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS && p->isparam("value")) {
4554 db_get_key(hDB, hkey, &key);
4555 memset(data, 0, sizeof(data));
4556 if (key.item_size <= (int)sizeof(data)) {
4557 if (index == -1) {
4558 const char* ptr = p->getparam("value");
4559 for (i=0 ; ptr != NULL ; i++) {
4560 size = sizeof(data);
4561 db_sscanf(ptr, data, &size, 0, key.type);
4562 if (strchr(data, ','))
4563 *strchr(data, ',') = 0;
4565 ptr = strchr(ptr, ',');
4566 if (ptr != NULL)
4567 ptr++;
4568 }
4569 } else {
4570 size = sizeof(data);
4571 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4572
4573 /* extend data size for single string if necessary */
4574 if ((key.type == TID_STRING || key.type == TID_LINK)
4575 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1) {
4576 key.item_size = strlen(data) + 1;
4578 } else
4580 }
4581 }
4582 } else {
4583 if (p->isparam("value") && p->isparam("type") && p->isparam("len")) {
4584 int type = atoi(p->getparam("type"));
4585 if (type == 0) {
4587 r->rsprintf("Invalid type %d!", type);
4588 return;
4589 }
4590 db_create_key(hDB, 0, str, type);
4591 db_find_key(hDB, 0, str, &hkey);
4592 if (!hkey) {
4594 r->rsprintf("Cannot create \'%s\' type %d", str, type);
4595 return;
4596 }
4597 db_get_key(hDB, hkey, &key);
4598 memset(data, 0, sizeof(data));
4599 size = sizeof(data);
4600 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4601 if (key.type == TID_STRING)
4602 db_set_data(hDB, hkey, data, atoi(p->getparam("len")), 1, TID_STRING);
4603 else {
4604 for (i=0 ; i<atoi(p->getparam("len")) ; i++)
4606 }
4607 }
4608 }
4609
4611 r->rsprintf("OK");
4612 return;
4613 }
4614
4615 /* process "jget" command */
4616 if (equal_ustring(p->getparam("cmd"), "jget")) {
4617
4618 if (p->isparam("odb")) {
4619 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4620 if (strchr(str, '[')) {
4621 if (*(strchr(str, '[')+1) == '*')
4622 index = -1;
4623 else
4624 index = atoi(strchr(str, '[')+1);
4625 *strchr(str, '[') = 0;
4626 } else
4627 index = 0;
4628
4630
4631 status = db_find_key(hDB, 0, str, &hkey);
4632
4633 if (status == DB_SUCCESS)
4634 output_key(p, r, hkey, index, p->getparam("format"));
4635 else
4636 r->rsputs("<DB_NO_KEY>");
4637 }
4638
4639 if (p->isparam("odb0")) {
4641 for (i=0 ; ; i++) {
4642 char ppath[256];
4643 sprintf(ppath, "odb%d", i);
4644 sprintf(format, "format%d", i);
4645 if (p->isparam(ppath)) {
4646 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4647 if (strchr(str, '[')) {
4648 if (*(strchr(str, '[')+1) == '*')
4649 index = -1;
4650 else
4651 index = atoi(strchr(str, '[')+1);
4652 *strchr(str, '[') = 0;
4653 } else
4654 index = 0;
4655 if (i > 0)
4656 r->rsputs("$#----#$\n");
4657 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS)
4658 output_key(p, r, hkey, index, p->getparam(format));
4659 else
4660 r->rsputs("<DB_NO_KEY>");
4661
4662 } else
4663 break;
4664 }
4665 }
4666
4667 return;
4668 }
4669
4670 /* process "jcopy" command */
4671 if (equal_ustring(p->getparam("cmd"), "jcopy")) {
4672
4673 bool fmt_odb = false;
4674 bool fmt_xml = false;
4675 bool fmt_json = true;
4676 bool fmt_jsonp = false;
4677 int follow_links = 1;
4678 int save_keys = 1;
4679 int recurse = 1;
4680 const char* fmt = NULL;
4681 const char* jsonp_callback = "callback";
4682
4683 if (p->isparam("encoding")) {
4684 fmt = p->getparam("encoding");
4685 } else if (p->isparam("format")) {
4686 fmt = p->getparam("format");
4687 }
4688
4689 if (fmt) {
4690 fmt_odb = (equal_ustring(fmt, "odb") > 0);
4691 fmt_xml = (equal_ustring(fmt, "xml") > 0);
4692 fmt_json = (strstr(fmt, "json") != NULL);
4693
4694 if (fmt_odb)
4695 fmt_xml = fmt_json = false;
4696 if (fmt_xml)
4697 fmt_odb = fmt_json = false;
4698 if (fmt_json)
4699 fmt_odb = fmt_xml = false;
4700
4701 if (fmt_json)
4702 fmt_jsonp = (strstr(fmt, "-p") != NULL);
4703 if (fmt_jsonp && p->isparam("callback"))
4704 jsonp_callback = p->getparam("callback");
4705 if (fmt_json && strstr(fmt, "-nofollowlinks"))
4706 follow_links = 0;
4707 if (fmt_json && strstr(fmt, "-nokeys"))
4708 save_keys = 2;
4709 if (fmt_json && strstr(fmt, "-nolastwritten"))
4710 save_keys = 0;
4711 if (fmt_json && strstr(fmt, "-norecurse"))
4712 recurse = 0;
4713 }
4714
4715 if (p->isparam("odb")) {
4716 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4717
4719
4720 if (fmt_json)
4721 status = db_find_link(hDB, 0, str, &hkey);
4722 else
4723 status = db_find_key(hDB, 0, str, &hkey);
4724 if (status == DB_SUCCESS) {
4725
4726 if (fmt_jsonp) {
4728 r->rsputs("(");
4729 }
4730
4731 int end = 0;
4733 char* buf = (char *)malloc(bufsize);
4734
4735 if (fmt_xml)
4736 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4737 else if (fmt_json)
4739 else
4740 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4741
4742 r->rsputs(buf);
4743 free(buf);
4744
4745 if (fmt_jsonp) {
4746 r->rsputs(");\n");
4747 }
4748 } else
4749 r->rsputs("<DB_NO_KEY>");
4750 }
4751
4752 if (p->isparam("odb0")) {
4754 if (fmt_jsonp) {
4756 r->rsputs("(");
4757 }
4758 if (fmt_xml) {
4759 r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4760 r->rsputs("<jcopy>\n");
4761 r->rsputs("<data>\n");
4762 } else if (fmt_json)
4763 r->rsputs("[\n");
4764 else
4765 r->rsputs("");
4766 for (int i=0 ; ; i++) {
4767 char ppath[256];
4768 sprintf(ppath, "odb%d", i);
4769 if (!p->isparam(ppath))
4770 break;
4771 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4772
4773 if (i > 0) {
4774 if (fmt_xml)
4775 r->rsputs("</data>\n<data>\n");
4776 else if (fmt_json)
4777 r->rsputs(",\n");
4778 else
4779 r->rsputs("$#----#$\n");
4780 }
4781
4782 if (fmt_json)
4783 status = db_find_link(hDB, 0, str, &hkey);
4784 else
4785 status = db_find_key(hDB, 0, str, &hkey);
4786 if (status != DB_SUCCESS) {
4787 if (fmt_xml)
4788 r->rsputs("<DB_NO_KEY/>\n");
4789 else if (fmt_json) {
4790 char tmp[256];
4791 sprintf(tmp, "{ \"/error\" : %d }\n", status);
4792 r->rsputs(tmp);
4793 } else
4794 r->rsputs("<DB_NO_KEY>\n");
4795 continue;
4796 }
4797
4798 int end = 0;
4800 char* buf = (char *)malloc(bufsize);
4801
4802 if (fmt_xml) {
4803 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4804 const char* s = strstr(buf, "-->");
4805 if (s)
4806 s+=4;
4807 else
4808 s = buf;
4809 r->rsputs(s);
4810 } else if (fmt_json) {
4812 r->rsputs(buf);
4813 } else {
4814 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4815 r->rsputs(buf);
4816 }
4817
4818 free(buf);
4819 }
4820
4821 if (fmt_xml)
4822 r->rsputs("</data>\n</jcopy>\n");
4823 else if (fmt_json)
4824 r->rsputs("]\n");
4825 else
4826 r->rsputs("");
4827
4828 if (fmt_jsonp) {
4829 r->rsputs(");\n");
4830 }
4831 }
4832 return;
4833 }
4834
4835 /* process "jkey" command */
4836 if (equal_ustring(p->getparam("cmd"), "jkey")) {
4837
4838 // test:
4839 // curl "http://localhost:8080?cmd=jkey&odb0=/runinfo/run+number&odb1=/nonexistant&odb2=/&encoding=json&callback=aaa"
4840
4842
4843 if (jsonp) {
4844 r->rsputs(jsonp_callback.c_str());
4845 r->rsputs("(");
4846 }
4847
4848 if (multiple) {
4849 switch (encoding) {
4850 default:
4851 break;
4852 case ENCODING_JSON:
4853 r->rsprintf("[ ");
4854 break;
4855 }
4856 }
4857
4858 for (unsigned i=0; i<odb.size(); i++) {
4859 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
4860 if (status == DB_SUCCESS)
4862 switch (encoding) {
4863 default:
4864 if (multiple && i>0)
4865 r->rsputs("$#----#$\n");
4866 if (status == DB_SUCCESS) {
4867 r->rsprintf("%s\n", key.name);
4868 r->rsprintf("TID_%s\n", rpc_tid_name(key.type));
4869 r->rsprintf("%d\n", key.num_values);
4870 r->rsprintf("%d\n", key.item_size);
4871 r->rsprintf("%d\n", key.last_written);
4872 } else {
4873 r->rsputs("<DB_NO_KEY>\n");
4874 }
4875 break;
4876 case ENCODING_JSON:
4877 if (multiple && i>0)
4878 r->rsprintf(", ");
4879 if (status == DB_SUCCESS) {
4880 r->rsprintf("{ ");
4881 r->rsprintf("\"name\":\"%s\",", key.name);
4882 r->rsprintf("\"type\":%d,", key.type);
4883 r->rsprintf("\"type_name\":\"TID_%s\",", rpc_tid_name(key.type));
4884 r->rsprintf("\"num_values\":%d,", key.num_values);
4885 r->rsprintf("\"item_size\":%d,", key.item_size);
4886 r->rsprintf("\"last_written\":%d", key.last_written);
4887 r->rsprintf(" }");
4888 } else {
4889 r->rsprintf("{ \"/error\":%d }", status);
4890 }
4891 break;
4892 }
4893 }
4894
4895 if (multiple) {
4896 switch (encoding) {
4897 default:
4898 break;
4899 case ENCODING_JSON:
4900 r->rsprintf(" ]");
4901 break;
4902 }
4903 }
4904
4905 if (jsonp) {
4906 r->rsputs(");\n");
4907 }
4908
4909 return;
4910 }
4911
4912 /* process "jcreate" command */
4913 if (equal_ustring(p->getparam("cmd"), "jcreate")) {
4914
4915 // test:
4916 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
4917 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo&type=7"
4918 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo70&type=7&arraylen=10"
4919 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s&type=12&strlen=32"
4920 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s5&type=12&strlen=32&arraylen=5"
4921 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo12s5x&type0=12&strlen0=32&arraylen0=5"
4922
4923
4925
4926 if (jsonp) {
4927 r->rsputs(jsonp_callback.c_str());
4928 r->rsputs("(");
4929 }
4930
4931 if (multiple) {
4932 switch (encoding) {
4933 default:
4934 case ENCODING_JSON:
4935 r->rsprintf("[ ");
4936 break;
4937 }
4938 }
4939
4940 for (unsigned i=0; i<odb.size(); i++) {
4941 HNDLE hkey = 0;
4942 int type = 0;
4943 int arraylength = 0;
4944 int strlength = 0;
4945
4946 if (single) {
4947 type = atoi(p->getparam("type"));
4948 arraylength = atoi(p->getparam("arraylen"));
4949 strlength = atoi(p->getparam("strlen"));
4950 }
4951 else if (multiple) {
4952 char buf[256];
4953 sprintf(buf, "type%d", i);
4954 type = atoi(p->getparam(buf));
4955 sprintf(buf, "arraylen%d", i);
4956 arraylength = atoi(p->getparam(buf));
4957 sprintf(buf, "strlen%d", i);
4958 strlength = atoi(p->getparam(buf));
4959 }
4960
4961 status = db_create_key(hDB, 0, odb[i].c_str(), type);
4962
4963 if (status == DB_SUCCESS) {
4964 status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
4965 }
4966
4967 if (status == DB_SUCCESS && hkey && type == TID_STRING && strlength > 0) {
4968 char* s = (char*)calloc(strlength, 1); // initialized to zero
4970 free(s);
4971 }
4972
4973 if (status == DB_SUCCESS && hkey && arraylength > 1) {
4975 }
4976
4977 switch (encoding) {
4978 default:
4979 case ENCODING_JSON:
4980 if (multiple && i>0)
4981 r->rsprintf(", ");
4982 r->rsprintf("%d", status);
4983 break;
4984 }
4985 }
4986
4987 if (multiple) {
4988 switch (encoding) {
4989 default:
4990 case ENCODING_JSON:
4991 r->rsprintf(" ]");
4992 break;
4993 }
4994 }
4995
4996 if (jsonp) {
4997 r->rsputs(");\n");
4998 }
4999
5000 return;
5001 }
5002
5003 /* process "jresize" command */
5004 if (equal_ustring(p->getparam("cmd"), "jresize")) {
5005
5006 // test:
5007
5008 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo70&arraylen=5"
5009 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&arraylen=5"
5010 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=16"
5011 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=30&arraylen=10"
5012
5014
5015 if (jsonp) {
5016 r->rsputs(jsonp_callback.c_str());
5017 r->rsputs("(");
5018 }
5019
5020 if (multiple) {
5021 switch (encoding) {
5022 default:
5023 case ENCODING_JSON:
5024 r->rsprintf("[ ");
5025 break;
5026 }
5027 }
5028
5029 for (unsigned i=0; i<odb.size(); i++) {
5030 HNDLE hkey;
5031 KEY key;
5032 int arraylength = 0;
5033 int strlength = 0;
5034
5035 if (single) {
5036 arraylength = atoi(p->getparam("arraylen"));
5037 strlength = atoi(p->getparam("strlen"));
5038 }
5039 else if (multiple) {
5040 char buf[256];
5041 sprintf(buf, "arraylen%d", i);
5042 arraylength = atoi(p->getparam(buf));
5043 sprintf(buf, "strlen%d", i);
5044 strlength = atoi(p->getparam(buf));
5045 }
5046
5047 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5048
5049 if (status == DB_SUCCESS && hkey) {
5051 }
5052
5053 if (status == DB_SUCCESS && hkey && key.type == TID_STRING && strlength > 0) {
5055 char* olddata = (char*)malloc(oldsize);
5056 int size = oldsize;
5058
5059 if (status == DB_SUCCESS) {
5061 char* s = (char*)calloc(newsize, 1); // initialized to zero
5062 for (int k=0; k<key.num_values; k++) {
5064 }
5065
5067 free(s);
5068 }
5069
5070 free(olddata);
5071 }
5072
5073 if (status == DB_SUCCESS && hkey && arraylength > 0) {
5075 }
5076
5077 switch (encoding) {
5078 default:
5079 case ENCODING_JSON:
5080 if (multiple && i>0)
5081 r->rsprintf(", ");
5082 r->rsprintf("%d", status);
5083 break;
5084 }
5085 }
5086
5087 if (multiple) {
5088 switch (encoding) {
5089 default:
5090 case ENCODING_JSON:
5091 r->rsprintf(" ]");
5092 break;
5093 }
5094 }
5095
5096 if (jsonp) {
5097 r->rsputs(");\n");
5098 }
5099
5100 return;
5101 }
5102
5103 /* process "jrename" command */
5104 if (equal_ustring(p->getparam("cmd"), "jrename")) {
5105
5106 // test:
5107 // curl "http://localhost:8080?cmd=jrename&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
5108 // curl "http://localhost:8080?cmd=jrename&odb=/test/foo&name=foofoo"
5109
5111
5112 if (jsonp) {
5113 r->rsputs(jsonp_callback.c_str());
5114 r->rsputs("(");
5115 }
5116
5117 if (multiple) {
5118 switch (encoding) {
5119 default:
5120 case ENCODING_JSON:
5121 r->rsprintf("[ ");
5122 break;
5123 }
5124 }
5125
5126 for (unsigned i=0; i<odb.size(); i++) {
5127 const char* name = NULL;
5128 if (single)
5129 name = p->getparam("name");
5130 else if (multiple) {
5131 char buf[256];
5132 sprintf(buf, "name%d", i);
5133 name = p->getparam(buf);
5134 }
5135 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5136 if (status == DB_SUCCESS) {
5138 }
5139 switch (encoding) {
5140 default:
5141 case ENCODING_JSON:
5142 if (multiple && i>0)
5143 r->rsprintf(", ");
5144 r->rsprintf("%d", status);
5145 break;
5146 }
5147 }
5148
5149 if (multiple) {
5150 switch (encoding) {
5151 default:
5152 case ENCODING_JSON:
5153 r->rsprintf(" ]");
5154 break;
5155 }
5156 }
5157
5158 if (jsonp) {
5159 r->rsputs(");\n");
5160 }
5161
5162 return;
5163 }
5164
5165 /* process "jlink" command */
5166 if (equal_ustring(p->getparam("cmd"), "jlink")) {
5167
5168 // test:
5169 // curl "http://localhost:8080?cmd=jlink&odb=/test/link&dest=/test/foo"
5170 // curl "http://localhost:8080?cmd=jlink&odb0=/test/link0&dest0=/test/foo&odb1=/test/link1&dest1=/test/foo"
5171
5173
5174 if (jsonp) {
5175 r->rsputs(jsonp_callback.c_str());
5176 r->rsputs("(");
5177 }
5178
5179 if (multiple) {
5180 switch (encoding) {
5181 default:
5182 case ENCODING_JSON:
5183 r->rsprintf("[ ");
5184 break;
5185 }
5186 }
5187
5188 for (unsigned i=0; i<odb.size(); i++) {
5189 const char* dest = NULL;
5190 if (single)
5191 dest = p->getparam("dest");
5192 else if (multiple) {
5193 char buf[256];
5194 sprintf(buf, "dest%d", i);
5195 dest = p->getparam(buf);
5196 }
5197
5198 status = db_create_link(hDB, 0, odb[i].c_str(), dest);
5199
5200 switch (encoding) {
5201 default:
5202 case ENCODING_JSON:
5203 if (multiple && i>0)
5204 r->rsprintf(", ");
5205 r->rsprintf("%d", status);
5206 break;
5207 }
5208 }
5209
5210 if (multiple) {
5211 switch (encoding) {
5212 default:
5213 case ENCODING_JSON:
5214 r->rsprintf(" ]");
5215 break;
5216 }
5217 }
5218
5219 if (jsonp) {
5220 r->rsputs(");\n");
5221 }
5222
5223 return;
5224 }
5225
5226 /* process "jreorder" command */
5227 if (equal_ustring(p->getparam("cmd"), "jreorder")) {
5228
5229 // test:
5230 // curl "http://localhost:8080?cmd=jreorder&odb0=/test/foo&index0=0&odb1=/test/bar&index1=1"
5231 // curl "http://localhost:8080?cmd=jreorder&odb=/test/bar&index=0"
5232
5234
5235 if (jsonp) {
5236 r->rsputs(jsonp_callback.c_str());
5237 r->rsputs("(");
5238 }
5239
5240 if (multiple) {
5241 switch (encoding) {
5242 default:
5243 case ENCODING_JSON:
5244 r->rsprintf("[ ");
5245 break;
5246 }
5247 }
5248
5249 for (unsigned i=0; i<odb.size(); i++) {
5250 int index = 0;
5251 if (single)
5252 index = atoi(p->getparam("index"));
5253 else if (multiple) {
5254 char buf[256];
5255 sprintf(buf, "index%d", i);
5256 index = atoi(p->getparam(buf));
5257 }
5258
5259 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5260 if (status == DB_SUCCESS) {
5262 }
5263
5264 switch (encoding) {
5265 default:
5266 case ENCODING_JSON:
5267 if (multiple && i>0)
5268 r->rsprintf(", ");
5269 r->rsprintf("%d", status);
5270 break;
5271 }
5272 }
5273
5274 if (multiple) {
5275 switch (encoding) {
5276 default:
5277 case ENCODING_JSON:
5278 r->rsprintf(" ]");
5279 break;
5280 }
5281 }
5282
5283 if (jsonp) {
5284 r->rsputs(");\n");
5285 }
5286
5287 return;
5288 }
5289
5290 /* process "jdelete" command */
5291 if (equal_ustring(p->getparam("cmd"), "jdelete")) {
5292
5293 // test:
5294 // curl "http://localhost:8080?cmd=jdelete&odb0=/test/foo&odb1=/nonexistant&odb2=/test/bar&encoding=json&callback=aaa"
5295 // curl "http://localhost:8080?cmd=jdelete&odb=/test/foo"
5296
5298
5299 if (jsonp) {
5300 r->rsputs(jsonp_callback.c_str());
5301 r->rsputs("(");
5302 }
5303
5304 if (multiple) {
5305 switch (encoding) {
5306 default:
5307 case ENCODING_JSON:
5308 r->rsprintf("[ ");
5309 break;
5310 }
5311 }
5312
5313 for (unsigned i=0; i<odb.size(); i++) {
5314 BOOL follow_links = 0;
5315 status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
5316 if (status == DB_SUCCESS) {
5318 }
5319 switch (encoding) {
5320 default:
5321 case ENCODING_JSON:
5322 if (multiple && i>0)
5323 r->rsprintf(", ");
5324 r->rsprintf("%d", status);
5325 break;
5326 }
5327 }
5328
5329 if (multiple) {
5330 switch (encoding) {
5331 default:
5332 case ENCODING_JSON:
5333 r->rsprintf(" ]");
5334 break;
5335 }
5336 }
5337
5338 if (jsonp) {
5339 r->rsputs(");\n");
5340 }
5341
5342 return;
5343 }
5344
5345 /* process "jmsg" command */
5346 if (equal_ustring(p->getparam("cmd"), "jmsg")) {
5347
5348 if (p->getparam("f") && *p->getparam("f"))
5349 mstrlcpy(facility, p->getparam("f"), sizeof(facility));
5350 else
5351 mstrlcpy(facility, "midas", sizeof(facility));
5352
5353 n = 1;
5354 if (p->getparam("n") && *p->getparam("n"))
5355 n = atoi(p->getparam("n"));
5356
5357 t = 0;
5358 if (p->getparam("t") && p->getparam("t"))
5359 t = atoi(p->getparam("t"));
5360
5362 char* messages = NULL;
5363 int num_messages = 0;
5365 if (messages) {
5366 r->rsputs(messages);
5367 free(messages);
5368 }
5369 return;
5370 }
5371
5372 /* process "jgenmsg" command */
5373 if (equal_ustring(p->getparam("cmd"), "jgenmsg")) {
5374
5375 if (p->getparam("facility") && *p->getparam("facility"))
5376 mstrlcpy(facility, p->getparam("facility"), sizeof(facility));
5377 else
5378 mstrlcpy(facility, "midas", sizeof(facility));
5379
5380 if (p->getparam("user") && *p->getparam("user"))
5381 mstrlcpy(user, p->getparam("user"), sizeof(user));
5382 else
5383 mstrlcpy(user, "javascript_commands", sizeof(user));
5384
5385 if (p->getparam("type") && *p->getparam("type"))
5386 type = atoi(p->getparam("type"));
5387 else
5388 type = MT_INFO;
5389
5390 if (p->getparam("msg") && *p->getparam("msg")) {
5391 cm_msg1(type, __FILE__, __LINE__, facility, user, "%s", p->getparam("msg"));
5392 }
5393
5395 r->rsputs("Message successfully created\n");
5396 return;
5397 }
5398
5399 /* process "jalm" command */
5400 if (equal_ustring(p->getparam("cmd"), "jalm")) {
5401
5403 std::string alarms;
5405 r->rsputs(alarms.c_str());
5406 return;
5407 }
5408
5409 /* process "jrpc" command */
5410 if (equal_ustring(p->getparam("cmd"), "jrpc_rev0")) {
5411 do_jrpc_rev0(p, r);
5412 return;
5413 }
5414
5415 /* process "jrpc" command */
5416 if (equal_ustring(p->getparam("cmd"), "jrpc_rev1")) {
5417 do_jrpc_rev1(p, r);
5418 return;
5419 }
5420
5421 /* process "jrpc" command */
5422 if (equal_ustring(p->getparam("cmd"), "jrpc")) {
5423 do_jrpc(p, r);
5424 return;
5425 }
5426}
5427
5428/*------------------------------------------------------------------*/
5429
5430void show_custom_page(Param* pp, Return* r, const char *cookie_cpwd)
5431{
5432 int size, n_var, index, edit;
5433 char keypath[256], type[32], *p, *ps;
5434 char pwd[256], tail[256];
5435 HNDLE hDB, hkey;
5436 KEY key;
5437 char data[TEXT_SIZE];
5438
5439 std::string path = pp->getparam("page");
5440
5441 if (path[0] == 0) {
5442 show_error_404(r, "show_custom_page: Invalid custom page: \"page\" parameter is empty");
5443 return;
5444 }
5445
5446 if (strstr(path.c_str(), "..")) {
5447 std::string str;
5448 str += "Invalid custom page name \'";
5449 str += path;
5450 str += "\' contains \'..\'";
5451 show_error_404(r, str.c_str());
5452 return;
5453 }
5454
5455 if (strstr(path.c_str(), ".gif")) {
5456 show_custom_gif(r, path.c_str());
5457 return;
5458 }
5459
5460 if (strchr(path.c_str(), '.')) {
5461 show_custom_file(r, path.c_str());
5462 return;
5463 }
5464
5466
5467 std::string xpath = std::string("/Custom/") + path;
5468 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5469 if (!hkey) {
5470 xpath = std::string("/Custom/") + path + "&";
5471 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5472 if (!hkey) {
5473 xpath = std::string("/Custom/") + path + "!";
5474 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5475 }
5476 }
5477
5478 if (hkey) {
5479 char* ctext;
5480 int status;
5481
5483 assert(status == DB_SUCCESS);
5484 size = key.total_size;
5485 ctext = (char*)malloc(size);
5487 if (status != DB_SUCCESS) {
5488 std::string errtext = msprintf("show_custom_page: Error: db_get_data() for \"%s\" status %d", xpath.c_str(), status);
5489 show_error_404(r, errtext.c_str());
5490 free(ctext);
5491 return;
5492 }
5493
5494 std::string content_type = "text/html";
5495
5496 /* check for link */
5497 if (std::string(ctext).substr(0, 5) == "?cmd=") {
5498 redirect(r, ctext);
5499 free(ctext);
5500 return;
5501 }
5502
5503 /* check if filename */
5504 if (strchr(ctext, '\n') == 0) {
5505 std::string full_filename = add_custom_path(ctext);
5506 int fh = open(full_filename.c_str(), O_RDONLY | O_BINARY);
5507 if (fh < 0) {
5508 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", open() errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5509 show_error_404(r, str.c_str());
5510 free(ctext);
5511 return;
5512 }
5513 free(ctext);
5514 ctext = NULL;
5515 off_t off = lseek(fh, 0, SEEK_END);
5516 if (off < 0) {
5517 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", lseek(SEEK_END) errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5518 show_error_404(r, str.c_str());
5519 free(ctext);
5520 close(fh);
5521 return;
5522 }
5523 size_t size = off;
5524 lseek(fh, 0, SEEK_SET);
5525 ctext = (char*)malloc(size+1);
5526 ssize_t rd = read(fh, ctext, size);
5527 if (rd > 0) {
5528 ctext[rd] = 0; // make sure string is zero-terminated
5529 size = rd;
5530 } else {
5531 ctext[0] = 0;
5532 size = 0;
5533 }
5534 close(fh);
5535
5537 }
5538
5539 /* check for valid password */
5540 if (equal_ustring(pp->getparam("cmd"), "Edit")) {
5541 p = ps = ctext;
5542 n_var = 0;
5543 do {
5544 char format[256];
5545
5546 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5547 if (p == NULL)
5548 break;
5549 ps = strchr(p, '>') + 1;
5550
5551 if (pwd[0] && n_var == atoi(pp->getparam("index"))) {
5552 char str[256];
5553 size = NAME_LENGTH;
5554 mstrlcpy(str, path.c_str(), sizeof(str)); // FIXME: overflows "str"
5555 if (strlen(str)>0 && str[strlen(str)-1] == '&')
5556 str[strlen(str)-1] = 0;
5557 std::string ppath;
5558 ppath += "/Custom/Pwd/";
5559 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5560 ppath += pp->getparam("pnam");
5561 } else {
5562 ppath += str;
5563 }
5564 str[0] = 0;
5565 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
5566 if (!equal_ustring(cookie_cpwd, str)) {
5567 show_error_404(r, "show_custom_page: Invalid password!");
5568 free(ctext);
5569 return;
5570 } else
5571 break;
5572 }
5573
5574 n_var++;
5575 } while (p != NULL);
5576 }
5577
5578 /* process toggle command */
5579 if (equal_ustring(pp->getparam("cmd"), "Toggle")) {
5580
5581 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5582 std::string ppath;
5583 ppath += "/Custom/Pwd/";
5584 ppath += pp->getparam("pnam");
5585 std::string str;
5586 db_get_value_string(hDB, 0, ppath.c_str(), 0, &str, TRUE, 256);
5587 if (!equal_ustring(cookie_cpwd, str.c_str())) {
5588 show_error_404(r, "show_custom_page: Invalid password!");
5589 free(ctext);
5590 return;
5591 }
5592 }
5593 std::string podb = pp->getparam("odb");
5594 std::string::size_type pos = podb.find('[');
5595 if (pos != std::string::npos) {
5596 index = atoi(podb.substr(pos+1).c_str());
5597 podb.resize(pos);
5598 //printf("found index %d in [%s] [%s]\n", index, pp->getparam("odb"), podb.c_str());
5599 } else
5600 index = 0;
5601
5602 if (db_find_key(hDB, 0, podb.c_str(), &hkey)) {
5603 db_get_key(hDB, hkey, &key);
5604 memset(data, 0, sizeof(data));
5605 if (key.item_size <= (int)sizeof(data)) {
5606 size = sizeof(data);
5608 std::string data_str = db_sprintf(data, size, 0, key.type);
5609 if (atoi(data_str.c_str()) == 0)
5610 db_sscanf("1", data, &size, 0, key.type);
5611 else
5612 db_sscanf("0", data, &size, 0, key.type);
5614 }
5615 }
5616
5617 /* redirect (so that 'reload' does not toggle again) */
5618 redirect(r, path.c_str());
5619 free(ctext);
5620 return;
5621 }
5622
5623 /* HTTP header */
5624 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
5625 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5626 r->rsprintf("Content-Type: %s; charset=%s\r\n\r\n", content_type.c_str(), HTTP_ENCODING);
5627
5628 /* interprete text, replace <odb> tags with ODB values */
5629 p = ps = ctext;
5630 n_var = 0;
5631 do {
5632 char format[256];
5633 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5634 if (p != NULL)
5635 *p = 0;
5636 r->rsputs(ps);
5637
5638 if (p == NULL)
5639 break;
5640 ps = strchr(p + 1, '>') + 1;
5641
5642 show_odb_tag(pp, r, path.c_str(), keypath, format, n_var, edit, type, pwd, tail);
5643 n_var++;
5644
5645 } while (p != NULL);
5646
5647 if (equal_ustring(pp->getparam("cmd"), "Set") || pp->isparam("cbi")) {
5648 /* redirect (so that 'reload' does not change value) */
5649 r->reset();
5650 redirect(r, path.c_str());
5651 }
5652
5653 free(ctext);
5654 ctext = NULL;
5655 } else {
5656 std::string str = msprintf("Invalid custom page: Page \"%s\" not found in ODB", path.c_str());
5657 show_error_404(r, str.c_str());
5658 return;
5659 }
5660}
5661
5662/*------------------------------------------------------------------*/
5663
5665{
5666 char str[256];
5667 int c, n, a, f, d, q, x, r, ia, id, w;
5668 int i, size, status;
5670
5671 static char client_name[NAME_LENGTH];
5672 static HNDLE hconn = 0;
5673
5675
5676 /* find FCNA server if not specified */
5677 if (hconn == 0) {
5678 /* find client which exports FCNA function */
5679 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
5680 if (status == DB_SUCCESS) {
5681 for (i = 0;; i++) {
5684 break;
5685
5686 sprintf(str, "RPC/%d", RPC_CNAF16);
5688 if (status == DB_SUCCESS) {
5689 size = sizeof(client_name);
5690 db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
5691 break;
5692 }
5693 }
5694 }
5695
5696 if (client_name[0]) {
5697 status = cm_connect_client(client_name, &hconn);
5698 if (status != RPC_SUCCESS)
5699 hconn = 0;
5700 }
5701 }
5702
5703 /* header */
5704 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
5705 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5706 rr->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
5707
5708 rr->rsprintf("<html><head>\n");
5709 rr->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
5710 rr->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
5711 rr->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
5712 rr->rsprintf("<title>MIDAS CAMAC interface</title></head>\n");
5713 rr->rsprintf("<body><form method=\"GET\" action=\"CNAF\">\n\n");
5714
5715 /* title row */
5716
5717 size = sizeof(str);
5718 str[0] = 0;
5719 db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
5720
5721 rr->rsprintf("<table border=3 cellpadding=1>\n");
5722 rr->rsprintf("<tr><th colspan=3>MIDAS experiment \"%s\"", str);
5723
5724 if (client_name[0] == 0)
5725 rr->rsprintf("<th colspan=3 class=\"redLight\">No CAMAC server running</tr>\n");
5726 else if (hconn == 0)
5727 rr->rsprintf("<th colspan=3 class=\"redLight\">Cannot connect to %s</tr>\n", client_name);
5728 else
5729 rr->rsprintf("<th colspan=3>CAMAC server: %s</tr>\n", client_name);
5730
5731 /* default values */
5732 c = n = 1;
5733 a = f = d = q = x = 0;
5734 r = 1;
5735 ia = id = w = 0;
5736
5737 /*---- menu buttons ----*/
5738
5739 rr->rsprintf("<tr><td colspan=3>\n");
5740 rr->rsprintf("<input type=submit name=cmd value=Execute>\n");
5741
5742 rr->rsprintf("<td colspan=3>\n");
5743 rr->rsprintf("<input type=submit name=cmd value=ODB>\n");
5744 rr->rsprintf("<input type=submit name=cmd value=Status>\n");
5745 rr->rsprintf("<input type=submit name=cmd value=Help>\n");
5746 rr->rsprintf("</tr>\n\n");
5747
5748 /* header */
5749 rr->rsprintf("<tr><th>N");
5750 rr->rsprintf("<th>A");
5751 rr->rsprintf("<th>F");
5752 rr->rsprintf("<th colspan=3>Data");
5753
5754 /* execute commands */
5755 size = sizeof(d);
5756
5757 const char* cmd = p->getparam("cmd");
5758 if (equal_ustring(cmd, "C cycle")) {
5759 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5760 &q);
5761
5762 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">C cycle executed sucessfully</tr>\n");
5763 } else if (equal_ustring(cmd, "Z cycle")) {
5764 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_ZINIT, 0, 0, 0, 0, 0, &d, &size, &x,
5765 &q);
5766
5767 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">Z cycle executed sucessfully</tr>\n");
5768 } else if (equal_ustring(cmd, "Clear inhibit")) {
5769 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5770 &q);
5771
5772 rr->rsprintf
5773 ("<tr><td colspan=6 class=\"greenLight\">Clear inhibit executed sucessfully</tr>\n");
5774 } else if (equal_ustring(cmd, "Set inhibit")) {
5775 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_SET, 0, 0, 0, 0, 0, &d, &size, &x,
5776 &q);
5777
5778 rr->rsprintf
5779 ("<tr><td colspan=6 class=\"greenLight\">Set inhibit executed sucessfully</tr>\n");
5780 } else if (equal_ustring(cmd, "Execute")) {
5781 c = atoi(p->getparam("C"));
5782 n = atoi(p->getparam("N"));
5783 a = atoi(p->getparam("A"));
5784 f = atoi(p->getparam("F"));
5785 r = atoi(p->getparam("R"));
5786 w = atoi(p->getparam("W"));
5787 id = atoi(p->getparam("ID"));
5788 ia = atoi(p->getparam("IA"));
5789
5790 const char* pd = p->getparam("D");
5791 if (strncmp(pd, "0x", 2) == 0)
5792 sscanf(pd + 2, "%x", &d);
5793 else
5794 d = atoi(p->getparam("D"));
5795
5796 /* limit repeat range */
5797 if (r == 0)
5798 r = 1;
5799 if (r > 100)
5800 r = 100;
5801 if (w > 1000)
5802 w = 1000;
5803
5804 for (i = 0; i < r; i++) {
5805 status = SUCCESS;
5806
5807 if (hconn) {
5808 size = sizeof(d);
5809 status =
5810 rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x,
5811 &q);
5812
5813 if (status == RPC_NET_ERROR) {
5814 /* try to reconnect */
5815 //cm_disconnect_client(hconn, FALSE);
5816 status = cm_connect_client(client_name, &hconn);
5817 if (status != RPC_SUCCESS) {
5818 hconn = 0;
5819 client_name[0] = 0;
5820 }
5821
5822 if (hconn) {
5823 status = rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x, &q);
5824 }
5825 }
5826 }
5827
5828 if (status != SUCCESS) {
5829 rr->rsprintf
5830 ("<tr><td colspan=6 class=\"redLight\">Error executing function, code = %d</tr>",
5831 status);
5832 } else {
5833 rr->rsprintf("<tr align=center><td>%d", n);
5834 rr->rsprintf("<td>%d", a);
5835 rr->rsprintf("<td>%d", f);
5836 rr->rsprintf("<td colspan=3>%d / 0x%04X Q%d X%d", d, d, q, x);
5837 }
5838
5839 d += id;
5840 a += ia;
5841
5842 if (w > 0)
5843 ss_sleep(w);
5844 }
5845 }
5846
5847 /* input fields */
5848 rr->rsprintf
5849 ("<tr align=center><td><input type=text size=3 name=N value=%d>\n",
5850 n);
5851 rr->rsprintf("<td><input type=text size=3 name=A value=%d>\n", a);
5852 rr->rsprintf("<td><input type=text size=3 name=F value=%d>\n", f);
5853 rr->rsprintf
5854 ("<td colspan=3><input type=text size=8 name=D value=%d></tr>\n",
5855 d);
5856
5857 /* control fields */
5858 rr->rsprintf("<tr><td colspan=2>Repeat");
5859 rr->rsprintf("<td><input type=text size=3 name=R value=%d>\n", r);
5860
5861 rr->rsprintf
5862 ("<td align=center colspan=3><input type=submit name=cmd value=\"C cycle\">\n");
5863 rr->rsprintf("<input type=submit name=cmd value=\"Z cycle\">\n");
5864
5865 rr->rsprintf("<tr><td colspan=2>Repeat delay [ms]");
5866 rr->rsprintf("<td><input type=text size=3 name=W value=%d>\n", w);
5867
5868 rr->rsprintf
5869 ("<td align=center colspan=3><input type=submit name=cmd value=\"Set inhibit\">\n");
5870 rr->rsprintf("<input type=submit name=cmd value=\"Clear inhibit\">\n");
5871
5872 rr->rsprintf("<tr><td colspan=2>Data increment");
5873 rr->rsprintf("<td><input type=text size=3 name=ID value=%d>\n", id);
5874
5875 rr->rsprintf
5876 ("<td colspan=3 align=center>Branch <input type=text size=3 name=B value=0>\n");
5877
5878 rr->rsprintf("<tr><td colspan=2>A increment");
5879 rr->rsprintf("<td><input type=text size=3 name=IA value=%d>\n", ia);
5880
5881 rr->rsprintf
5882 ("<td colspan=3 align=center>Crate <input type=text size=3 name=C value=%d>\n",
5883 c);
5884
5885 rr->rsprintf("</table></body>\r\n");
5886}
5887
5888/*------------------------------------------------------------------*/
5889
5890#ifdef HAVE_MSCB
5891
5892typedef struct {
5893 signed char id;
5894 char name[32];
5895} NAME_TABLE;
5896
5897static const NAME_TABLE prefix_table[] = {
5898 {PRFX_PICO, "pico",},
5899 {PRFX_NANO, "nano",},
5900 {PRFX_MICRO, "micro",},
5901 {PRFX_MILLI, "milli",},
5902 {PRFX_NONE, "",},
5903 {PRFX_KILO, "kilo",},
5904 {PRFX_MEGA, "mega",},
5905 {PRFX_GIGA, "giga",},
5906 {PRFX_TERA, "tera",},
5907 {99}
5908};
5909
5910static const NAME_TABLE unit_table[] = {
5911
5912 {UNIT_METER, "meter",},
5913 {UNIT_GRAM, "gram",},
5914 {UNIT_SECOND, "second",},
5915 {UNIT_MINUTE, "minute",},
5916 {UNIT_HOUR, "hour",},
5917 {UNIT_AMPERE, "ampere",},
5918 {UNIT_KELVIN, "kelvin",},
5919 {UNIT_CELSIUS, "deg. celsius",},
5920 {UNIT_FARENHEIT, "deg. farenheit",},
5921
5922 {UNIT_HERTZ, "hertz",},
5923 {UNIT_PASCAL, "pascal",},
5924 {UNIT_BAR, "bar",},
5925 {UNIT_WATT, "watt",},
5926 {UNIT_VOLT, "volt",},
5927 {UNIT_OHM, "ohm",},
5928 {UNIT_TESLA, "tesls",},
5929 {UNIT_LITERPERSEC, "liter/sec",},
5930 {UNIT_RPM, "RPM",},
5931 {UNIT_FARAD, "farad",},
5932
5933 {UNIT_BOOLEAN, "boolean",},
5934 {UNIT_BYTE, "byte",},
5935 {UNIT_WORD, "word",},
5936 {UNIT_DWORD, "dword",},
5937 {UNIT_ASCII, "ascii",},
5938 {UNIT_STRING, "string",},
5939 {UNIT_BAUD, "baud",},
5940
5941 {UNIT_PERCENT, "percent",},
5942 {UNIT_PPM, "RPM",},
5943 {UNIT_COUNT, "counts",},
5944 {UNIT_FACTOR, "factor",},
5945 {0}
5946};
5947
5948/*------------------------------------------------------------------*/
5949
5950void print_mscb_var(char *value, char *evalue, char *unit, MSCB_INFO_VAR *info_chn, void *pdata)
5951{
5952 char str[80];
5953 signed short sdata;
5954 unsigned short usdata;
5955 signed int idata;
5956 unsigned int uidata;
5957 float fdata;
5958 int i;
5959
5960 value[0] = 0;
5961 evalue[0] = 0;
5962
5963 if (info_chn->unit == UNIT_STRING) {
5964 memset(str, 0, sizeof(str));
5965 strncpy(str, (char *)pdata, info_chn->width);
5966 for (i = 0; i < (int) strlen(str); i++)
5967 switch (str[i]) {
5968 case 1:
5969 strcat(value, "\\001");
5970 break;
5971 case 2:
5972 strcat(value, "\\002");
5973 break;
5974 case 9:
5975 strcat(value, "\\t");
5976 break;
5977 case 10:
5978 strcat(value, "\\n");
5979 break;
5980 case 13:
5981 strcat(value, "\\r");
5982 break;
5983 default:
5984 value[strlen(value) + 1] = 0;
5985 value[strlen(value)] = str[i];
5986 break;
5987 }
5988 mstrlcpy(evalue, value, 256);
5989 } else {
5990 switch (info_chn->width) {
5991 case 0:
5992 strcpy(value, "0");
5993 strcpy(evalue, "0");
5994 break;
5995
5996 case 1:
5997 if (info_chn->flags & MSCBF_SIGNED) {
5998 sprintf(value, "%d (0x%02X/", *((signed char *)pdata), *((signed char *)pdata));
5999 sprintf(evalue, "%d", *((signed char *)pdata));
6000 } else {
6001 sprintf(value, "%u (0x%02X/", *((unsigned char *)pdata), *((unsigned char *)pdata));
6002 sprintf(evalue, "%u", *((unsigned char *)pdata));
6003 }
6004
6005 for (i = 0; i < 8; i++)
6006 if (*((unsigned char *)pdata) & (0x80 >> i))
6007 sprintf(value + strlen(value), "1");
6008 else
6009 sprintf(value + strlen(value), "0");
6010 sprintf(value + strlen(value), ")");
6011 break;
6012
6013 case 2:
6014 if (info_chn->flags & MSCBF_SIGNED) {
6015 sdata = *((signed short *)pdata);
6016 WORD_SWAP(&sdata);
6017 sprintf(value, "%d (0x%04X)", sdata, sdata);
6018 sprintf(evalue, "%d", sdata);
6019 } else {
6020 usdata = *((unsigned short *)pdata);
6021 WORD_SWAP(&usdata);
6022 sprintf(value, "%u (0x%04X)", usdata, usdata);
6023 sprintf(evalue, "%u", usdata);
6024 }
6025 break;
6026
6027 case 4:
6028 if (info_chn->flags & MSCBF_FLOAT) {
6029 fdata = *((float *)pdata);
6030 DWORD_SWAP(&fdata);
6031 sprintf(value, "%1.6lg", fdata);
6032 sprintf(evalue, "%1.6lg", fdata);
6033 } else {
6034 if (info_chn->flags & MSCBF_SIGNED) {
6035 idata = *((signed int *)pdata);
6036 DWORD_SWAP(&idata);
6037 sprintf(value, "%d (0x%08X)", idata, idata);
6038 sprintf(evalue, "%d", idata);
6039 } else {
6040 uidata = *((unsigned int *)pdata);
6042 sprintf(value, "%u (0x%08X)", uidata, uidata);
6043 sprintf(evalue, "%u", uidata);
6044 }
6045 }
6046 break;
6047 }
6048 }
6049
6050 /* evaluate prefix */
6051 unit[0] = 0;
6052 if (info_chn->prefix) {
6053 for (i = 0; prefix_table[i].id != 99; i++)
6054 if ((unsigned char)prefix_table[i].id == info_chn->prefix)
6055 break;
6056 if (prefix_table[i].id)
6057 strcpy(unit, prefix_table[i].name);
6058 }
6059
6060 /* evaluate unit */
6061 if (info_chn->unit && info_chn->unit != UNIT_STRING) {
6062 for (i = 0; unit_table[i].id; i++)
6063 if ((unsigned char)unit_table[i].id == info_chn->unit)
6064 break;
6065 if (unit_table[i].id)
6067 }
6068}
6069
6070static int cmp_int(const void *a, const void *b)
6071{
6072 return *((int *)a) > *((int *)b);
6073}
6074
6075/*------------------------------------------------------------------*/
6076
6077void create_mscb_tree()
6078{
6080 KEY key;
6081 int i, j, k, l, size, address[1000], dev_badr[1000], dev_adr[1000], dev_chn[1000],
6083 char mscb_dev[256], mscb_pwd[32], eq_name[32];
6084
6086
6087 db_create_key(hDB, 0, "MSCB/Submaster", TID_KEY);
6088 db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6089 assert(hKeySubm);
6090
6091 /*---- go through equipment list ----*/
6092 db_find_key(hDB, 0, "Equipment", &hKeyEq);
6093 if (hKeyEq) {
6094 for (i=0 ; ; i++) {
6096 if (!hKey)
6097 break;
6098 db_get_key(hDB, hKey, &key);
6099 strcpy(eq_name, key.name);
6100 db_find_key(hDB, hKey, "Settings/Devices", &hKeyDev);
6101 if (hKeyDev) {
6102 for (j=0 ;; j++) {
6104 if (!hKey)
6105 break;
6106
6107 if (db_find_key(hDB, hKey, "MSCB Address", &hKeyAdr) == DB_SUCCESS) {
6108 /* mscbdev type of device */
6109 size = sizeof(mscb_dev);
6110 if (db_get_value(hDB, hKey, "Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6111 continue;
6112 size = sizeof(mscb_pwd);
6113 if (db_get_value(hDB, hKey, "Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6114 continue;
6115
6116 size = sizeof(dev_adr);
6118 n_dev_adr = size / sizeof(int);
6119 } else if (db_find_key(hDB, hKey, "Block Address", &hKeyAdr) == DB_SUCCESS) {
6120 /* mscbhvr type of device */
6121 size = sizeof(mscb_dev);
6122 if (db_get_value(hDB, hKey, "MSCB Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6123 continue;
6124 size = sizeof(mscb_pwd);
6125 if (db_get_value(hDB, hKey, "MSCB Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6126 continue;
6127
6128 n_dev_adr = 0;
6129 size = sizeof(dev_badr);
6131 size = sizeof(dev_chn);
6132 if (db_get_value(hDB, hKey, "Block Channels", dev_chn, &size, TID_INT, FALSE) == DB_SUCCESS) {
6133 for (k=0 ; k<size/(int)sizeof(int) && n_dev_adr < (int)(sizeof(dev_adr)/sizeof(int)) ; k++) {
6134 for (l=0 ; l<dev_chn[k] ; l++)
6135 dev_adr[n_dev_adr++] = dev_badr[k]+l;
6136 }
6137 }
6138 } else
6139 continue;
6140
6141 /* create or open submaster entry */
6143 if (!hKey) {
6146 assert(hKey);
6147 }
6148
6149 /* get old address list */
6150 size = sizeof(address);
6151 if (db_get_value(hDB, hKey, "Address", address, &size, TID_INT, FALSE) == DB_SUCCESS)
6152 n_address = size / sizeof(int);
6153 else
6154 n_address = 0;
6155
6156 /* merge with new address list */
6157 for (k=0 ; k<n_dev_adr ; k++) {
6158 for (l=0 ; l<n_address ; l++)
6159 if (address[l] == dev_adr[k])
6160 break;
6161
6162 if (l == n_address)
6163 address[n_address++] = dev_adr[k];
6164 }
6165
6166 /* sort address list */
6167 qsort(address, n_address, sizeof(int), cmp_int);
6168
6169 /* store new address list */
6170 db_set_value(hDB, hKey, "Pwd", mscb_pwd, 32, 1, TID_STRING);
6171 db_set_value(hDB, hKey, "Comment", eq_name, 32, 1, TID_STRING);
6172 db_set_value(hDB, hKey, "Address", address, n_address*sizeof(int), n_address, TID_INT);
6173 }
6174 }
6175 }
6176 }
6177}
6178
6179/*------------------------------------------------------------------*/
6180
6181void show_mscb_page(Param* p, Return* r, int refresh)
6182{
6183 int i, j, n, ind, fi, fd, status, size, n_addr, cur_node, adr, show_hidden;
6184 unsigned int uptime;
6186 float fvalue;
6187 char *pd;
6188 char dbuf[256], evalue[256], unit[256], cur_subm_name[256];
6190 KEY key;
6193 int ping_addr[0x10000];
6194
6196
6197 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6198 if (!hKeySubm)
6200
6201 mstrlcpy(cur_subm_name, p->getparam("subm"), sizeof(cur_subm_name));
6202 if (cur_subm_name[0] == 0) {
6204 if (!hKeyCurSubm) {
6205 char errorstr[256];
6206 sprintf(errorstr, "No submaster defined under /MSCB/Submaster");
6207 show_error(r, errorstr);
6208 return;
6209 }
6211 strcpy(cur_subm_name, key.name);
6212 } else
6214
6215 if (p->isparam("node"))
6216 cur_node = atoi(p->getparam("node"));
6217 else
6218 cur_node = -1;
6219
6220 /* perform MSCB rescan */
6221 if (p->isparam("mcmd") && equal_ustring(p->getparam("mcmd"), "Rescan") && p->isparam("subm")) {
6222 /* create Pwd and Comment if not there */
6223 char tmp[32];
6224 size = 32;
6225 tmp[0] = 0;
6226 db_get_value(hDB, hKeyCurSubm, "Pwd", (void *)tmp, &size, TID_STRING, true);
6227 tmp[0] = 0;
6228 db_get_value(hDB, hKeyCurSubm, "Comment", (void *)tmp, &size, TID_STRING, true);
6229
6230 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6231 std::vector<int> addr;
6232 std::vector<char> node_comment;
6233 if (hKeyAddr) {
6234 /* get current address array */
6237 addr.resize(n_addr);
6238 size = sizeof(int)*n_addr;
6239 db_get_data(hDB, hKeyAddr, addr.data(), &size, TID_INT);
6240 } else {
6241 /* create new address array */
6242 db_create_key(hDB, hKeyCurSubm, "Address", TID_INT);
6243 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6244 n_addr = 0;
6245 addr.resize(1);
6246 }
6247
6249 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6250 if (hKeyComm) {
6251 /* get current node comments */
6253 node_comment.resize(32*key.num_values);
6254 size = 32*key.num_values;
6256 } else {
6257 /* create new comment array */
6258 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6259 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6260 node_comment.resize(32);
6262 }
6263
6264 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6265 if (fd >= 0) {
6266 /* fill table of possible addresses */
6267 for (i=0 ; i<0x10000 ; i++)
6268 ping_addr[i] = 0;
6269 for (i=0 ; i<1000 ; i++) // 0..999
6270 ping_addr[i] = 1;
6271 for (i=0 ; i<0x10000 ; i+=100) // 100, 200, ...
6272 ping_addr[i] = 1;
6273 for (i=0 ; i<0x10000 ; i+= 0x100)
6274 ping_addr[i] = 1; // 256, 512, ...
6275 for (i=0xFF00 ; i<0x10000 ; i++)
6276 ping_addr[i] = 1; // 0xFF00-0xFFFF
6277
6278 for (ind = n = 0; ind < 0x10000; ind++) {
6279 if (!ping_addr[ind])
6280 continue;
6281
6282 status = mscb_ping(fd, (unsigned short) ind, 1, 0);
6283 if (status == MSCB_SUCCESS) {
6284
6285 /* node found, search next 100 as well */
6286 for (j=ind; j<ind+100 && j<0x10000 ; j++)
6287 if (j >= 0)
6288 ping_addr[j] = 1;
6289
6290 status = mscb_info(fd, (unsigned short) ind, &info);
6291
6292 if (status == MSCB_SUCCESS) {
6293 /* check if node already in list */
6294 for (j=0 ; j<n_addr ; j++)
6295 if (addr[j] == ind)
6296 break;
6297 if (j == n_addr) {
6298 addr.resize(n_addr+1);
6299 addr[n_addr] = ind;
6300 node_comment.resize(32*(n_addr+1));
6301 /* use node name as default comment */
6302 strncpy(node_comment.data()+n_addr*32, info.node_name, 32);
6303 n_addr ++;
6304 } else if (comment_created) {
6305 node_comment.resize(32*n_addr);
6306 /* use node name as default comment */
6307 strncpy(node_comment.data()+j*32, info.node_name, 32);
6308 }
6309 }
6310 }
6311 }
6312
6313 db_set_data(hDB, hKeyAddr, addr.data(), n_addr*sizeof(int), n_addr, TID_INT);
6315
6316 char redirstr[512];
6317 sprintf(redirstr, "?cmd=mscb&subm=%s", cur_subm_name);
6318 redirect(r, redirstr);
6319 return;
6320
6321 } else {
6322 char errorstr[512];
6323 sprintf(errorstr, "Cannot talk to submaster \"%s\"", cur_subm_name);
6324 show_error(r, errorstr);
6325 return;
6326 }
6327 }
6328
6329 /* write data to node */
6330 if (p->isparam("subm") && p->isparam("node") &&
6331 p->isparam("idx") && p->isparam("value")) {
6332 i = atoi(p->getparam("idx"));
6333 char value[256];
6334 mstrlcpy(value, p->getparam("value"), sizeof(value));
6335
6336 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6337 if (fd >= 0) {
6339 (unsigned short) cur_node, (unsigned char) i, &info_var);
6340 if (status == MSCB_SUCCESS) {
6341 if (info_var.unit == UNIT_STRING) {
6342 char valstr[256];
6343 mstrlcpy(valstr, value, sizeof(valstr));
6344 if (strlen(valstr) > 0 && valstr[strlen(valstr) - 1] == '\n')
6345 valstr[strlen(valstr) - 1] = 0;
6346
6347 status = mscb_write(fd, (unsigned short) cur_node,
6348 (unsigned char) i, valstr, strlen(valstr) + 1);
6349 } else {
6350 if (info_var.flags & MSCBF_FLOAT) {
6351 fvalue = (float) atof(value);
6352 memcpy(&dbuf, &fvalue, sizeof(float));
6353 } else {
6354 if (value[1] == 'x')
6355 sscanf(value + 2, "%x", (int *)&dbuf);
6356 else
6357 *((int *)dbuf) = atoi(value);
6358 }
6359
6360 status = mscb_write(fd, (unsigned short) cur_node,
6361 (unsigned char) i, dbuf, info_var.width);
6362 }
6363 }
6364 }
6365 char redirstr[512];
6366 sprintf(redirstr, "?cmd=mscb&subm=%s&node=%d", cur_subm_name, cur_node);
6367 redirect(r, redirstr);
6368 return;
6369 }
6370
6371 if (p->isparam("hidden"))
6372 show_hidden = atoi(p->getparam("hidden"));
6373 else
6375
6376 show_header(r, "MSCB", "GET", "./", refresh);
6377 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6378 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6379 show_navigation_bar(r, "MSCB");
6380
6381 /* style sheet */
6382 r->rsprintf("<style type=\"text/css\">\r\n");
6383 r->rsprintf("select { width:150px; background-color:#FFFFE0; font-size:12px; }\r\n");
6384 r->rsprintf(".subm {\r\n");
6385 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6386 r->rsprintf(" padding:5px;\r\n");
6387 r->rsprintf(" vertical-align:top;\r\n");
6388 r->rsprintf(" font-size:16px;\r\n");
6389 r->rsprintf(" border-right:1px solid #808080;\r\n");
6390 r->rsprintf("}\r\n");
6391 r->rsprintf(".node {\r\n");
6392 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6393 r->rsprintf(" padding:5px;\r\n");
6394 r->rsprintf(" vertical-align:top;\r\n");
6395 r->rsprintf(" font-size:16px;\r\n");
6396 r->rsprintf(" border-right:1px solid #808080;\r\n");
6397 r->rsprintf("}\r\n");
6398 r->rsprintf(".vars {\r\n");
6399 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6400 r->rsprintf(" padding:5px;\r\n");
6401 r->rsprintf(" vertical-align:top;\r\n");
6402 r->rsprintf(" font-size:10px;\r\n");
6403 r->rsprintf("}\r\n");
6404 r->rsprintf(".v1 {\r\n");
6405 r->rsprintf(" padding:3px;\r\n");
6406 r->rsprintf(" font-weight:bold;\r\n");
6407 r->rsprintf(" font-size:12px;\r\n");
6408 r->rsprintf("}\r\n");
6409 r->rsprintf(".v2 {\r\n");
6410 r->rsprintf(" background-color:#F0F0F0;\r\n");
6411 r->rsprintf(" padding:3px;\r\n");
6412 r->rsprintf(" font-size:12px;\r\n");
6413 r->rsprintf(" border:1px solid #808080;\r\n");
6414 r->rsprintf(" border-right:1px solid #FFFFFF;\r\n");
6415 r->rsprintf(" border-bottom:1px solid #FFFFFF;\r\n");
6416 r->rsprintf("}\r\n");
6417 r->rsprintf(".v3 {\r\n");
6418 r->rsprintf(" padding:3px;\r\n");
6419 r->rsprintf(" font-size:12px;\r\n");
6420 r->rsprintf("}\r\n");
6421 r->rsprintf("</style>\r\n\r\n");
6422
6423 /* javascript */
6424 r->rsprintf("<script type=\"text/javascript\">\r\n");
6425 r->rsprintf("function mscb_edit(index, value)\r\n");
6426 r->rsprintf("{\r\n");
6427 r->rsprintf(" var new_value = prompt('Please enter new value', value);\r\n");
6428 r->rsprintf(" if (new_value != undefined) {\r\n");
6429 r->rsprintf(" window.location.search = '?cmd=mscb&subm=%s&node=%d&idx='+index+'&value='+new_value;\n", cur_subm_name, cur_node);
6430 r->rsprintf(" }\n");
6431 r->rsprintf("}\r\n");
6432 r->rsprintf("</script>\r\n\r\n");
6433
6434 /*---- main content ----*/
6435
6436 r->rsprintf("<table class=\"mtable\">"); //main table
6437 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>MSCB</th><tr>");
6438
6439 /*---- menu buttons ----*/
6440
6441 r->rsprintf("<tr><td colspan=2>\n");
6442 r->rsprintf("<table width=100%%><tr>\n");
6443 r->rsprintf("<td><input type=button value=Reload onclick=\"window.location.search='?cmd=mscb&subm=%s&node=%d&rnd=%d'\"></td>\n", cur_subm_name, cur_node, rand());
6444
6445 r->rsprintf("<tr><td colspan=\"2\" cellpadding=\"0\" cellspacing=\"0\">\r\n");
6446
6447 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6448 if (status != DB_SUCCESS) {
6449 r->rsprintf("<h1>No MSCB Submasters defined in ODB</h1>\r\n");
6450 r->rsprintf("</td></tr>\r\n");
6451 r->rsprintf("</table>\r\n"); //submaster table
6452 r->rsprintf("</td></tr>\r\n");
6453 r->rsprintf("</table>\r\n"); //main table
6454 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6455 r->rsprintf("</form>\n");
6456 r->rsprintf("</body></html>\r\n");
6457 return;
6458 }
6459
6460 r->rsprintf("<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"0\">");
6461
6462 /*---- submaster list ----*/
6463 r->rsprintf("<tr><td class=\"subm\">\r\n");
6464 r->rsprintf("Submaster<hr>\r\n");
6465
6466 /* count submasters */
6467 for (i = 0;;i++) {
6469 if (!hKey)
6470 break;
6471 }
6472 if (i<2)
6473 i = 2;
6474
6475 r->rsprintf("<select name=\"subm\" id=\"subm\" size=%d ", i);
6476 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm='+document.getElementById('subm').value;\">\r\n");
6477 hKeyCurSubm = 0;
6478 for (i = 0;;i++) {
6480 if (!hKey)
6481 break;
6482 db_get_key(hDB, hKey, &key);
6483 char str[NAME_LENGTH+10+256];
6484 mstrlcpy(str, key.name, sizeof(str));
6485 char comment[256];
6486 size = sizeof(comment);
6487 if (db_get_value(hDB, hKey, "Comment", comment, &size, TID_STRING, FALSE) == DB_SUCCESS) {
6488 mstrlcat(str, ": ", sizeof(str));
6489 mstrlcat(str, comment, sizeof(str));
6490 }
6491
6493 (cur_subm_name[0] == 0 && i == 0)) {
6494 r->rsprintf("<option value=\"%s\" selected>%s</option>\r\n", key.name, str);
6495 hKeyCurSubm = hKey;
6496 } else
6497 r->rsprintf("<option value=\"%s\">%s</option>\r\n", key.name, str);
6498 }
6499 r->rsprintf("</select>\r\n");
6500
6501 /*---- node list ----*/
6502 r->rsprintf("<td class=\"node\">\r\n");
6503 r->rsprintf("Node ");
6504
6505 r->rsprintf("<script type=\"text/javascript\">\n");
6506 r->rsprintf("<!--\n");
6507 r->rsprintf("function rescan()\n");
6508 r->rsprintf("{\n");
6509 r->rsprintf(" flag = confirm('Rescan can take up to one minute.');\n");
6510 r->rsprintf(" if (flag == true)\n");
6511 r->rsprintf(" window.location.href = '?cmd=mscb&mcmd=Rescan&subm=%s';\n", cur_subm_name);
6512 r->rsprintf("}\n");
6513 r->rsprintf("//-->\n");
6514 r->rsprintf("</script>\n");
6515
6516 r->rsprintf("<input type=button name=cmd value=\"Rescan\" onClick=\"rescan();\">");
6517 r->rsprintf("<hr>\r\n");
6518
6519 if (!hKeyCurSubm) {
6520 r->rsprintf("No submaster found in ODB\r\n");
6521 r->rsprintf("</td></tr>\r\n");
6522 r->rsprintf("</table>\r\n"); //inner submaster table
6523 r->rsprintf("</td></tr>\r\n");
6524 r->rsprintf("</table>\r\n"); //submaster table
6525 r->rsprintf("</td></tr>\r\n");
6526 r->rsprintf("</table>\r\n"); //main table
6527 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6528 r->rsprintf("</form>\n");
6529 r->rsprintf("</body></html>\r\n");
6530 return;
6531 }
6532
6533 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6534 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6535
6536 i = 10;
6537 if (hKeyAddr) {
6539 i = key.num_values;
6540
6541 if (hKeyComm == 0) {
6542 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6543 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6544 }
6546 if (key.num_values < i) {
6547 char str[32] = "";
6548 for (int j=key.num_values ; j<i ; j++)
6550 }
6551 }
6552 if (i < 2)
6553 i = 2;
6554
6555 r->rsprintf("<select name=\"node\" id=\"node\" size=%d ", i);
6556 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm=%s&node='+document.getElementById('node').value;\">\r\n", cur_subm_name);
6557
6558 if (hKeyAddr) {
6560 size = sizeof(adr);
6561
6562 /* check if current node is in list */
6563 for (i = 0; i<key.num_values ;i++) {
6564 size = sizeof(adr);
6565 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6566 if (adr == cur_node)
6567 break;
6568 }
6569 if (i == key.num_values) // if not found, use first one in list
6571
6572 for (i = 0; i<key.num_values ;i++) {
6573 char str[100+256];
6574 size = sizeof(adr);
6575 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6576 if (hKeyComm) {
6577 char comment[256];
6578 size = sizeof(comment);
6579 db_get_data_index(hDB, hKeyComm, comment, &size, i, TID_STRING);
6580 sprintf(str, "%d: %s", adr, comment);
6581 } else {
6582 sprintf(str, "%d", adr);
6583 }
6584 if (cur_node == 0 && i == 0)
6585 cur_node = adr;
6586 if (adr == cur_node)
6587 r->rsprintf("<option selected>%s</option>\r\n", str);
6588 else
6589 r->rsprintf("<option>%s</option>\r\n", str);
6590 }
6591 }
6592 r->rsprintf("</select>\r\n");
6593
6594 /*---- node contents ----*/
6595 r->rsprintf("<td class=\"vars\">\r\n");
6596 r->rsprintf("<table>\r\n");
6598 if (cur_node != -1)
6599 r->rsprintf("<tr><td colspan=3 align=center><b>%s:%d</b>", key.name, cur_node);
6600 else
6601 r->rsprintf("<tr><td colspan=3 align=center><b>%s</b>", key.name);
6602 r->rsprintf("<hr></td></tr>\r\n");
6603
6604 char passwd[32];
6605 passwd[0] = 0;
6606 size = 32;
6607 db_get_value(hDB, hKeyCurSubm, "Pwd", passwd, &size, TID_STRING, TRUE);
6608
6609 fd = mscb_init(key.name, 0, passwd, FALSE);
6610 if (fd < 0) {
6611 if (fd == EMSCB_WRONG_PASSWORD)
6612 r->rsprintf("<tr><td colspan=3><b>Invalid password</b></td>");
6613 else
6614 r->rsprintf("<tr><td colspan=3><b>Submaster does not respond</b></td>");
6615 goto mscb_error;
6616 }
6619
6620 status = mscb_ping(fd, cur_node, 0, 1);
6621 if (status != MSCB_SUCCESS) {
6622 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6623 goto mscb_error;
6624 }
6625 status = mscb_info(fd, (unsigned short) cur_node, &info);
6626 if (status != MSCB_SUCCESS) {
6627 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6628 goto mscb_error;
6629 }
6630 char tr16[17];
6631 mstrlcpy(tr16, info.node_name, sizeof(tr16));
6632 r->rsprintf("<tr><td class=\"v1\">Node name<td colspan=2 class=\"v2\">%s</tr>\n", tr16);
6633 r->rsprintf("<tr><td class=\"v1\">GIT revision<td colspan=2 class=\"v2\">%d</tr>\n", info.revision);
6634
6635 if (info.rtc[0] && info.rtc[0] != 0xFF) {
6636 for (i=0 ; i<6 ; i++)
6637 info.rtc[i] = (info.rtc[i] / 0x10) * 10 + info.rtc[i] % 0x10;
6638 r->rsprintf("<tr><td class=\"v1\">Real Time Clock<td colspan=2 class=\"v2\">%02d-%02d-%02d %02d:%02d:%02d</td>\n",
6639 info.rtc[0], info.rtc[1], info.rtc[2],
6640 info.rtc[3], info.rtc[4], info.rtc[5]);
6641 }
6642
6643 status = mscb_uptime(fd, (unsigned short) cur_node, &uptime);
6644 if (status == MSCB_SUCCESS)
6645 r->rsprintf("<tr><td class=\"v1\">Uptime<td colspan=2 class=\"v2\">%dd %02dh %02dm %02ds</tr>\n",
6646 uptime / (3600 * 24),
6647 (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
6648 (uptime % 60));
6649
6650 r->rsprintf("<tr><td colspan=3><hr></td></tr>\r\n");
6651
6652 /* check for hidden variables */
6653 for (i=0 ; i < info.n_variables ; i++) {
6655 if (info_var.flags & MSCBF_HIDDEN)
6656 break;
6657 }
6658 if (i < info.n_variables) {
6659 char str[32];
6660 strcpy(str, show_hidden ? " checked" : "");
6661 r->rsprintf("<tr><td colspan=3><input type=checkbox%s name=\"hidden\" value=\"1\"", str);
6662 r->rsprintf("onChange=\"window.location.search=?cmd=mscb&subm=%s&node=%d&hidden=1\">Display hidden variables<hr></td></tr>\r\n", cur_subm_name, cur_node);
6663 }
6664
6665 /* read variables in blocks of 100 bytes */
6666 for (fi=0 ; fi < info.n_variables ; ) {
6667 for (i=fi,size=0 ; i < info.n_variables && size < 100; i++) {
6669 size += info_var.width;
6670 }
6671
6672 size = sizeof(dbuf);
6673 status = mscb_read_range(fd, cur_node, fi, i-1, dbuf, &size);
6674 if (status != MSCB_SUCCESS) {
6675 r->rsprintf("<tr><td colspan=3><b>Error reading data from node</b></td>");
6676 goto mscb_error;
6677 }
6678 pd = dbuf;
6679
6680 for (j=fi ; j<i ; j++) {
6682 if ((info_var.flags & MSCBF_HIDDEN) == 0 || show_hidden) {
6683 char tr8[9];
6684 mstrlcpy(tr8, info_var.name, sizeof(tr8));
6685 r->rsprintf("<tr><td class=\"v1\">%s</td>\r\n", tr8);
6686 r->rsprintf("<td class=\"v2\">\r\n");
6687 char value[256];
6689 r->rsprintf("<a href=\"#\" onClick=\"mscb_edit(%d,'%s')\">%s</a>",
6690 j, evalue, value);
6691 r->rsprintf("</td><td class=\"v3\">%s</td>", unit);
6692 r->rsprintf("</tr>\r\n");
6693 }
6694 pd += info_var.width;
6695 }
6696
6697 fi = i;
6698 }
6699
6701 r->rsprintf("</tr></table>\r\n");
6702 r->rsprintf("</td></tr></table>\r\n");
6703 r->rsprintf("</td></tr></table>\r\n");
6704 r->rsprintf("</td></tr></table>\r\n");
6705 r->rsprintf("</div></body></html>\r\n");
6706}
6707
6708#endif // HAVE_MSCB
6709
6710/*------------------------------------------------------------------*/
6711
6712void show_password_page(Return* r, const char* dec_path, const char *password)
6713{
6714 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6715 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6716 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6717
6718 r->rsprintf("<html><head>\n");
6719 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6720 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6721 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6722 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6723
6724 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6725
6726 /*---- page header ----*/
6727 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6728
6729 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6730 if (password[0])
6731 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6732
6733 r->rsprintf("<tr><th>Please enter password</tr>\n");
6734 r->rsprintf("<tr><td align=center><input type=password name=pwd></tr>\n");
6735 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6736
6737 r->rsprintf("</table>\n");
6738
6739 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6740 r->rsprintf("</form>\n");
6741 r->rsprintf("</body></html>\r\n");
6742}
6743
6744/*------------------------------------------------------------------*/
6745
6746BOOL check_web_password(Return* r, HNDLE hDB, const char* dec_path, const char *password, const char *redir)
6747{
6748 HNDLE hkey;
6749 INT size;
6750 char str[256];
6751
6752 /* check for password */
6753 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
6754 if (hkey) {
6755 size = sizeof(str);
6756 db_get_data(hDB, hkey, str, &size, TID_STRING);
6757 if (strcmp(password, str) == 0)
6758 return TRUE;
6759
6760 /* show web password page */
6761 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6762 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6763 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6764
6765 r->rsprintf("<html><head>\n");
6766 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6767 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6768 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6769 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6770
6771 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6772
6773 /* define hidden fields for current experiment and destination */
6774 if (redir[0])
6775 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", redir);
6776
6777 /*---- page header ----*/
6778 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6779
6780 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6781
6782 if (password[0])
6783 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6784
6785 r->rsprintf
6786 ("<tr><th>Please enter password to obtain write access</tr>\n");
6787 r->rsprintf("<tr><td align=center><input type=password name=wpwd></tr>\n");
6788 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6789
6790 r->rsprintf("</table>\n");
6791
6792 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6793 r->rsprintf("</form>\n");
6794 r->rsprintf("</body></html>\r\n");
6795
6796 return FALSE;
6797 } else
6798 return TRUE;
6799}
6800
6801/*------------------------------------------------------------------*/
6802
6803void show_odb_page(Param* pp, Return* r, const char* dec_path, int write_access)
6804{
6805 int keyPresent, size, status, line, link_index;
6806 char colspan;
6807 char style[32];
6809 KEY key;
6810 DWORD delta;
6811
6813
6814 //printf("path [%s]\n", dec_path);
6815
6816 if (strcmp(dec_path, "root") == 0) {
6817 dec_path = "";
6818 }
6819
6820 char xdecpath[256];
6822 if (strrchr(xdecpath, '/'))
6823 mstrlcpy(xdecpath, strrchr(xdecpath, '/')+1, sizeof(xdecpath));
6824 if (xdecpath[0] == 0)
6825 mstrlcpy(xdecpath, "root", sizeof(xdecpath));
6826 show_header(r, "MIDAS online database", "", xdecpath, 0);
6827
6828 /* use javascript file */
6829 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6830 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6831 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
6832 r->rsprintf("<script type=\"text/javascript\" src=\"controls.js\"></script>\n");
6833
6834 /* find key via path */
6836 if (status != DB_SUCCESS) {
6837 r->rsprintf("Error: cannot find key %s<P>\n", dec_path);
6838 r->rsprintf("</body></html>\r\n");
6839 return;
6840 }
6841
6842 char xdec_path[MAX_ODB_PATH];
6843
6844 /* if key is not of type TID_KEY, cut off key name */
6846 if (key.type != TID_KEY) {
6848
6849 /* strip variable name from path */
6850 char* p = xdec_path + strlen(xdec_path) - 1;
6851 while (*p && *p != '/')
6852 *p-- = 0;
6853 if (*p == '/')
6854 *p = 0;
6855
6857 if (status != DB_SUCCESS) {
6858 r->rsprintf("Error: cannot find key %s<P>\n", xdec_path);
6859 r->rsprintf("</body></html>\r\n");
6860 return;
6861 }
6862
6864 }
6865
6866 //mstrlcpy(enc_path, dec_path, enc_path_size);
6867 //urlEncode(enc_path, enc_path_size);
6868
6869 std::string odbpath = db_get_path(hDB, hkeyroot);
6870
6871 /*---- navigation bar ----*/
6872
6873 colspan = 7;
6874
6875 if (elog_mode) {
6876 r->rsprintf("<table class=\"mtableheader\">\n");
6877 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6878 r->rsprintf("<input type=button value=ELog onclick=\"self.location=\'?cmd=Alarms\';\">\n");
6879 r->rsprintf("</td></tr></table>\n\n");
6880 } else
6881 show_navigation_bar(r, "ODB");
6882
6883 /*---- begin ODB directory table ----*/
6884
6885 r->rsprintf("<table class=\"mtable\" style=\"border-spacing:0px;\">\n");
6886 r->rsprintf("<tr><th colspan=%d class=\"mtableheader\">Online Database Browser</tr>\n", colspan);
6887 //buttons:
6888 if(!elog_mode){
6889 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6890 r->rsprintf("<input type=button value=Find onclick=\"self.location=\'?cmd=Find\';\">\n");
6891 r->rsprintf("<input type=button value=Create onclick=\"dlgShow('dlgCreate')\">\n");
6892 r->rsprintf("<input type=button value=Link onclick=\"dlgShow('dlgLink')\">\n");
6893 r->rsprintf("<input type=button value=Delete onclick=\"dlgShow('dlgDelete')\">\n");
6894 r->rsprintf("<input type=button value=\"Create Elog from this page\" onclick=\"self.location=\'?cmd=Create Elog from this page&odb_path=%s\';\">\n", urlEncode(odbpath.c_str()).c_str());
6895 r->rsprintf("<input type=button value=\"Show open records\" onclick=\"self.location=\'?cmd=odb_sor&odb_path=%s\';\">\n", urlEncode(odbpath.c_str()).c_str());
6896 r->rsprintf("<input type=button value=\"Show ODB clients\" onclick=\"self.location=\'?cmd=odb_scl\';\">\n");
6897 r->rsprintf("</td></tr>\n");
6898 }
6899
6900 /*---- Build the Delete dialog------------------------------------*/
6901
6902 std::string dd = "";
6903
6904 dd += "<!-- Demo dialog -->\n";
6905 dd += "<div id=\"dlgDelete\" class=\"dlgFrame\">\n";
6906 dd += "<div class=\"dlgTitlebar\">Delete ODB entry</div>\n";
6907 dd += "<div class=\"dlgPanel\">\n";
6908 dd += "<div id=odbpath>";
6909 dd += "\"";
6910 dd += MJsonNode::Encode(odbpath.c_str());
6911 dd += "\"";
6912 dd += "</div>\n";
6913 dd += "<div><br></div>\n";
6914
6915 dd += "<table class=\"dialogTable\">\n";
6916 dd += "<th colspan=2>Delete ODB entries:</th>\n";
6917
6918 std::vector<std::string> delete_list;
6919
6920 int count_delete = 0;
6921
6922 /*---- ODB display -----------------------------------------------*/
6923
6924 /* display root key */
6925 r->rsprintf("<tr><td colspan=%d class='ODBpath'><b>", colspan);
6926 r->rsprintf("<a href=\"?cmd=oldodb\">/</a> \n");
6927
6928 std::string enc_root_path;
6929
6930 /*---- display path ----*/
6931 {
6932 const char* p = dec_path;
6933 while (*p) {
6934 std::string pd;
6935 while (*p && *p != '/')
6936 pd += *p++;
6937
6938 enc_root_path += urlEncode(pd.c_str());
6939
6940 if (pd.length() > 0)
6941 r->rsprintf("<a href=\"?cmd=oldodb&odb_path=%s\">%s</a>\n / ", enc_root_path.c_str(), pd.c_str());
6942
6943 enc_root_path += "/";
6944 if (*p == '/')
6945 p++;
6946 }
6947 }
6948
6949 r->rsprintf("</b></tr>\n");
6950
6951 /* enumerate subkeys */
6952 keyPresent = 0;
6953 for(int scan=0; scan<2; scan++){
6954 if(scan==1 && keyPresent==1) {
6955 r->rsprintf("<tr class=\"titleRow\">\n");
6956 r->rsprintf("<th class=\"ODBkey\">Key</th>\n");
6957 r->rsprintf("<th class=\"ODBvalue\">Value&nbsp;");
6958 r->rsprintf("<script type=\"text/javascript\">\n");
6959 r->rsprintf("function expand()\n");
6960 r->rsprintf("{\n");
6961 r->rsprintf(" var n = document.getElementsByName('ext');\n");
6962 r->rsprintf(" for (i=0 ; i<n.length ; i++) {\n");
6963 r->rsprintf(" if (n[i].style.display == 'none')\n");
6964 r->rsprintf(" n[i].style.display = 'table-cell';\n");
6965 r->rsprintf(" else\n");
6966 r->rsprintf(" n[i].style.display = 'none';\n");
6967 r->rsprintf(" }\n");
6968 r->rsprintf(" if (document.getElementById('expp').expflag === true) {\n");
6969 r->rsprintf(" document.getElementById('expp').expflag = false;\n");
6970 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E5;';\n");
6971 r->rsprintf(" } else {\n");
6972 r->rsprintf(" document.getElementById('expp').expflag = true;\n");
6973 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E4;';\n");
6974 r->rsprintf(" }\n");
6975 r->rsprintf("}\n");
6976 r->rsprintf("</script>");
6977 r->rsprintf("<div style=\"display:inline;float:right\"><a id=\"expp\"href=\"#\" onClick=\"expand();return false;\">&#x21E5;</div>");
6978 r->rsprintf("</th>\n");
6979 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Type</th>\n");
6980 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">#Val</th>\n");
6981 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Size</th>\n");
6982 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Written</th>\n");
6983 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Mode</th>\n");
6984 r->rsprintf("</tr>\n");
6985 }
6986 line = 0;
6987 for (int i = 0;; i++) {
6989 if (!hkey)
6990 break;
6991 db_get_link(hDB, hkey, &key);
6992
6993 if (scan == 0) {
6994 delete_list.push_back(key.name);
6995 }
6996
6997 if (line % 2 == 0)
6998 mstrlcpy(style, "ODBtableEven", sizeof(style));
6999 else
7000 mstrlcpy(style, "ODBtableOdd", sizeof(style));
7001
7002 std::string keyname = key.name;
7003 std::string enc_keyname = urlEncode(key.name);
7004
7005 std::string enc_full_path = enc_root_path + enc_keyname;
7006
7007 std::string odb_path = dec_path;
7008 if (odb_path.length() > 0 && odb_path[odb_path.length() - 1] != '/')
7009 odb_path += "/";
7010 odb_path += key.name;
7011
7012 /* resolve links */
7013 std::string enc_link_ref;
7014 char link_name[MAX_ODB_PATH];
7015 link_name[0] = 0;
7017 if (key.type == TID_LINK) {
7018 size = sizeof(link_name);
7020
7022
7023 if (status == DB_SUCCESS)
7024 db_get_key(hDB, hkey, &key);
7025
7026 //sprintf(link_ref, "?cmd=Set&odb_path=%s", full_path);
7027 enc_link_ref = "?cmd=Set&odb_path=";
7029
7030 if (status == DB_SUCCESS && link_name[0] == 0) {
7031 // fake the case when an empty link somehow resolves
7032 sprintf(link_name, "%s", "(empty)");
7033 }
7034 }
7035
7036 std::string enc_ref;
7037
7038 if (link_name[0]) {
7039 if (enc_root_path.back() == '/' && link_name[0] == '/') {
7040 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name+1);
7041 enc_ref = "";
7042 enc_ref += "?cmd=Set&odb_path=";
7044 enc_ref += urlEncode(link_name + 1);
7045 } else {
7046 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name);
7047 enc_ref = "";
7048 enc_ref += "?cmd=Set&odb_path=";
7051 }
7052 } else {
7053 //sprintf(ref, "?cmd=Set&odb_path=%s", full_path);
7054 enc_ref = "";
7055 enc_ref += "?cmd=Set&odb_path=";
7057 }
7058
7059 if (status != DB_SUCCESS) {
7060 if (scan == 1) {
7061 r->rsprintf("<tr><td class=\"yellowLight\">");
7062 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)");
7063 }
7064 } else {
7065
7066 if (key.type == TID_KEY && scan == 0) {
7067 /* for keys, don't display data value */
7068 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());
7069 if (link_name[0])
7070 r->rsprintf("<i>&rarr; <a href=\"%s\">%s</a></i>", enc_link_ref.c_str(), link_name);
7071 r->rsprintf("</tr>\n");
7072 } else if(key.type != TID_KEY && scan == 1) {
7073
7074 if (strchr(link_name, '['))
7075 link_index = atoi(strchr(link_name, '[')+1);
7076 else
7077 link_index = -1;
7078
7079 /* display single value */
7080 if (key.num_values == 1 || link_index != -1) {
7081 char data[TEXT_SIZE];
7082 size = sizeof(data);
7083 db_get_data(hDB, hkey, data, &size, key.type);
7084
7085 std::string data_str;
7086
7087 if (link_index != -1)
7089 else
7091
7092 if (key.type == TID_STRING) {
7093 if (size == sizeof(data)) {
7094 data_str += "...(truncated)";
7095 }
7096 }
7097
7098 std::string hex_str;
7099
7100 if (key.type != TID_STRING) {
7101 if (link_index != -1)
7103 else
7105 }
7106
7107 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7108 data_str = "(empty)";
7109 hex_str = "";
7110 }
7111
7112 r->rsprintf("<tr>\n");
7113 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
7114 if (link_name[0]) {
7115 r->rsprintf("<td class=\"ODBkey\">\n");
7116 r->rsprintf("%s <i>&rarr; ", keyname.c_str());
7117 r->rsprintf("<a href=\"%s\">%s</a></i>\n", enc_link_ref.c_str(), link_name);
7118 r->rsprintf("<td class=\"%s\">\n", style);
7119 if (!write_access)
7120 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7121 else {
7122 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7123 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7124 }
7125 } else {
7126 r->rsprintf("<td class=\"ODBkey\">\n");
7127 r->rsprintf("%s<td class=\"%s\">", keyname.c_str(), style);
7128 if (!write_access)
7129 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7130 else {
7131 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7132 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7133 }
7134 }
7135 } else {
7136 if (strchr(data_str.c_str(), '\n')) {
7137 if (link_name[0]) {
7138 r->rsprintf("<td class=\"ODBkey\">");
7139 r->rsprintf("%s <i>&rarr; <a href=\"%s\">%s</a></i><td class=\"ODBvalue\">", keyname.c_str(), enc_link_ref.c_str(), link_name);
7140 } else
7141 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7142 r->rsprintf("\n<pre>");
7143 strencode3(r, data_str.c_str());
7144 r->rsprintf("</pre>");
7145 if (strlen(data) > data_str.length())
7146 r->rsprintf("<i>... (%d bytes total)<p>\n", (int)strlen(data));
7147
7148 r->rsprintf("<a href=\"%s\">Edit</a>\n", enc_ref.c_str());
7149 } else {
7150 if (link_name[0]) {
7151 r->rsprintf("<td class=\"ODBkey\">\n");
7152 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);
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 } else {
7162 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7163 if (!write_access) {
7164 strencode(r, data_str.c_str());
7165 } else {
7166 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7167 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7168 strencode(r, data_str.c_str());
7169 r->rsprintf("</a>\n");
7170 }
7171 }
7172 }
7173 }
7174
7175 /* extended key information */
7176 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7177 r->rsprintf("%s", rpc_tid_name(key.type));
7178 r->rsprintf("</td>\n");
7179
7180 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7181 r->rsprintf("%d", key.num_values);
7182 r->rsprintf("</td>\n");
7183
7184 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7185 r->rsprintf("%d", key.item_size);
7186 r->rsprintf("</td>\n");
7187
7188 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7190 if (delta < 60)
7191 r->rsprintf("%ds", delta);
7192 else if (delta < 3600)
7193 r->rsprintf("%1.0lfm", delta / 60.0);
7194 else if (delta < 86400)
7195 r->rsprintf("%1.0lfh", delta / 3600.0);
7196 else if (delta < 86400 * 99)
7197 r->rsprintf("%1.0lfd", delta / 86400.0);
7198 else
7199 r->rsprintf(">99d");
7200 r->rsprintf("</td>\n");
7201
7202 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7204 r->rsprintf("R");
7206 r->rsprintf("W");
7208 r->rsprintf("D");
7210 r->rsprintf("E");
7211 r->rsprintf("</td>\n");
7212
7213 line++;
7214 r->rsprintf("</tr>\n");
7215 } else { /* display array value */
7216 /* check for exceeding length */
7217 if (key.num_values > 1000 && !pp->isparam("all"))
7218 r->rsprintf("<tr><td class=\"ODBkey\">%s<td class=\"%s\"><span style=\"font-style: italic\"><a href=\"?cmd=oldodb&odb_path=%s&all=1\">... %d values ...</a></span>\n", keyname.c_str(), style, enc_full_path.c_str(), key.num_values);
7219 else {
7220 /* display first value */
7221 if (link_name[0])
7222 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);
7223 else
7224 r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s\n", key.num_values, keyname.c_str());
7225
7226 for (int j = 0; j < key.num_values; j++) {
7227 if (line % 2 == 0)
7228 mstrlcpy(style, "ODBtableEven", sizeof(style));
7229 else
7230 mstrlcpy(style, "ODBtableOdd", sizeof(style));
7231
7232 char data[TEXT_SIZE];
7233 size = sizeof(data);
7234 db_get_data_index(hDB, hkey, data, &size, j, key.type);
7235 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
7236
7237 std::string hex_str;
7238 if (key.type == TID_STRING || key.type == TID_LINK) {
7239 hex_str = "";
7240 } else {
7242 }
7243
7244 if (key.type == TID_STRING) {
7245 if (size == sizeof(data)) {
7246 data_str += "...(truncated)";
7247 }
7248 }
7249
7250 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7251 data_str = "(empty)";
7252 hex_str = "";
7253 }
7254
7255 //sprintf(ref, "?cmd=Set&odb_path=%s&index=%d", full_path, j);
7256 enc_ref = "";
7257 enc_ref += "?cmd=Set&odb_path=";
7259 enc_ref += "&index=";
7260 enc_ref += toString(j);
7261
7262 std::string tmpstr;
7263 //sprintf(str, "%s[%d]", odb_path, j);
7264 tmpstr += odb_path;
7265 tmpstr += "[";
7266 tmpstr += toString(j);
7267 tmpstr += "]";
7268
7269 if (j > 0)
7270 r->rsprintf("<tr>");
7271
7272 r->rsprintf("<td class=\"%s\">[%d]&nbsp;", style, j);
7273 if (!write_access)
7274 r->rsprintf("<a href=\"%s\">", enc_ref.c_str());
7275 else {
7276 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), tmpstr.c_str());
7277 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", tmpstr.c_str());
7278 }
7279 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
7280 r->rsprintf("%s (%s)</a>\n", data_str.c_str(), hex_str.c_str());
7281 else
7282 r->rsprintf("%s</a>\n", data_str.c_str());
7283
7284 if (j == 0) {
7285 /* extended key information */
7286 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7287 r->rsprintf("%s", rpc_tid_name(key.type));
7288 r->rsprintf("</td>\n");
7289
7290 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7291 r->rsprintf("%d", key.num_values);
7292 r->rsprintf("</td>\n");
7293
7294 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7295 r->rsprintf("%d", key.item_size);
7296 r->rsprintf("</td>\n");
7297
7298 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7300 if (delta < 60)
7301 r->rsprintf("%ds", delta);
7302 else if (delta < 3600)
7303 r->rsprintf("%1.0lfm", delta / 60.0);
7304 else if (delta < 86400)
7305 r->rsprintf("%1.0lfh", delta / 3600.0);
7306 else if (delta < 86400 * 99)
7307 r->rsprintf("%1.0lfh", delta / 86400.0);
7308 else
7309 r->rsprintf(">99d");
7310 r->rsprintf("</td>\n");
7311
7312 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7314 r->rsprintf("R");
7316 r->rsprintf("W");
7318 r->rsprintf("D");
7320 r->rsprintf("E");
7321 r->rsprintf("</td>\n");
7322 }
7323 line++;
7324 }
7325
7326 r->rsprintf("</tr>\n");
7327 }
7328 }
7329 } else if(key.type != TID_KEY){
7330 keyPresent = 1; //flag that we've seen a key on the first pass, and should therefore write the Key / Value headline
7331 }
7332 }
7333 }
7334 }
7335 r->rsprintf("</table>\n");
7336 r->rsprintf("</div>\n"); // <div id="mmain">
7337
7338 /*---- Build the Delete dialog------------------------------------*/
7339
7340 std::sort(delete_list.begin(), delete_list.end());
7341
7342 for (unsigned i=0; i<delete_list.size(); i++) {
7343 std::string name = delete_list[i];
7344
7345 dd += "<tr><td style=\"text-align:left;\" align=left><input align=left type=checkbox id=delete";
7346 dd += toString(count_delete++);
7347 dd += " value=\'";
7348 dd += "\"";
7349 dd += MJsonNode::Encode(name.c_str());
7350 dd += "\"";
7351 dd += "\'>";
7352 dd += name;
7353 dd += "</input></td></tr>\n";
7354 }
7355
7356 dd += "</table>\n";
7357 dd += "<input type=button value=Delete onClick='mhttpd_delete_page_handle_delete(event);'>\n";
7358 dd += "<input type=button value=Cancel onClick='mhttpd_delete_page_handle_cancel(event);'>\n";
7359 dd += "</div>\n";
7360 dd += "</div>\n";
7361
7362 r->rsputs(dd.c_str());
7363
7364 /*---- Build the Create dialog------------------------------------*/
7365
7366 std::string cd = "";
7367
7368 cd += "<!-- Demo dialog -->\n";
7369 cd += "<div id=\"dlgCreate\" class=\"dlgFrame\">\n";
7370 cd += "<div class=\"dlgTitlebar\">Create ODB entry</div>\n";
7371 cd += "<div class=\"dlgPanel\">\n";
7372 cd += "<br />\n";
7373 cd += "<div id=odbpath>";
7374 cd += "\"";
7375 cd += MJsonNode::Encode(odbpath.c_str());
7376 cd += "\"";
7377 cd += "</div>\n";
7378 cd += "<div><br></div>\n";
7379
7380 cd += "<table class=\"dialogTable\">\n";
7381 cd += "<th colspan=2>Create ODB entry:</th>\n";
7382 cd += "<tr>";
7383 cd += "<td>Type";
7384 cd += "<td>";
7385 cd += "<select type=text size=1 id=create_tid name=type>";
7386 cd += "<option value=7>Integer (32-bit)";
7387 cd += "<option value=9>Float (4 Bytes)";
7388 cd += "<option value=12>String";
7389 cd += "<option selected value=15>Subdirectory";
7390 cd += "<option value=1>Byte";
7391 cd += "<option value=2>Signed byte";
7392 cd += "<option value=3>Character (8-bit)";
7393 cd += "<option value=4>Word (16-bit)";
7394 cd += "<option value=5>Short integer (16-bit)";
7395 cd += "<option value=6>Double Word (32-bit)";
7396 cd += "<option value=8>Boolean";
7397 cd += "<option value=10>Double float (8 Bytes)";
7398 //cd += "<option value=16>Symbolic link";
7399 cd += "</select>";
7400 cd += "</tr>\n";
7401 cd += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=create_name name=value></tr>\n";
7402 cd += "<tr><td>Array size<td><input type=text size=31 maxlength=31 id=create_array_length name=index value=1></tr>\n";
7403 cd += "<tr><td>String length<td><input type=text size=31 maxlength=31 id=create_strlen name=strlen value=32></tr>\n";
7404 cd += "</table>\n";
7405 cd += "<input type=button value=Create onClick='mhttpd_create_page_handle_create(event);'>\n";
7406 cd += "<input type=button value=Cancel onClick='mhttpd_create_page_handle_cancel(event);'>\n";
7407 cd += "</div>\n";
7408 cd += "</div>\n";
7409
7410 r->rsputs(cd.c_str());
7411
7412 /*---- Build the Link dialog------------------------------------*/
7413
7414 std::string ld = "";
7415
7416 ld += "<!-- Demo dialog -->\n";
7417 ld += "<div id=\"dlgLink\" class=\"dlgFrame\">\n";
7418 ld += "<div class=\"dlgTitlebar\">Create a link to an ODB entry</div>\n";
7419 ld += "<div class=\"dlgPanel\">\n";
7420 ld += "<br />\n";
7421 ld += "<div id=link_odbpath>";
7422 ld += "\"";
7423 ld += MJsonNode::Encode(odbpath.c_str());
7424 ld += "\"";
7425 ld += "</div>\n";
7426 ld += "<div><br></div>\n";
7427
7428 ld += "<table class=\"dialogTable\">\n";
7429 ld += "<th colspan=2>Create a link to an ODB entry:</th>\n";
7430 ld += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=link_name name=value></tr>\n";
7431 ld += "<tr><td>Link target<td><input type=text size=31 maxlength=256 id=link_target name=target></tr>\n";
7432 ld += "</table>\n";
7433 ld += "<input type=button value=Link onClick='mhttpd_link_page_handle_link(event);'>\n";
7434 ld += "<input type=button value=Cancel onClick='mhttpd_link_page_handle_cancel(event);'>\n";
7435 ld += "</div>\n";
7436 ld += "</div>\n";
7437
7438 r->rsputs(ld.c_str());
7439}
7440
7441/*------------------------------------------------------------------*/
7442
7444 const char *group,
7445 int index, const char *value)
7446{
7447 int status, size;
7448 HNDLE hDB, hkey;
7449 KEY key;
7450 char data[TEXT_SIZE];
7451
7452 std::string odb_path = pp->getparam("odb_path");
7453
7454 //printf("show_set_page: odb_path [%s] group [%s] index %d value [%s]\n", odb_path.c_str(), group, index, value);
7455
7457
7458 /* show set page if no value is given */
7459 if (!pp->isparam("value") && !*pp->getparam("text")) {
7460 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7461 if (status != DB_SUCCESS) {
7462 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7463 return;
7464 }
7465 db_get_link(hDB, hkey, &key);
7466
7467 show_header(r, "Set value", "POST", "", 0);
7468 //close header:
7469 r->rsprintf("</table>");
7470
7471 //main table:
7472 r->rsprintf("<table class=\"dialogTable\">");
7473
7474 if (index > 0)
7475 r->rsprintf("<input type=hidden name=index value=\"%d\">\n", index);
7476 else
7477 index = 0;
7478
7479 if (group[0])
7480 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", group);
7481
7482 r->rsprintf("<input type=hidden name=odb_path value=\"%s\">\n", odb_path.c_str());
7483
7484 std::string data_str1 = rpc_tid_name(key.type);
7485 std::string str1;
7486 if (key.num_values > 1) {
7487 data_str1 += msprintf("[%d]", key.num_values);
7488 str1 = msprintf("%s[%d]", odb_path.c_str(), index);
7489 } else
7490 str1 = odb_path.c_str();
7491
7492 r->rsprintf("<tr><th colspan=2>Set new value - type = %s</tr>\n", data_str1.c_str());
7493 r->rsprintf("<tr><td>%s<td>\n", str1.c_str());
7494
7495 /* set current value as default */
7496 size = sizeof(data);
7497 db_get_link_data(hDB, hkey, data, &size, key.type);
7498 std::string data_str = db_sprintf(data, key.item_size, index, key.type);
7499
7500 if (equal_ustring(data_str.c_str(), "<NULL>"))
7501 data_str = "";
7502
7503 if (strchr(data_str.c_str(), '\n') != NULL) {
7504 r->rsprintf("<textarea rows=20 cols=80 name=\"text\">\n");
7505 strencode3(r, data);
7506 r->rsprintf("</textarea>\n");
7507 } else {
7508 size = 20;
7509 if ((int) data_str.length() > size)
7510 size = data_str.length() + 3;
7511 if (size > 80)
7512 size = 80;
7513
7514 r->rsprintf("<input type=\"text\" size=%d maxlength=256 name=\"value\" value=\"", size);
7515 strencode(r, data_str.c_str());
7516 r->rsprintf("\">\n");
7517 }
7518
7519 r->rsprintf("</tr>\n");
7520
7521 r->rsprintf("<tr><td align=center colspan=2>");
7522 r->rsprintf("<input type=submit name=cmd value=Set>");
7523 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7524 r->rsprintf("</tr>");
7525 r->rsprintf("</table>");
7526
7527 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
7528
7529 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7530 r->rsprintf("</form>\n");
7531 r->rsprintf("</body></html>\r\n");
7532 return;
7533 } else {
7534 /* set value */
7535
7536 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7537 if (status != DB_SUCCESS) {
7538 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7539 return;
7540 }
7541 db_get_link(hDB, hkey, &key);
7542
7543 memset(data, 0, sizeof(data));
7544
7545 if (pp->getparam("text") && *pp->getparam("text"))
7546 mstrlcpy(data, pp->getparam("text"), sizeof(data));
7547 else
7548 db_sscanf(value, data, &size, 0, key.type);
7549
7550 if (index < 0)
7551 index = 0;
7552
7553 /* extend data size for single string if necessary */
7554 if ((key.type == TID_STRING || key.type == TID_LINK)
7555 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
7556 key.item_size = strlen(data) + 1;
7557
7558 if (key.item_size == 0)
7560
7561 if (key.num_values > 1)
7563 else
7565
7566 if (status == DB_NO_ACCESS)
7567 r->rsprintf("<h2>Write access not allowed</h2>\n");
7568
7569 redirect(r, "");
7570
7571 return;
7572 }
7573}
7574
7575/*------------------------------------------------------------------*/
7576
7577void show_find_page(Return* r, const char *value)
7578{
7579 HNDLE hDB, hkey;
7580
7582
7583 if (value[0] == 0) {
7584 /* without value, show find dialog */
7585 show_header(r, "Find value", "GET", "", 0);
7586
7587 //end header:
7588 r->rsprintf("</table>");
7589
7590 //find dialog:
7591 r->rsprintf("<table class=\"dialogTable\">");
7592
7593 r->rsprintf("<tr><th colspan=2>Find string in Online Database</tr>\n");
7594 r->rsprintf("<tr><td>Enter substring (case insensitive)\n");
7595
7596 r->rsprintf("<td><input type=\"text\" size=\"20\" maxlength=\"80\" name=\"value\">\n");
7597 r->rsprintf("</tr>");
7598
7599 r->rsprintf("<tr><td align=center colspan=2>");
7600 r->rsprintf("<input type=submit name=cmd value=Find>");
7601 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7602 r->rsprintf("</tr>");
7603 r->rsprintf("</table>");
7604
7605 r->rsprintf("<input type=hidden name=cmd value=Find>");
7606
7607 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7608 r->rsprintf("</form>\n");
7609 r->rsprintf("</body></html>\r\n");
7610 } else {
7611 show_header(r, "Search results", "GET", "", 0);
7612
7613 r->rsprintf("<table class=\"mtable\">\n");
7614 r->rsprintf("<tr><th colspan=2 class=\"mtableheader\">");
7615 r->rsprintf("Results of search for substring \"%s\"</tr>\n", value);
7616 r->rsprintf("<tr><th class=\"titlerow\">Key<th>Value</tr>\n");
7617
7618 /* start from root */
7619 db_find_key(hDB, 0, "", &hkey);
7620 assert(hkey);
7621
7622 /* scan tree, call "search_callback" for each key */
7624 data.r = r;
7625 data.search_name = value;
7626
7627 db_scan_tree(hDB, hkey, 0, search_callback, (void *)&data);
7628
7629 r->rsprintf("</table>");
7630 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7631 r->rsprintf("</form>\n");
7632 r->rsprintf("</body></html>\r\n");
7633 }
7634}
7635
7636/*------------------------------------------------------------------*/
7637
7638#define LN10 2.302585094
7639#define LOG2 0.301029996
7640#define LOG5 0.698970005
7641
7642void haxis(gdImagePtr im, gdFont * font, int col, int gcol,
7643 int x1, int y1, int width,
7644 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7645{
7648 char str[80];
7649 double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7650
7651 if (xmax <= xmin || width <= 0)
7652 return;
7653
7654 /* use 5 as min tick distance */
7655 dx = (xmax - xmin) / (double) (width / 5);
7656
7657 frac_dx = modf(log(dx) / LN10, &int_dx);
7658 if (frac_dx < 0) {
7659 frac_dx += 1;
7660 int_dx -= 1;
7661 }
7662
7663 tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
7665
7666 /* rounding up of dx, label_dx */
7667 dx = pow(10, int_dx) * base[tick_base];
7668 major_dx = pow(10, int_dx) * base[major_base];
7670
7671 /* number of significant digits */
7672 if (xmin == 0)
7673 n_sig1 = 0;
7674 else
7675 n_sig1 = (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7676
7677 if (xmax == 0)
7678 n_sig2 = 0;
7679 else
7680 n_sig2 =
7681 (int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7682
7683 n_sig1 = MAX(n_sig1, n_sig2);
7684 n_sig1 = MAX(n_sig1, 4);
7685
7686 /* determination of maximal width of labels */
7687 sprintf(str, "%1.*lG", n_sig1, floor(xmin / dx) * dx);
7688 maxwidth = font->h / 2 * strlen(str);
7689 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx);
7690 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7691 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx + label_dx);
7692 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7693
7694 /* increasing label_dx, if labels would overlap */
7695 while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7696 label_base++;
7697 label_dx = pow(10, int_dx) * base[label_base];
7698 if (label_base % 3 == 2 && major_base % 3 == 1) {
7699 major_base++;
7700 major_dx = pow(10, int_dx) * base[major_base];
7701 }
7702 }
7703
7704 x_act = floor(xmin / dx) * dx;
7705
7706 gdImageLine(im, x1, y1, x1 + width, y1, col);
7707
7708 do {
7709 x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
7710 xs = (int) (x_screen + 0.5);
7711
7712 if (x_screen > x1 + width + 0.001)
7713 break;
7714
7715 if (x_screen >= x1) {
7716 if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
7717 dx / major_dx / 10.0) {
7718
7719 if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
7720 dx / label_dx / 10.0) {
7721 /* label tick mark */
7722 gdImageLine(im, xs, y1, xs, y1 + text, col);
7723
7724 /* grid line */
7725 if (grid != 0 && xs > x1 && xs < x1 + width)
7726 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7727
7728 /* label */
7729 if (label != 0) {
7730 sprintf(str, "%1.*lG", n_sig1, x_act);
7731 gdImageString(im, font, (int) xs - font->w * strlen(str) / 2,
7732 y1 + label, str, col);
7733 }
7734 } else {
7735 /* major tick mark */
7736 gdImageLine(im, xs, y1, xs, y1 + major, col);
7737
7738 /* grid line */
7739 if (grid != 0 && xs > x1 && xs < x1 + width)
7740 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7741 }
7742
7743 } else
7744 /* minor tick mark */
7745 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7746
7747 }
7748
7749 x_act += dx;
7750
7751 /* supress 1.23E-17 ... */
7752 if (fabs(x_act) < dx / 100)
7753 x_act = 0;
7754
7755 } while (1);
7756}
7757
7758/*------------------------------------------------------------------*/
7759
7760void sec_to_label(char *result, int sec, int base, int force_date)
7761{
7762 char mon[80];
7763 time_t t_sec;
7764
7765 t_sec = (time_t) sec;
7766
7767 struct tm tms;
7768 localtime_r(&t_sec, &tms);
7769 strcpy(mon, mname[tms.tm_mon]);
7770 mon[3] = 0;
7771
7772 if (force_date) {
7773 if (base < 600)
7774 sprintf(result, "%02d %s %02d %02d:%02d:%02d",
7775 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min,
7776 tms.tm_sec);
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 } else {
7783 if (base < 600)
7784 sprintf(result, "%02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec);
7785 else if (base < 3600 * 3)
7786 sprintf(result, "%02d:%02d", tms.tm_hour, tms.tm_min);
7787 else if (base < 3600 * 24)
7788 sprintf(result, "%02d %s %02d %02d:%02d",
7789 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7790 else
7791 sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7792 }
7793}
7794
7795void taxis(gdImagePtr im, gdFont * font, int col, int gcol,
7796 int x1, int y1, int width, int xr,
7797 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7798{
7801 char str[80];
7802 const int base[] = { 1, 5, 10, 60, 300, 600, 1800, 3600, 3600 * 6, 3600 * 12, 3600 * 24, 0 };
7803 time_t ltime;
7804 int force_date, d1, d2;
7805 struct tm tms;
7806
7807 if (xmax <= xmin || width <= 0)
7808 return;
7809
7810 /* force date display if xmax not today */
7811 ltime = ss_time();
7812 localtime_r(&ltime, &tms);
7813 d1 = tms.tm_mday;
7814 ltime = (time_t) xmax;
7815 localtime_r(&ltime, &tms);
7816 d2 = tms.tm_mday;
7817 force_date = (d1 != d2);
7818
7819 /* use 5 pixel as min tick distance */
7820 dx = (int) ((xmax - xmin) / (double) (width / 5) + 0.5);
7821
7822 for (tick_base = 0; base[tick_base]; tick_base++) {
7823 if (base[tick_base] > dx)
7824 break;
7825 }
7826 if (!base[tick_base])
7827 tick_base--;
7828 dx = base[tick_base];
7829
7830 if (base[tick_base + 1])
7831 major_base = tick_base + 1;
7832 else
7835
7836 if (base[major_base + 1])
7837 label_base = major_base + 1;
7838 else
7841
7842 do {
7843 sec_to_label(str, (int) (xmin + 0.5), label_dx, force_date);
7844 maxwidth = font->h / 2 * strlen(str);
7845
7846 /* increasing label_dx, if labels would overlap */
7847 if (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7848 if (base[label_base + 1])
7850 else
7851 label_dx += 3600 * 24;
7852 } else
7853 break;
7854 } while (1);
7855
7856 x_act =
7857 (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
7858
7859 gdImageLine(im, x1, y1, x1 + width, y1, col);
7860
7861 do {
7862 x_screen = (int) ((x_act - xmin) / (xmax - xmin) * width + x1 + 0.5);
7863 xs = (int) (x_screen + 0.5);
7864
7865 if (x_screen > x1 + width + 0.001)
7866 break;
7867
7868 if (x_screen >= x1) {
7869 if ((x_act - ss_timezone()) % major_dx == 0) {
7870 if ((x_act - ss_timezone()) % label_dx == 0) {
7871 /* label tick mark */
7872 gdImageLine(im, xs, y1, xs, y1 + text, col);
7873
7874 /* grid line */
7875 if (grid != 0 && xs > x1 && xs < x1 + width)
7876 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7877
7878 /* label */
7879 if (label != 0) {
7881
7882 /* if labels at edge, shift them in */
7883 xl = (int) xs - font->w * strlen(str) / 2;
7884 if (xl < 0)
7885 xl = 0;
7886 if (xl + font->w * (int) strlen(str) > xr)
7887 xl = xr - font->w * strlen(str);
7888 gdImageString(im, font, xl, y1 + label, str, col);
7889 }
7890 } else {
7891 /* major tick mark */
7892 gdImageLine(im, xs, y1, xs, y1 + major, col);
7893
7894 /* grid line */
7895 if (grid != 0 && xs > x1 && xs < x1 + width)
7896 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7897 }
7898
7899 } else
7900 /* minor tick mark */
7901 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7902
7903 }
7904
7905 x_act += dx;
7906
7907 /* supress 1.23E-17 ... */
7908 if (fabs((double)x_act) < dx / 100)
7909 x_act = 0;
7910
7911 } while (1);
7912}
7913
7914/*------------------------------------------------------------------*/
7915
7916int vaxis(gdImagePtr im, gdFont * font, int col, int gcol,
7917 int x1, int y1, int width,
7918 int minor, int major, int text, int label, int grid, double ymin, double ymax,
7919 BOOL logaxis)
7920{
7923 int last_label_y;
7924 char str[80];
7925 const double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7926
7927 if (ymax <= ymin || width <= 0)
7928 return 0;
7929
7930 // data type "double" only has about 15 significant digits, if difference between ymax and ymin is less than 10 significant digits, bailout! Otherwise code below goes into infinite loop
7931 if (fabs(ymax - ymin) <= 1e-10)
7932 return 0;
7933
7934 if (logaxis) {
7935 dy = pow(10, floor(log(ymin) / LN10));
7936 label_dy = dy;
7937 major_dy = dy * 10;
7938 n_sig1 = 4;
7939 } else {
7940 dy = (ymax - ymin) / (double) (width / 5);
7941
7942 frac_dy = modf(log(dy) / LN10, &int_dy);
7943 if (frac_dy < 0) {
7944 frac_dy += 1;
7945 int_dy -= 1;
7946 }
7947
7948 tick_base = frac_dy < LOG2 ? 1 : frac_dy < LOG5 ? 2 : 3;
7950
7951 /* rounding up of dy, label_dy */
7952 dy = pow(10, int_dy) * base[tick_base];
7953 major_dy = pow(10, int_dy) * base[major_base];
7955
7956 /* number of significant digits */
7957 if (ymin == 0)
7958 n_sig1 = 0;
7959 else
7960 n_sig1 =
7961 (int) floor(log(fabs(ymin)) / LN10) -
7962 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7963
7964 if (ymax == 0)
7965 n_sig2 = 0;
7966 else
7967 n_sig2 =
7968 (int) floor(log(fabs(ymax)) / LN10) -
7969 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7970
7971 n_sig1 = MAX(n_sig1, n_sig2);
7972 n_sig1 = MAX(n_sig1, 4);
7973
7974 /* increasing label_dy, if labels would overlap */
7975 while (label_dy / (ymax - ymin) * width < 1.5 * font->h) {
7976 label_base++;
7977 label_dy = pow(10, int_dy) * base[label_base];
7978 if (label_base % 3 == 2 && major_base % 3 == 1) {
7979 major_base++;
7980 major_dy = pow(10, int_dy) * base[major_base];
7981 }
7982 }
7983 }
7984
7985 max_width = 0;
7986 y_act = floor(ymin / dy) * dy;
7987
7988 if (x1 != 0 || y1 != 0)
7989 gdImageLine(im, x1, y1, x1, y1 - width, col);
7990
7991 last_label_y = y1 + 2 * font->h;
7992
7993 do {
7994 if (logaxis)
7995 y_screen = y1 - (log(y_act) - log(ymin)) / (log(ymax) - log(ymin)) * width;
7996 else
7997 y_screen = y1 - (y_act - ymin) / (ymax - ymin) * width;
7998 ys = (int) (y_screen + 0.5);
7999
8000 if (y_screen < y1 - width - 0.001)
8001 break;
8002
8003 if (y_screen <= y1 + 0.001) {
8004 if (fabs(floor(y_act / major_dy + 0.5) - y_act / major_dy) <
8005 dy / major_dy / 10.0) {
8006 if (fabs(floor(y_act / label_dy + 0.5) - y_act / label_dy) <
8007 dy / label_dy / 10.0) {
8008 if (x1 != 0 || y1 != 0) {
8009 /* label tick mark */
8010 gdImageLine(im, x1, ys, x1 + text, ys, col);
8011
8012 /* grid line */
8013 if (grid != 0 && y_screen < y1 && y_screen > y1 - width) {
8014 if (grid > 0)
8015 gdImageLine(im, x1 + 1, ys, x1 + grid, ys, gcol);
8016 else
8017 gdImageLine(im, x1 - 1, ys, x1 + grid, ys, gcol);
8018 }
8019
8020 /* label */
8021 if (label != 0) {
8022 sprintf(str, "%1.*lG", n_sig1, y_act);
8023 if (label < 0)
8024 gdImageString(im, font, x1 + label - font->w * strlen(str),
8025 ys - font->h / 2, str, col);
8026 else
8027 gdImageString(im, font, x1 + label, ys - font->h / 2, str, col);
8028
8029 last_label_y = ys - font->h / 2;
8030 }
8031 } else {
8032 sprintf(str, "%1.*lG", n_sig1, y_act);
8033 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8034 }
8035 } else {
8036 if (x1 != 0 || y1 != 0) {
8037 /* major tick mark */
8038 gdImageLine(im, x1, ys, x1 + major, ys, col);
8039
8040 /* grid line */
8041 if (grid != 0 && y_screen < y1 && y_screen > y1 - width)
8042 gdImageLine(im, x1, ys, x1 + grid, ys, col);
8043 }
8044 }
8045 if (logaxis) {
8046 dy *= 10;
8047 major_dy *= 10;
8048 label_dy *= 10;
8049 }
8050
8051 } else {
8052 if (x1 != 0 || y1 != 0) {
8053 /* minor tick mark */
8054 gdImageLine(im, x1, ys, x1 + minor, ys, col);
8055 }
8056
8057 /* for logaxis, also put labes on minor tick marks */
8058 if (logaxis) {
8059 if (label != 0) {
8060 if (x1 != 0 || y1 != 0) {
8061 /* calculate position of next major label */
8062 y_next = pow(10, floor(log(y_act) / LN10) + 1);
8063 y_screen =
8064 (int) (y1 -
8065 (log(y_next) - log(ymin)) / (log(ymax) -
8066 log(ymin)) * width + 0.5);
8067
8068 if (ys + font->h / 2 < last_label_y
8069 && ys - font->h / 2 > y_screen + font->h / 2) {
8070 sprintf(str, "%1.*lG", n_sig1, y_act);
8071 if (label < 0)
8072 gdImageString(im, font, x1 + label - font->w * strlen(str),
8073 ys - font->h / 2, str, col);
8074 else
8075 gdImageString(im, font, x1 + label, ys - font->h / 2, str,
8076 col);
8077 }
8078
8079 last_label_y = ys - font->h / 2;
8080 } else {
8081 sprintf(str, "%1.*lG", n_sig1, y_act);
8082 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8083 }
8084 }
8085 }
8086 }
8087 }
8088
8089 y_act += dy;
8090
8091 /* supress 1.23E-17 ... */
8092 if (fabs(y_act) < dy / 100)
8093 y_act = 0;
8094
8095 } while (1);
8096
8097 return max_width + abs(label);
8098}
8099
8100/*------------------------------------------------------------------*/
8101
8102int time_to_sec(const char *str)
8103{
8104 double s;
8105
8106 s = atof(str);
8107 switch (str[strlen(str) - 1]) {
8108 case 'm':
8109 case 'M':
8110 s *= 60;
8111 break;
8112 case 'h':
8113 case 'H':
8114 s *= 3600;
8115 break;
8116 case 'd':
8117 case 'D':
8118 s *= 3600 * 24;
8119 break;
8120 }
8121
8122 return (int) s;
8123}
8124
8125/*------------------------------------------------------------------*/
8126
8128{
8129 time_t t = 0;
8130 for (; *str != 0; str++) {
8131 if (*str < '0')
8132 break;
8133 if (*str > '9')
8134 break;
8135 t *= 10;
8136 t += *str - '0';
8137 }
8138 return t;
8139}
8140
8141/*------------------------------------------------------------------*/
8142
8144{
8145 char buf[256];
8146 sprintf(buf, "%.0f", (double)t);
8147 return buf;
8148}
8149
8150/*------------------------------------------------------------------*/
8151
8152static bool gDoSetupHistoryWatch = true;
8153static bool gDoReloadHistory = false;
8154
8156{
8157 //printf("history_watch_callback %d %d %d\n", hDB, hKey, index);
8158 gDoReloadHistory = true;
8159 cm_msg(MINFO, "history_watch_callback", "History configuration may have changed, will reconnect");
8160}
8161
8163static HNDLE gMhkey = 0;
8164
8165/*------------------------------------------------------------------*/
8166
8167static MidasHistoryInterface* get_history(bool reset = false)
8168{
8169 int status;
8170 HNDLE hDB;
8171
8172 // history reconnect requested by watch callback?
8173
8174 if (gDoReloadHistory) {
8175 gDoReloadHistory = false;
8176 reset = true;
8177 }
8178
8179 // disconnect from previous history
8180
8181 if (reset && gMh) {
8182 gMh->hs_disconnect();
8183 delete gMh;
8184 gMh = NULL;
8185 gMhkey = 0;
8186 }
8187
8189 assert(status == CM_SUCCESS);
8190
8191 // setup a watch on history configuration
8192
8194 HNDLE hKey;
8195 gDoSetupHistoryWatch = false;
8196
8197 status = db_find_key(hDB, 0, "/Logger/History", &hKey);
8198 if (status == DB_SUCCESS)
8200
8201 status = db_find_key(hDB, 0, "/History/LoggerHistoryChannel", &hKey);
8202 if (status == DB_SUCCESS)
8204 }
8205
8206 // find out if ODB settings have changed and we need to connect to a different history channel
8207
8208 HNDLE hKey = 0;
8210 if (status != HS_SUCCESS)
8211 return gMh;
8212
8213 //printf("mh %p, hKey %d, mhkey %d\n", mh, hKey, mhkey);
8214
8215 if (gMh && hKey == gMhkey) // same channel as before
8216 return gMh;
8217
8218 if (gMh) {
8219 delete gMh;
8220 gMh = NULL;
8221 gMhkey = 0;
8222 }
8223
8225 if (status != HS_SUCCESS || gMh==NULL) {
8226 cm_msg(MERROR, "get_history", "Cannot configure history, hs_get_history() status %d", status);
8227 gMh = NULL;
8228 return NULL;
8229 }
8230
8231 gMhkey = hKey;
8232
8233 // cm_msg(MINFO, "get_history", "Reading history from channel \'%s\' type \'%s\'", mh->name, mh->type);
8234
8235 return gMh;
8236}
8237
8238/*------------------------------------------------------------------*/
8239
8240#ifdef OS_WINNT
8241#undef DELETE
8242#endif
8243
8244#define ALLOC(t,n) (t*)calloc(sizeof(t),(n))
8245#define DELETE(x) if (x) { free(x); (x)=NULL; }
8246#define DELETEA(x, n) if (x) { for (int i=0; i<(n); i++) { free((x)[i]); (x)[i]=NULL; }; DELETE(x); }
8247#define STRDUP(x) strdup(x)
8248
8250{
8260 double** v;
8261
8264
8268
8269 void Allocate(int xnvars) {
8270 if (alloc_nvars > 0)
8271 Free();
8272 nvars = 0;
8274 event_names = ALLOC(char*, alloc_nvars);
8275 var_names = ALLOC(char*, alloc_nvars);
8276 var_index = ALLOC(int, alloc_nvars);
8277 odb_index = ALLOC(int, alloc_nvars);
8278 status = ALLOC(int, alloc_nvars);
8281 v = ALLOC(double*, alloc_nvars);
8282
8283 have_last_written = false;
8285 }
8286
8287 void Free() {
8292 DELETE(status);
8297 nvars = 0;
8298 alloc_nvars = 0;
8299 have_last_written = false;
8300 }
8301
8302 void Print() const {
8303 printf("this %p, nvars %d. tstart %d, tend %d, scale %d\n", this, nvars, (int)tstart, (int)tend, (int)scale);
8304 for (int i=0; i<nvars; i++) {
8305 printf("var[%d]: [%s/%s][%d] %d entries, status %d", i, event_names[i], var_names[i], var_index[i], num_entries[i], status[i]);
8306 if (status[i]==HS_SUCCESS && num_entries[i]>0 && t[i] && v[i])
8307 printf(", t %d:%d, v %g:%g", (int)t[i][0], (int)t[i][num_entries[i]-1], v[i][0], v[i][num_entries[i]-1]);
8308 printf(" last_written %d", (int)last_written[i]);
8309 printf("\n");
8310 }
8311 }
8312
8313 HistoryData() // ctor
8314 {
8315 nvars = 0;
8316 alloc_nvars = 0;
8317 have_last_written = false;
8318 tstart = 0;
8319 tend = 0;
8320 scale = 0;
8321 }
8322
8324 {
8325 if (alloc_nvars > 0)
8326 Free();
8327 }
8328};
8329
8330#define READ_HISTORY_DATA 0x1
8331#define READ_HISTORY_RUNMARKER 0x2
8332#define READ_HISTORY_LAST_WRITTEN 0x4
8333
8335{
8336 std::string event_name;
8337 std::string tag_name;
8338 std::string formula;
8339 std::string colour;
8340 std::string label;
8341 bool show_raw_value = false;
8342 int order = -1;
8343 double factor = 1.0;
8344 double offset = 0;
8345 double voffset = 0;
8346};
8347
8349{
8350 std::string timescale = "1h";
8351 double minimum = 0;
8352 double maximum = 0;
8353 bool zero_ylow = false;
8354 bool log_axis = false;
8355 bool show_run_markers = true;
8356 bool show_values = true;
8357 bool show_fill = true;
8358 bool show_factor = false;
8359 bool enable_factor = true;
8360
8361 std::vector<HistVar> vars;
8362};
8363
8364static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel);
8365
8366int read_history(const HistPlot& hp, /*HNDLE hDB, const char *group, const char *panel,*/ int index, int flags, time_t tstart, time_t tend, time_t scale, HistoryData *data)
8367{
8368 //HNDLE hkeypanel, hkeydvar, hkey;
8369 //KEY key;
8370 //char path[256];
8371 //int n_vars;
8372 int status;
8373 int debug = 1;
8374
8375 //mstrlcpy(path, group, sizeof(path));
8376 //mstrlcat(path, "/", sizeof(path));
8377 //mstrlcat(path, panel, sizeof(path));
8378
8379 //printf("read_history, path %s, index %d, flags 0x%x, start %d, end %d, scale %d, data %p\n", path, index, flags, (int)tstart, (int)tend, (int)scale, data);
8380
8381 /* connect to history */
8383 if (mh == NULL) {
8384 //r->rsprintf(str, "History is not configured\n");
8385 return HS_FILE_ERROR;
8386 }
8387
8388#if 0
8389 /* check panel name in ODB */
8390 status = db_find_key(hDB, 0, "/History/Display", &hkey);
8391 if (!hkey) {
8392 cm_msg(MERROR, "read_history", "Cannot find \'/History/Display\' in ODB, status %d", status);
8393 return HS_FILE_ERROR;
8394 }
8395
8396 /* check panel name in ODB */
8397 status = db_find_key(hDB, hkey, path, &hkeypanel);
8398 if (!hkeypanel) {
8399 cm_msg(MERROR, "read_history", "Cannot find \'%s\' in ODB, status %d", path, status);
8400 return HS_FILE_ERROR;
8401 }
8402
8403 status = db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8404 if (!hkeydvar) {
8405 cm_msg(MERROR, "read_history", "Cannot find \'%s/Variables\' in ODB, status %d", path, status);
8406 return HS_FILE_ERROR;
8407 }
8408
8411#endif
8412
8413 data->Allocate(hp.vars.size()+2);
8414
8415 data->tstart = tstart;
8416 data->tend = tend;
8417 data->scale = scale;
8418
8419 for (size_t i=0; i<hp.vars.size(); i++) {
8420 if (index != -1 && (size_t)index != i)
8421 continue;
8422
8423 //char str[256];
8424 //int size = sizeof(str);
8425 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8426 //if (status != DB_SUCCESS) {
8427 // cm_msg(MERROR, "read_history", "Cannot read tag %d in panel %s, status %d", i, path, status);
8428 // continue;
8429 //}
8430
8431 /* split varname in event, variable and index: "event/tag[index]" */
8432
8433 //char *p = strchr(str, ':');
8434 //if (!p)
8435 // p = strchr(str, '/');
8436 //
8437 //if (!p) {
8438 // cm_msg(MERROR, "read_history", "Tag \"%s\" has wrong format in panel \"%s\"", str, path);
8439 // continue;
8440 //}
8441
8442 //*p = 0;
8443
8444 data->odb_index[data->nvars] = i;
8445 data->event_names[data->nvars] = STRDUP(hp.vars[i].event_name.c_str());
8446 data->var_names[data->nvars] = STRDUP(hp.vars[i].tag_name.c_str());
8447 data->var_index[data->nvars] = 0;
8448
8449 char *q = strchr(data->var_names[data->nvars], '[');
8450 if (q) {
8451 data->var_index[data->nvars] = atoi(q+1);
8452 *q = 0;
8453 }
8454
8455 data->nvars++;
8456 } // loop over variables
8457
8458 /* write run markes if selected */
8459 if (flags & READ_HISTORY_RUNMARKER) {
8460
8461 data->event_names[data->nvars+0] = STRDUP("Run transitions");
8462 data->event_names[data->nvars+1] = STRDUP("Run transitions");
8463
8464 data->var_names[data->nvars+0] = STRDUP("State");
8465 data->var_names[data->nvars+1] = STRDUP("Run number");
8466
8467 data->var_index[data->nvars+0] = 0;
8468 data->var_index[data->nvars+1] = 0;
8469
8470 data->odb_index[data->nvars+0] = -1;
8471 data->odb_index[data->nvars+1] = -2;
8472
8473 data->nvars += 2;
8474 }
8475
8476 bool get_last_written = false;
8477
8478 if (flags & READ_HISTORY_DATA) {
8479 status = mh->hs_read(tstart, tend, scale,
8480 data->nvars,
8481 data->event_names,
8482 data->var_names,
8483 data->var_index,
8484 data->num_entries,
8485 data->t,
8486 data->v,
8487 data->status);
8488
8489 if (debug) {
8490 printf("read_history: nvars %d, hs_read() status %d\n", data->nvars, status);
8491 for (int i=0; i<data->nvars; i++) {
8492 printf("read_history: %d: event [%s], var [%s], index %d, odb index %d, status %d, num_entries %d\n", i, data->event_names[i], data->var_names[i], data->var_index[i], data->odb_index[i], data->status[i], data->num_entries[i]);
8493 }
8494 }
8495
8496 if (status != HS_SUCCESS) {
8497 cm_msg(MERROR, "read_history", "Complete history failure, hs_read() status %d, see messages", status);
8498 return HS_FILE_ERROR;
8499 }
8500
8501 for (int i=0; i<data->nvars; i++) {
8502 if (data->status[i] != HS_SUCCESS || data->num_entries[i] < 1) {
8503 get_last_written = true;
8504 break;
8505 }
8506 }
8507 }
8508
8509 if (flags & READ_HISTORY_LAST_WRITTEN)
8510 get_last_written = true;
8511
8512 if (get_last_written) {
8513 data->have_last_written = true;
8514
8516 tstart,
8517 data->nvars,
8518 data->event_names,
8519 data->var_names,
8520 data->var_index,
8521 data->last_written);
8522
8523 if (status != HS_SUCCESS) {
8524 data->have_last_written = false;
8525 }
8526 }
8527
8528 return SUCCESS;
8529}
8530
8531int get_hist_last_written(MVOdb* odb, const char *group, const char *panel, time_t endtime, int index, int want_all, time_t *plastwritten)
8532{
8533 //HNDLE hDB;
8534 int status;
8535
8536 time_t now = ss_time();
8537
8538 if (endtime == 0)
8539 endtime = now;
8540
8543
8544 //cm_get_experiment_database(&hDB, NULL);
8545
8546 HistPlot hp;
8548
8549 double tstart = ss_millitime();
8550
8551 int flags = READ_HISTORY_LAST_WRITTEN;
8552
8553 status = read_history(hp, /*hDB, group, panel,*/ index, flags, endtime, endtime, 0, hsdata);
8554
8555 if (status != HS_SUCCESS) {
8556 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8557 return status;
8558 }
8559
8560 if (!hsdata->have_last_written) {
8561 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8562 return HS_FILE_ERROR;
8563 }
8564
8565 int count = 0;
8567 time_t tmax = 0;
8568
8569 for (int k=0; k<hsdata->nvars; k++) {
8570 int i = hsdata->odb_index[k];
8571
8572 if (i<0)
8573 continue;
8574 if (index != -1 && index != i)
8575 continue;
8576
8577 time_t lw = hsdata->last_written[k];
8578
8579 if (lw==0) // no last_written for this variable, skip it.
8580 continue;
8581
8582 if (lw > endtime)
8583 lw = endtime; // just in case hs_get_last_written() returns dates in the "future" for this plot
8584
8585 if (lw > tmax)
8586 tmax = lw;
8587
8588 if (lw < tmin)
8589 tmin = lw;
8590
8591 count++;
8592
8593 //printf("odb index %d, last_written[%d] = %.0f, tmin %.0f, tmax %.0f, endtime %.0f\n", i, k, (double)lw, (double)tmin, (double)tmax, (double)endtime);
8594 }
8595
8596 if (count == 0) // all variables have no last_written
8597 return HS_FILE_ERROR;
8598
8599 if (want_all)
8600 *plastwritten = tmin; // all variables have data
8601 else
8602 *plastwritten = tmax; // at least one variable has data
8603
8604 //printf("tmin %.0f, tmax %.0f, endtime %.0f, last written %.0f\n", (double)tmin, (double)tmax, (double)endtime, (double)*plastwritten);
8605
8606 double tend = ss_millitime();
8607
8608 if (/* DISABLES CODE */ (0))
8609 printf("get_hist_last_written: elapsed time %f ms\n", tend-tstart);
8610
8611 return HS_SUCCESS;
8612}
8613
8614void generate_hist_graph(MVOdb* odb, Return* rr, const char *hgroup, const char *hpanel, char *buffer, int *buffer_size,
8615 int width, int height,
8617 int scale,
8618 int index,
8619 int labels, const char *bgcolor, const char *fgcolor, const char *gridcolor)
8620{
8621 HNDLE hDB;
8622 //KEY key;
8623 gdImagePtr im;
8625 int i, j, k, l;
8626 //int n_vars;
8627 int size, status, r, g, b;
8628 //int x_marker;
8629 int length;
8630 int white, grey, red;
8631 //int black, ltgrey, green, blue;
8632 int fgcol, bgcol, gridcol;
8633 int curve_col[MAX_VARS];
8634 int state_col[3];
8635 char str[256], *p;
8636 //INT var_index[MAX_VARS];
8637 //char event_name[MAX_VARS][NAME_LENGTH];
8638 //char tag_name[MAX_VARS][64];
8639 //char var_name[MAX_VARS][NAME_LENGTH];
8640 //char varname[64];
8641 //char key_name[256];
8642 //float factor[MAX_VARS], offset[MAX_VARS];
8643 //BOOL logaxis, runmarker;
8644 //double xmin, xrange;
8645 double ymin, ymax;
8647 //float minvalue = (float) -HUGE_VAL;
8648 //float maxvalue = (float) +HUGE_VAL;
8649 //int show_values = 0;
8650 //int sort_vars = 0;
8651 //int old_vars = 0;
8653 int flags;
8654
8655 time_t now = ss_time();
8656
8657 if (xendtime == 0)
8658 xendtime = now;
8659
8660 HistPlot hp;
8662
8663 std::vector<int> var_index; var_index.resize(hp.vars.size());
8664
8665 for (size_t i=0; i<hp.vars.size(); i++) {
8666 var_index[i] = 0;
8667 const char *vp = strchr(hp.vars[i].tag_name.c_str(), '[');
8668 if (vp) {
8669 var_index[i] = atoi(vp + 1);
8670 }
8671 }
8672
8673 int logaxis = hp.log_axis;
8674 double minvalue = hp.minimum;
8675 double maxvalue = hp.maximum;
8676
8677 if ((minvalue == 0) && (maxvalue == 0)) {
8678 minvalue = -HUGE_VAL;
8679 maxvalue = +HUGE_VAL;
8680 }
8681
8682 std::vector<int> x[MAX_VARS];
8683 std::vector<double> y[MAX_VARS];
8684
8687
8689
8690 /* generate image */
8691 im = gdImageCreate(width, height);
8692
8693 /* allocate standard colors */
8694 sscanf(bgcolor, "%02x%02x%02x", &r, &g, &b);
8695 bgcol = gdImageColorAllocate(im, r, g, b);
8696 sscanf(fgcolor, "%02x%02x%02x", &r, &g, &b);
8697 fgcol = gdImageColorAllocate(im, r, g, b);
8698 sscanf(gridcolor, "%02x%02x%02x", &r, &g, &b);
8699 gridcol = gdImageColorAllocate(im, r, g, b);
8700
8701 grey = gdImageColorAllocate(im, 192, 192, 192);
8702 //ltgrey = gdImageColorAllocate(im, 208, 208, 208);
8703 white = gdImageColorAllocate(im, 255, 255, 255);
8704 //black = gdImageColorAllocate(im, 0, 0, 0);
8705 red = gdImageColorAllocate(im, 255, 0, 0);
8706 //green = gdImageColorAllocate(im, 0, 255, 0);
8707 //blue = gdImageColorAllocate(im, 0, 0, 255);
8708
8709 curve_col[0] = gdImageColorAllocate(im, 0, 0, 255);
8710 curve_col[1] = gdImageColorAllocate(im, 0, 192, 0);
8711 curve_col[2] = gdImageColorAllocate(im, 255, 0, 0);
8712 curve_col[3] = gdImageColorAllocate(im, 0, 192, 192);
8713 curve_col[4] = gdImageColorAllocate(im, 255, 0, 255);
8714 curve_col[5] = gdImageColorAllocate(im, 192, 192, 0);
8715 curve_col[6] = gdImageColorAllocate(im, 128, 128, 128);
8716 curve_col[7] = gdImageColorAllocate(im, 128, 255, 128);
8717 curve_col[8] = gdImageColorAllocate(im, 255, 128, 128);
8718 curve_col[9] = gdImageColorAllocate(im, 128, 128, 255);
8719 for (i=10; i<MAX_VARS; i++)
8720 curve_col[i] = gdImageColorAllocate(im, 128, 128, 128);
8721
8722 state_col[0] = gdImageColorAllocate(im, 255, 0, 0);
8723 state_col[1] = gdImageColorAllocate(im, 255, 255, 0);
8724 state_col[2] = gdImageColorAllocate(im, 0, 255, 0);
8725
8726 /* Set transparent color. */
8728
8729 /* Title */
8730 gdImageString(im, gdFontGiant, width / 2 - (strlen(hpanel) * gdFontGiant->w) / 2, 2, (char*)hpanel, fgcol);
8731
8732 /* connect to history */
8734 if (mh == NULL) {
8735 sprintf(str, "History is not configured, see messages");
8736 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8737 goto error;
8738 }
8739
8741 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
8742 //db_find_key(hDB, 0, str, &hkeypanel);
8743 //if (!hkeypanel) {
8744 // sprintf(str, "Cannot find /History/Display/%s/%s in ODB", hgroup, hpanel);
8745 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8746 // goto error;
8747 //}
8748
8749 //db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8750 //if (!hkeydvar) {
8751 // sprintf(str, "Cannot find /History/Display/%s/%s/Variables in ODB", hgroup, hpanel);
8752 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8753 // goto error;
8754 //}
8755
8756 //db_get_key(hDB, hkeydvar, &key);
8757 //n_vars = key.num_values;
8758
8759 if (hp.vars.empty()) {
8760 sprintf(str, "No variables in panel %s/%s", hgroup, hpanel);
8761 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8762 goto error;
8763 }
8764
8765 if (hp.vars.size() > MAX_VARS) {
8766 sprintf(str, "Too many variables in panel %s/%s", hgroup, hpanel);
8767 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8768 goto error;
8769 }
8770
8771 ymin = ymax = 0;
8772 //logaxis = runmarker = 0;
8773
8774 for (i = 0; i < (int)hp.vars.size(); i++) {
8775 if (index != -1 && index != i)
8776 continue;
8777
8778 //size = sizeof(str);
8779 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8780 //if (status != DB_SUCCESS) {
8781 // sprintf(str, "Cannot read tag %d in panel %s/%s, status %d", i, hgroup, hpanel, status);
8782 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8783 // goto error;
8784 //}
8785 //
8786 //mstrlcpy(tag_name[i], str, sizeof(tag_name[0]));
8787
8789 //char *tp = strchr(tag_name[i], ':');
8790 //if (tp) {
8791 // mstrlcpy(event_name[i], tag_name[i], sizeof(event_name[0]));
8792 // char *ep = strchr(event_name[i], ':');
8793 // if (ep)
8794 // *ep = 0;
8795 // mstrlcpy(var_name[i], tp+1, sizeof(var_name[0]));
8796 // var_index[i] = 0;
8797 // char *vp = strchr(var_name[i], '[');
8798 // if (vp) {
8799 // var_index[i] = atoi(vp + 1);
8800 // *vp = 0;
8801 // }
8802 //} else {
8803 // sprintf(str, "Tag \"%s\" has wrong format in panel \"%s/%s\"", tag_name[i], hgroup, hpanel);
8804 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8805 // goto error;
8806 //}
8807 //
8808 //db_find_key(hDB, hkeypanel, "Colour", &hkey);
8809 //if (hkey) {
8810 // size = sizeof(str);
8811 // status = db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
8812 // if (status == DB_SUCCESS) {
8813 // if (str[0] == '#') {
8814 // char sss[3];
8815 // int r, g, b;
8816 //
8817 // sss[0] = str[1];
8818 // sss[1] = str[2];
8819 // sss[2] = 0;
8820 // r = strtoul(sss, NULL, 16);
8821 // sss[0] = str[3];
8822 // sss[1] = str[4];
8823 // sss[2] = 0;
8824 // g = strtoul(sss, NULL, 16);
8825 // sss[0] = str[5];
8826 // sss[1] = str[6];
8827 // sss[2] = 0;
8828 // b = strtoul(sss, NULL, 16);
8829 //
8830 // curve_col[i] = gdImageColorAllocate(im, r, g, b);
8831 // }
8832 // }
8833 //}
8834
8835 if (hp.vars[i].colour[0] == '#') {
8836 const char* str = hp.vars[i].colour.c_str();
8837 char sss[3];
8838 int r, g, b;
8839
8840 sss[0] = str[1];
8841 sss[1] = str[2];
8842 sss[2] = 0;
8843 r = strtoul(sss, NULL, 16);
8844 sss[0] = str[3];
8845 sss[1] = str[4];
8846 sss[2] = 0;
8847 g = strtoul(sss, NULL, 16);
8848 sss[0] = str[5];
8849 sss[1] = str[6];
8850 sss[2] = 0;
8851 b = strtoul(sss, NULL, 16);
8852
8853 curve_col[i] = gdImageColorAllocate(im, r, g, b);
8854 }
8855
8856 /* get timescale */
8857 if (scale == 0) {
8858 //std::string ts = "1h";
8859 //status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8860 //if (status != DB_SUCCESS) {
8861 // /* delete old integer key */
8862 // db_find_key(hDB, hkeypanel, "Timescale", &hkey);
8863 // if (hkey)
8864 // db_delete_key(hDB, hkey, FALSE);
8865 //
8866 // ts = "1h";
8867 // status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8868 //}
8869
8870 scale = time_to_sec(hp.timescale.c_str());
8871 }
8872
8873 //for (j = 0; j < MAX_VARS; j++) {
8874 // factor[j] = 1;
8875 // offset[j] = 0;
8876 //}
8877
8879 //size = sizeof(float) * n_vars;
8880 //db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
8881
8883 //size = sizeof(float) * n_vars;
8884 //db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
8885
8887 //size = sizeof(logaxis);
8888 //logaxis = 0;
8889 //db_get_value(hDB, hkeypanel, "Log axis", &logaxis, &size, TID_BOOL, TRUE);
8890
8892 //size = sizeof(show_values);
8893 //show_values = 0;
8894 //db_get_value(hDB, hkeypanel, "Show values", &show_values, &size, TID_BOOL, TRUE);
8895
8897 //size = sizeof(sort_vars);
8898 //sort_vars = 0;
8899 //db_get_value(hDB, hkeypanel, "Sort vars", &sort_vars, &size, TID_BOOL, TRUE);
8900
8902 //size = sizeof(old_vars);
8903 //old_vars = 0;
8904 //db_get_value(hDB, hkeypanel, "Show old vars", &old_vars, &size, TID_BOOL, TRUE);
8905
8907 //size = sizeof(minvalue);
8908 //minvalue = (float) -HUGE_VAL;
8909 //db_get_value(hDB, hkeypanel, "Minimum", &minvalue, &size, TID_FLOAT, TRUE);
8910
8912 //size = sizeof(maxvalue);
8913 //maxvalue = (float) +HUGE_VAL;
8914 //db_get_value(hDB, hkeypanel, "Maximum", &maxvalue, &size, TID_FLOAT, TRUE);
8915
8916 //if ((minvalue == 0) && (maxvalue == 0)) {
8917 // minvalue = (float) -HUGE_VAL;
8918 // maxvalue = (float) +HUGE_VAL;
8919 //}
8920
8922 //size = sizeof(runmarker);
8923 //runmarker = 1;
8924 //db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
8925
8926 /* make ODB path from tag name */
8927 std::string odbpath;
8928 HNDLE hkeyeq = 0;
8930 db_find_key(hDB, 0, "/Equipment", &hkeyroot);
8931 if (hkeyroot) {
8932 for (j = 0;; j++) {
8933 HNDLE hkeyeq;
8935
8936 if (!hkeyeq)
8937 break;
8938
8939 KEY key;
8941 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
8942 /* check if variable is individual key under variables/ */
8943 sprintf(str, "Variables/%s", hp.vars[i].tag_name.c_str());
8944 HNDLE hkey;
8946 if (hkey) {
8947 //sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[i], var_name[i]);
8948 odbpath = "";
8949 odbpath += "/Equipment/";
8950 odbpath += hp.vars[i].event_name;
8951 odbpath += "/Variables/";
8952 odbpath += hp.vars[i].tag_name;
8953 break;
8954 }
8955
8956 /* check if variable is in setttins/names array */
8958 db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
8959 if (hkeynames) {
8960 /* extract variable name and Variables/<key> */
8961 mstrlcpy(str, hp.vars[i].tag_name.c_str(), sizeof(str));
8962 p = str + strlen(str) - 1;
8963 while (p > str && *p != ' ')
8964 p--;
8965 std::string key_name = p + 1;
8966 *p = 0;
8967
8968 std::string varname = str;
8969
8970 /* find key in single name array */
8972 for (k = 0; k < key.num_values; k++) {
8973 size = sizeof(str);
8975 if (equal_ustring(str, varname.c_str())) {
8976 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, k);
8977 odbpath = "";
8978 odbpath += "/Equipment/";
8979 odbpath += hp.vars[i].event_name;
8980 odbpath += "/Variables/";
8981 odbpath += key_name;
8982 odbpath += "[";
8983 odbpath += toString(k);
8984 odbpath += "]";
8985 break;
8986 }
8987 }
8988 } else {
8989 /* go through /variables/<name> entries */
8991 db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
8992 if (hkeyvars) {
8993 for (k = 0;; k++) {
8995
8996 if (!hkey)
8997 break;
8998
8999 /* find "settins/names <key>" for this key */
9000 db_get_key(hDB, hkey, &key);
9001
9002 /* find key in key_name array */
9003 std::string key_name = key.name;
9004
9005 std::string path;
9006 //sprintf(str, "Settings/Names %s", key_name);
9007 path += "Settings/Names ";
9008 path += key_name;
9009
9011 db_find_key(hDB, hkeyeq, path.c_str(), &hkeynames);
9012 if (hkeynames) {
9014 for (l = 0; l < key.num_values; l++) {
9015 size = sizeof(str);
9017 if (equal_ustring(str, hp.vars[i].tag_name.c_str())) {
9018 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, l);
9019 odbpath = "";
9020 odbpath += "/Equipment/";
9021 odbpath += hp.vars[i].event_name;
9022 odbpath += "/Variables/";
9023 odbpath += key_name;
9024 odbpath += "[";
9025 odbpath += toString(l);
9026 odbpath += "]";
9027 break;
9028 }
9029 }
9030 }
9031 }
9032 }
9033 }
9034
9035 break;
9036 }
9037 }
9038
9039 if (!hkeyeq) {
9040 db_find_key(hDB, 0, "/History/Links", &hkeyroot);
9041 if (hkeyroot) {
9042 for (j = 0;; j++) {
9043 HNDLE hkey;
9045
9046 if (!hkey)
9047 break;
9048
9049 KEY key;
9050 db_get_key(hDB, hkey, &key);
9051 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
9053 db_find_key(hDB, hkey, hp.vars[i].tag_name.c_str(), &hkey);
9054 if (hkey) {
9055 db_get_key(hDB, hkey, &key);
9057 if (key.num_values > 1) {
9058 odbpath += "[";
9059 odbpath += toString(var_index[i]);
9060 odbpath += "]";
9061 }
9062 break;
9063 }
9064 }
9065 }
9066 }
9067 }
9068 }
9069
9070 /* search alarm limits */
9071 upper_limit[i] = lower_limit[i] = -12345;
9072 db_find_key(hDB, 0, "Alarms/Alarms", &hkeyroot);
9073 if (odbpath.length() > 0 && hkeyroot) {
9074 for (j = 0;; j++) {
9075 HNDLE hkey;
9077
9078 if (!hkey)
9079 break;
9080
9081 size = sizeof(str);
9082 db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
9083
9084 if (strstr(str, odbpath.c_str())) {
9085 if (strchr(str, '<')) {
9086 p = strchr(str, '<') + 1;
9087 if (*p == '=')
9088 p++;
9089 if (hp.enable_factor) {
9090 lower_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9091 } else {
9092 lower_limit[i] = atof(p);
9093 }
9094 }
9095 if (strchr(str, '>')) {
9096 p = strchr(str, '>') + 1;
9097 if (*p == '=')
9098 p++;
9099 if (hp.enable_factor) {
9100 upper_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9101 } else {
9102 upper_limit[i] = atof(p);
9103 }
9104 }
9105 }
9106 }
9107 }
9108 } // loop over variables
9109
9110 //starttime = now - scale + toffset;
9111 //endtime = now + toffset;
9112
9113 starttime = xendtime - scale;
9114 endtime = xendtime;
9115
9116 //printf("now %d, scale %d, xendtime %d, starttime %d, endtime %d\n", now, scale, xendtime, starttime, endtime);
9117
9118 flags = READ_HISTORY_DATA;
9119 if (hp.show_run_markers)
9120 flags |= READ_HISTORY_RUNMARKER;
9121
9122 status = read_history(hp, /*hDB, hgroup, hpanel,*/ index, flags, starttime, endtime, scale/1000+1, hsdata);
9123
9124 if (status != HS_SUCCESS) {
9125 sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
9126 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
9127 goto error;
9128 }
9129
9131 char var_status[MAX_VARS][256];
9132
9133 for (int k=0; k<hsdata->nvars; k++) {
9134 int i = hsdata->odb_index[k];
9135
9136 if (i<0)
9137 continue;
9138
9139 if (index != -1 && index != i)
9140 continue;
9141
9142 n_point[i] = 0;
9143
9144 var_status[i][0] = 0;
9145 if (hsdata->status[k] == HS_UNDEFINED_VAR) {
9146 sprintf(var_status[i], "not found in history");
9147 continue;
9148 } else if (hsdata->status[k] != HS_SUCCESS) {
9149 sprintf(var_status[i], "hs_read() error %d, see messages", hsdata->status[k]);
9150 continue;
9151 }
9152
9153 int n_vp = 0;
9154 for (int j=0; j<hsdata->num_entries[k]; j++) {
9155 int xx = (int)(hsdata->t[k][j]);
9156 double yy = hsdata->v[k][j];
9157
9158 /* skip NaNs */
9159 if (ss_isnan(yy))
9160 continue;
9161
9162 /* skip INFs */
9163 if (!ss_isfin(yy))
9164 continue;
9165
9166 /* avoid overflow */
9167 if (yy > 1E30)
9168 yy = 1E30f;
9169
9170 /* apply factor and offset */
9171 if (hp.enable_factor) {
9172 yy = hp.vars[i].factor * (yy - hp.vars[i].voffset) + hp.vars[i].offset;
9173 }
9174
9175 /* calculate ymin and ymax */
9176 if ((i == 0 || index != -1) && n_vp == 0)
9177 ymin = ymax = yy;
9178 else {
9179 if (yy > ymax)
9180 ymax = yy;
9181 if (yy < ymin)
9182 ymin = yy;
9183 }
9184
9185 /* increment number of valid points */
9186
9187 x[i].push_back(xx);
9188 y[i].push_back(yy);
9189
9190 n_vp++;
9191
9192 } // loop over data
9193
9194 n_point[i] = n_vp;
9195
9196 assert(x[i].size() == y[i].size());
9197 }
9198
9199 //int flag;
9200 int xmaxm;
9201 int row;
9202 int xold;
9203 int yold;
9204 int aoffset;
9205 double yb1, yb2, yf1, yf2;
9206 int xs, ys;
9207 int x1, x2;
9208 int y1, y2;
9209 int xs_old;
9210 double ybase;
9211
9212 gdPoint poly[3];
9213
9214 if (ymin < minvalue)
9215 ymin = minvalue;
9216
9217 if (ymax > maxvalue)
9218 ymax = maxvalue;
9219
9220 /* check if ylow = 0 */
9221 if (index == -1) {
9222 //flag = 0;
9223 //size = sizeof(flag);
9224 //db_get_value(hDB, hkeypanel, "Zero ylow", &flag, &size, TID_BOOL, TRUE);
9225 if (hp.zero_ylow && ymin > 0)
9226 ymin = 0;
9227 }
9228
9229 /* if min and max too close together, switch to linear axis */
9230 if (logaxis && ymin > 0 && ymax > 0) {
9231 yb1 = pow(10, floor(log(ymin) / LN10));
9232 yf1 = floor(ymin / yb1);
9233 yb2 = pow(10, floor(log(ymax) / LN10));
9234 yf2 = floor(ymax / yb2);
9235
9236 if (yb1 == yb2 && yf1 == yf2)
9237 logaxis = 0;
9238 else {
9239 /* round down and up ymin and ymax */
9240 ybase = pow(10, floor(log(ymin) / LN10));
9241 ymin = (floor(ymin / ybase) * ybase);
9242 ybase = pow(10, floor(log(ymax) / LN10));
9243 ymax = ((floor(ymax / ybase) + 1) * ybase);
9244 }
9245 }
9246
9247 /* avoid negative limits for log axis */
9248 if (logaxis) {
9249 if (ymax <= 0)
9250 ymax = 1;
9251 if (ymin <= 0)
9252 ymin = 1E-12f;
9253 }
9254
9255 /* increase limits by 5% */
9256 if (ymin == 0 && ymax == 0) {
9257 ymin = -1;
9258 ymax = 1;
9259 } else {
9260 if (!logaxis) {
9261 ymax += (ymax - ymin) / 20.f;
9262
9263 if (ymin != 0)
9264 ymin -= (ymax - ymin) / 20.f;
9265 }
9266 }
9267
9268 /* avoid ymin == ymax */
9269 if (ymax == ymin) {
9270 if (logaxis) {
9271 ymax *= 2;
9272 ymin /= 2;
9273 } else {
9274 ymax += 10;
9275 ymin -= 10;
9276 }
9277 }
9278
9279 /* calculate X limits */
9280 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9281 //xmax = (double) (toffset / 3600.0);
9282 //xrange = xmax - xmin;
9283 //xrange = scale/3600.0;
9284
9285 /* caluclate required space for Y-axis */
9286 aoffset = vaxis(im, gdFontSmall, fgcol, gridcol, 0, 0, height, -3, -5, -7, -8, 0, ymin, ymax, logaxis);
9287 aoffset += 2;
9288
9289 x1 = aoffset;
9290 y1 = height - 20;
9291 x2 = width - 20;
9292 y2 = 20;
9293
9295
9296 /* draw axis frame */
9297 taxis(im, gdFontSmall, fgcol, gridcol, x1, y1, x2 - x1, width, 3, 5, 9, 10, 0, (double)starttime, (double)endtime);
9298
9299 vaxis(im, gdFontSmall, fgcol, gridcol, x1, y1, y1 - y2, -3, -5, -7, -8, x2 - x1, ymin, ymax, logaxis);
9300 gdImageLine(im, x1, y2, x2, y2, fgcol);
9301 gdImageLine(im, x2, y2, x2, y1, fgcol);
9302
9303 xs = ys = xold = yold = 0;
9304
9305 /* old code for run markers, new code is below */
9306
9307 /* write run markes if selected */
9308 if (/* DISABLES CODE */ (0) && hp.show_run_markers) {
9309
9310 const char* event_names[] = {
9311 "Run transitions",
9312 "Run transitions",
9313 0 };
9314
9315 const char* tag_names[] = {
9316 "State",
9317 "Run number",
9318 0 };
9319
9320 const int tag_indexes[] = {
9321 0,
9322 0,
9323 0 };
9324
9325 int num_entries[3];
9326 time_t *tbuf[3];
9327 double *dbuf[3];
9328 int st[3];
9329
9330 num_entries[0] = 0;
9331 num_entries[1] = 0;
9332
9333 status = mh->hs_read(starttime - scale, endtime, 0,
9334 2, event_names, tag_names, tag_indexes,
9335 num_entries, tbuf, dbuf, st);
9336
9337 //printf("read run info: status %d, entries %d %d\n", status, num_entries[0], num_entries[1]);
9338
9339 int n_marker = num_entries[0];
9340
9341 if (status == HS_SUCCESS && n_marker > 0 && n_marker < 100) {
9342 xs_old = -1;
9343 xmaxm = x1;
9344 for (j = 0; j < (int) n_marker; j++) {
9345 int col;
9346
9347 // explicit algebra manipulation to clarify computations:
9348
9349 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9350 //xrange = scale/3600.0;
9351 //time_t starttime = now - scale + toffset;
9352
9353 //x_marker = (int)(tbuf[1][j] - now);
9354 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9355 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9356 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9357 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9358 xs = (int) ((tbuf[1][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9359
9360 if (xs < x1)
9361 continue;
9362 if (xs >= x2)
9363 continue;
9364
9365 double run_number = dbuf[1][j];
9366
9367 if (xs <= xs_old)
9368 xs = xs_old + 1;
9369 xs_old = xs;
9370
9371 if (dbuf[0][j] == 1)
9372 col = state_col[0];
9373 else if (dbuf[0][j] == 2)
9374 col = state_col[1];
9375 else if (dbuf[0][j] == 3)
9376 col = state_col[2];
9377 else
9378 col = state_col[0];
9379
9381
9382 sprintf(str, "%.0f", run_number);
9383
9384 if (dbuf[0][j] == STATE_RUNNING) {
9385 if (xs > xmaxm) {
9387 xmaxm = xs - 2 + gdFontSmall->h;
9388 }
9389 } else if (dbuf[0][j] == STATE_STOPPED) {
9390 if (xs + 2 - gdFontSmall->h > xmaxm) {
9392 xmaxm = xs - 1;
9393 }
9394 }
9395 }
9396 }
9397
9398 if (num_entries[0]) {
9399 free(tbuf[0]);
9400 free(dbuf[0]);
9401 tbuf[0] = NULL;
9402 dbuf[0] = NULL;
9403 }
9404
9405 if (num_entries[1]) {
9406 free(tbuf[1]);
9407 free(dbuf[1]);
9408 tbuf[1] = NULL;
9409 dbuf[1] = NULL;
9410 }
9411 }
9412
9413 /* write run markes if selected */
9414 if (hp.show_run_markers) {
9415
9416 int index_state = -1;
9417 int index_run_number = -1;
9418
9419 for (int k=0; k<hsdata->nvars; k++) {
9420 if (hsdata->odb_index[k] == -1)
9421 index_state = k;
9422
9423 if (hsdata->odb_index[k] == -2)
9425 }
9426
9427 bool ok = true;
9428
9429 if (ok)
9430 ok = (index_state >= 0) && (index_run_number >= 0);
9431
9432 if (ok)
9433 ok = (hsdata->status[index_state] == HS_SUCCESS);
9434
9435 if (ok)
9436 ok = (hsdata->status[index_run_number] == HS_SUCCESS);
9437
9438 if (/* DISABLES CODE */ (0) && ok)
9439 printf("read run info: indexes: %d, %d, status: %d, %d, entries: %d, %d\n", index_state, index_run_number, hsdata->status[index_state], hsdata->status[index_run_number], hsdata->num_entries[index_state], hsdata->num_entries[index_run_number]);
9440
9441 if (ok)
9442 ok = (hsdata->num_entries[index_state] == hsdata->num_entries[index_run_number]);
9443
9444 int n_marker = hsdata->num_entries[index_state];
9445
9446 if (ok && n_marker > 0 && n_marker < 100) {
9447 xs_old = -1;
9448 xmaxm = x1;
9449 for (j = 0; j < (int) n_marker; j++) {
9450 int col;
9451
9452 // explicit algebra manipulation to clarify computations:
9453
9454 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9455 //xrange = scale/3600.0;
9456 //time_t starttime = now - scale + toffset;
9457
9458 //x_marker = (int)(tbuf[1][j] - now);
9459 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9460 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9461 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9462 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9463 xs = (int) ((hsdata->t[index_state][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9464
9465 if (xs < x1)
9466 continue;
9467 if (xs >= x2)
9468 continue;
9469
9470 double run_number = hsdata->v[index_run_number][j];
9471
9472 if (xs <= xs_old)
9473 xs = xs_old + 1;
9474 xs_old = xs;
9475
9476 int state = (int)hsdata->v[index_state][j];
9477
9478 if (state == 1)
9479 col = state_col[0];
9480 else if (state == 2)
9481 col = state_col[1];
9482 else if (state == 3)
9483 col = state_col[2];
9484 else
9485 col = state_col[0];
9486
9488
9489 sprintf(str, "%.0f", run_number);
9490
9491 if (state == STATE_RUNNING) {
9492 if (xs > xmaxm) {
9494 xmaxm = xs - 2 + gdFontSmall->h;
9495 }
9496 } else if (state == STATE_STOPPED) {
9497 if (xs + 2 - gdFontSmall->h > xmaxm) {
9499 xmaxm = xs - 1;
9500 }
9501 }
9502 }
9503 }
9504 }
9505
9506 for (i = 0; i < (int)hp.vars.size(); i++) {
9507 if (index != -1 && index != i)
9508 continue;
9509
9510 /* draw alarm limits */
9511 if (lower_limit[i] != -12345) {
9512 if (logaxis) {
9513 if (lower_limit[i] <= 0)
9514 ys = y1;
9515 else
9516 ys = (int) (y1 - (log(lower_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9517 } else {
9518 ys = (int) (y1 - (lower_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9519 }
9520
9521 if (xs < 0)
9522 xs = 0;
9523 if (xs >= width)
9524 xs = width-1;
9525 if (ys < 0)
9526 ys = 0;
9527 if (ys >= height)
9528 ys = height-1;
9529
9530 if (ys > y2 && ys < y1) {
9532
9533 poly[0].x = x1;
9534 poly[0].y = ys;
9535 poly[1].x = x1 + 5;
9536 poly[1].y = ys;
9537 poly[2].x = x1;
9538 poly[2].y = ys - 5;
9539
9541 }
9542 }
9543 if (upper_limit[i] != -12345) {
9544 if (logaxis) {
9545 if (upper_limit[i] <= 0)
9546 ys = y1;
9547 else
9548 ys = (int) (y1 - (log(upper_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9549 } else {
9550 ys = (int) (y1 - (upper_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9551 }
9552
9553 if (xs < 0)
9554 xs = 0;
9555 if (xs >= width)
9556 xs = width-1;
9557 if (ys < 0)
9558 ys = 0;
9559 if (ys >= height)
9560 ys = height-1;
9561
9562 if (ys > y2 && ys < y1) {
9564
9565 poly[0].x = x1;
9566 poly[0].y = ys;
9567 poly[1].x = x1 + 5;
9568 poly[1].y = ys;
9569 poly[2].x = x1;
9570 poly[2].y = ys + 5;
9571
9573 }
9574 }
9575
9576 for (j = 0; j < (int) n_point[i]; j++) {
9577 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9578 //xrange = scale/3600.0;
9579 //xs = (int) (((x[i][j]-now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9580 //xs = (int) (((x[i][j] - now + scale - toffset) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9581 //xs = (int) (((x[i][j] - starttime) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9582 xs = (int) (((x[i][j] - starttime)/1.0) / (1.0*scale) * (x2 - x1) + x1 + 0.5);
9583
9584 if (logaxis) {
9585 if (y[i][j] <= 0)
9586 ys = y1;
9587 else
9588 ys = (int) (y1 - (log(y[i][j]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9589 } else {
9590 ys = (int) (y1 - (y[i][j] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9591 }
9592
9593 if (xs < 0)
9594 xs = 0;
9595 if (xs >= width)
9596 xs = width-1;
9597 if (ys < 0)
9598 ys = 0;
9599 if (ys >= height)
9600 ys = height-1;
9601
9602 if (j > 0)
9604 xold = xs;
9605 yold = ys;
9606 }
9607
9608 if (n_point[i] > 0) {
9609 poly[0].x = xs;
9610 poly[0].y = ys;
9611 poly[1].x = xs + 12;
9612 poly[1].y = ys - 6;
9613 poly[2].x = xs + 12;
9614 poly[2].y = ys + 6;
9615
9617 }
9618 }
9619
9620 if (labels) {
9621 for (i = 0; i < (int)hp.vars.size(); i++) {
9622 if (index != -1 && index != i)
9623 continue;
9624
9625 //str[0] = 0;
9626 //status = db_find_key(hDB, hkeypanel, "Label", &hkeydvar);
9627 //if (status == DB_SUCCESS) {
9628 // size = sizeof(str);
9629 // status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
9630 //}
9631
9632 std::string str = hp.vars[i].label.c_str();
9633
9634 if (str.empty()) {
9635 if (hp.enable_factor) {
9636 str = hp.vars[i].tag_name;
9637
9638 if (hp.vars[i].voffset > 0)
9639 str += msprintf(" - %G", hp.vars[i].voffset);
9640 else if (hp.vars[i].voffset < 0)
9641 str += msprintf(" + %G", -hp.vars[i].voffset);
9642
9643 if (hp.vars[i].factor != 1) {
9644 if (hp.vars[i].voffset == 0)
9645 str += msprintf(" * %+G", hp.vars[i].factor);
9646 else {
9647 str = msprintf("(%s) * %+G", str.c_str(), hp.vars[i].factor);
9648 }
9649 }
9650
9651 if (hp.vars[i].offset > 0)
9652 str += msprintf(" + %G", hp.vars[i].offset);
9653 else if (hp.vars[i].offset < 0)
9654 str += msprintf(" - %G", -hp.vars[i].offset);
9655
9656 } else {
9657 str = hp.vars[i].tag_name;
9658 }
9659 }
9660
9661 int k=0;
9662 for (int j=0; j<hsdata->nvars; j++)
9663 if (hsdata->odb_index[j] == i) {
9664 k = j;
9665 break;
9666 }
9667
9668 if (/* DISABLES CODE */ (0)) {
9669 printf("graph %d: odb index %d, n_point %d, num_entries %d, have_last_written %d %d, status %d, var_status [%s]\n", i, k, n_point[i], hsdata->num_entries[k], hsdata->have_last_written, (int)hsdata->last_written[k], hsdata->status[k], var_status[i]);
9670 }
9671
9672 if (hp.show_values) {
9673 char xstr[256];
9674 if (n_point[i] > 0) {
9675 sprintf(xstr," = %g", y[i][n_point[i]-1]);
9676 } else if (hsdata->num_entries[k] > 0) {
9677 sprintf(xstr," = all data is NaN or INF");
9678 } else if (hsdata->have_last_written) {
9679 if (hsdata->last_written[k]) {
9680 char ctimebuf[32];
9681 ctime_r(&hsdata->last_written[k], ctimebuf);
9682 sprintf(xstr," = last data %s", ctimebuf);
9683 // kill trailing '\n'
9684 char*s = strchr(xstr, '\n');
9685 if (s) *s=0;
9686 // clear the unnecessary error status report
9687 if (hsdata->status[k] == HS_UNDEFINED_VAR)
9688 var_status[i][0] = 0;
9689 } else {
9690 sprintf(xstr," = no data ever");
9691 }
9692 } else {
9693 sprintf(xstr," = no data");
9694 }
9695 str += xstr;
9696 }
9697
9698 if (strlen(var_status[i]) > 1) {
9699 str += msprintf(" (%s)", var_status[i]);
9700 }
9701
9702 row = index == -1 ? i : 0;
9703
9705 x1 + 10,
9706 y2 + 10 + row * (gdFontMediumBold->h + 10),
9707 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9708 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9709 gdFontMediumBold->h + 2 + 2, white);
9710 gdImageRectangle(im, x1 + 10, y2 + 10 + row * (gdFontMediumBold->h + 10),
9711 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9712 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9713 gdFontMediumBold->h + 2 + 2, curve_col[i]);
9714
9716 x1 + 10 + 5, y2 + 10 + 2 + row * (gdFontMediumBold->h + 10),
9717 (char*)str.c_str(),
9718 curve_col[i]);
9719 }
9720 }
9721
9723
9724 error:
9725
9726 /* generate GIF */
9727 gdImageInterlace(im, 1);
9728 gdImageGif(im, &gb);
9730 length = gb.size;
9731
9732 if (buffer == NULL) {
9733 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
9734 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
9735
9736 rr->rsprintf("Content-Type: image/gif\r\n");
9737 rr->rsprintf("Content-Length: %d\r\n", length);
9738 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
9739 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
9740
9741 rr->rmemcpy(gb.data, length);
9742 } else {
9743 if (length > *buffer_size) {
9744 printf("return buffer too small\n");
9745 return;
9746 }
9747
9748 memcpy(buffer, gb.data, length);
9749 *buffer_size = length;
9750 }
9751}
9752
9753/*------------------------------------------------------------------*/
9754
9756{
9757 // this silly stuff is required to correctly handle daylight savings time (Summer time/Winter time)
9758 // when we fill "struct tm" from user input, we cannot know if daylight savings time is in effect
9759 // and we do not know how to initialize the value of tms.tm_isdst.
9760 // This can cause the output of mktime() to be off by one hour.
9761 // (Rules for daylight savings time are set by national and local govt and in some locations, changes yearly)
9762 // (There are no locations with 2 hour or half-hour daylight savings that I know of)
9763 // (Yes, "man mktime" talks about using "tms.tm_isdst = -1")
9764 //
9765 // We assume the user is using local time and we convert in two steps:
9766 //
9767 // first we convert "struct tm" to "time_t" using mktime() with unknown tm_isdst
9768 // second we convert "time_t" back to "struct tm" using localtime_r()
9769 // this fills "tm_isdst" with correct value from the system time zone database
9770 // then we reset all the time fields (except for sub-minute fields not affected by daylight savings)
9771 // and call mktime() again, now with the correct value of "tm_isdst".
9772 // K.O. 2013-09-14
9773
9774 struct tm tms = *ptms;
9775 struct tm tms2;
9776 time_t t1 = ss_mktime(&tms);
9777 localtime_r(&t1, &tms2);
9778 tms2.tm_year = ptms->tm_year;
9779 tms2.tm_mon = ptms->tm_mon;
9780 tms2.tm_mday = ptms->tm_mday;
9781 tms2.tm_hour = ptms->tm_hour;
9782 tms2.tm_min = ptms->tm_min;
9783 time_t t2 = ss_mktime(&tms2);
9784 //printf("t1 %.0f, t2 %.0f, diff %d\n", (double)t1, (double)t2, (int)(t1-t2));
9785 return t2;
9786}
9787
9788/*------------------------------------------------------------------*/
9789
9790static std::string add_param_to_url(const char* name, const char* value)
9791{
9792 std::string s;
9793 s += name; // FIXME: should be URI-encoded
9794 s += "=";
9795 s += value; // FIXME: should be URI-encoded
9796 return s;
9797}
9798
9799/*------------------------------------------------------------------*/
9800
9802{
9803 int i;
9804 HNDLE hDB;
9805
9806 if (p->getparam("m1") && *p->getparam("m1")) {
9807 struct tm tms;
9808 memset(&tms, 0, sizeof(struct tm));
9809
9810 tms.tm_year = atoi(p->getparam("y1")) % 100;
9811
9812 std::string m1 = p->getparam("m1");
9813 for (i = 0; i < 12; i++)
9814 if (equal_ustring(m1.c_str(), mname[i]))
9815 break;
9816 if (i == 12)
9817 i = 0;
9818
9819 tms.tm_mon = i;
9820 tms.tm_mday = atoi(p->getparam("d1"));
9821 tms.tm_hour = atoi(p->getparam("h1"));
9822
9823 if (tms.tm_year < 90)
9824 tms.tm_year += 100;
9825
9827
9828 memset(&tms, 0, sizeof(struct tm));
9829 tms.tm_year = atoi(p->getparam("y2")) % 100;
9830
9831 std::string m2 = p->getparam("m2");
9832 for (i = 0; i < 12; i++)
9833 if (equal_ustring(m2.c_str(), mname[i]))
9834 break;
9835 if (i == 12)
9836 i = 0;
9837
9838 tms.tm_mon = i;
9839 tms.tm_mday = atoi(p->getparam("d2"));
9840 tms.tm_hour = atoi(p->getparam("h2"));
9841
9842 if (tms.tm_year < 90)
9843 tms.tm_year += 100;
9844
9846
9847 if (ltime_end == ltime_start)
9848 ltime_end += 3600 * 24;
9849
9850 std::string redir;
9851 redir += "?cmd=oldhistory&";
9852 redir += add_param_to_url("group", p->getparam("group"));
9853 redir += "&";
9854 redir += add_param_to_url("panel", p->getparam("panel"));
9855 redir += "&";
9856 redir += add_param_to_url("scale", toString((int)(ltime_end - ltime_start)).c_str());
9857 redir += "&";
9859 if (p->isparam("hindex")) {
9860 redir += "&";
9861 redir += add_param_to_url("index", p->getparam("hindex"));
9862 }
9863 redirect(r, redir.c_str());
9864 return;
9865 }
9866
9868 show_header(r, "History", "GET", "", 0);
9869
9870 /* set the times */
9871
9872 time_t now = time(NULL);
9873
9874 time_t starttime = now - 3600 * 24;
9875 time_t endtime = now;
9876 bool full_day = true;
9877
9878 if (p->isparam("htime")) {
9879 endtime = string_to_time(p->getparam("htime"));
9880
9881 if (p->isparam("hscale")) {
9882 starttime = endtime - atoi(p->getparam("hscale"));
9883 full_day = false;
9884 } else {
9885 starttime = endtime - 3600 * 24;
9886 full_day = false;
9887 }
9888 }
9889
9890 /* menu buttons */
9891 r->rsprintf("<tr><td colspan=2>\n");
9892 r->rsprintf("<input type=hidden name=cmd value=OldHistory>\n");
9893 r->rsprintf("<input type=submit name=hcmd value=Query>\n");
9894 r->rsprintf("<input type=submit name=hcmd value=Cancel>\n");
9895 if (p->isparam("group"))
9896 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", p->getparam("group"));
9897 if (p->isparam("panel"))
9898 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", p->getparam("panel"));
9899 if (p->isparam("htime"))
9900 r->rsprintf("<input type=hidden name=htime value=\"%s\">\n", p->getparam("htime"));
9901 if (p->isparam("hscale"))
9902 r->rsprintf("<input type=hidden name=hscale value=\"%s\">\n", p->getparam("hscale"));
9903 if (p->isparam("hindex"))
9904 r->rsprintf("<input type=hidden name=hindex value=\"%s\">\n", p->getparam("hindex"));
9905 r->rsprintf("</tr>\n\n");
9906 r->rsprintf("</table>"); //end header
9907
9908 r->rsprintf("<table class=\"dialogTable\">"); //main table
9909
9910 struct tm tms;
9912 tms.tm_year += 1900;
9913
9914 r->rsprintf("<tr><td nowrap>Start date:</td>");
9915
9916 r->rsprintf("<td>Month: <select name=\"m1\">\n");
9917 r->rsprintf("<option value=\"\">\n");
9918 for (i = 0; i < 12; i++)
9919 if (i == tms.tm_mon)
9920 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9921 else
9922 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9923 r->rsprintf("</select>\n");
9924
9925 r->rsprintf("&nbsp;Day: <select name=\"d1\">");
9926 r->rsprintf("<option selected value=\"\">\n");
9927 for (i = 0; i < 31; i++)
9928 if (i + 1 == tms.tm_mday)
9929 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9930 else
9931 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9932 r->rsprintf("</select>\n");
9933
9934 int start_hour = tms.tm_hour;
9935 if (full_day)
9936 start_hour = 0;
9937
9938 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h1\" value=\"%d\">", start_hour);
9939
9940 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">", tms.tm_year);
9941 r->rsprintf("</td></tr>\n");
9942
9943 r->rsprintf("<tr><td nowrap>End date:</td>");
9944
9946 tms.tm_year += 1900;
9947
9948 r->rsprintf("<td>Month: <select name=\"m2\">\n");
9949 r->rsprintf("<option value=\"\">\n");
9950 for (i = 0; i < 12; i++)
9951 if (i == tms.tm_mon)
9952 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9953 else
9954 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9955 r->rsprintf("</select>\n");
9956
9957 r->rsprintf("&nbsp;Day: <select name=\"d2\">");
9958 r->rsprintf("<option selected value=\"\">\n");
9959 for (i = 0; i < 31; i++)
9960 if (i + 1 == tms.tm_mday)
9961 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9962 else
9963 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9964 r->rsprintf("</select>\n");
9965
9966 int end_hour = tms.tm_hour;
9967 if (full_day)
9968 end_hour = 24;
9969
9970 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h2\" value=\"%d\">", end_hour);
9971
9972 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y2\" value=\"%d\">", tms.tm_year);
9973 r->rsprintf("</td></tr>\n");
9974
9975 r->rsprintf("</table>\n");
9976 r->rsprintf("</div>\n"); // closing for <div id="mmain">
9977 r->rsprintf("</form>\n");
9978 r->rsprintf("</body></html>\r\n");
9979}
9980
9981/*------------------------------------------------------------------*/
9982/* history plot code starts here */
9983/*------------------------------------------------------------------*/
9984
9985static int cmp_names(const void *a, const void *b)
9986{
9987 int i;
9988 const char*sa = (const char*)a;
9989 const char*sb = (const char*)b;
9990
9991 int debug = 0;
9992
9993 // Cannot use strcmp() because it does not know how to compare numerical values, e.g.
9994 // it thinks "111" is smaller than "9"
9995 //return strcmp(sa, sb);
9996
9997 if (debug)
9998 printf("compare [%s] and [%s]\n", sa, sb);
9999
10000 for (i=0; ; i++) {
10001 if (sa[i]==0 && sb[i]==0)
10002 return 0; // both strings have the same length and the same characters
10003
10004 //printf("index %d, char [%c] [%c], isdigit %d %d\n", i, sa[i], sb[i], isdigit(sa[i]), isdigit(sb[i]));
10005
10006 if (isdigit(sa[i]) && isdigit(sb[i])) {
10007 int va = atoi(sa+i);
10008 int vb = atoi(sb+i);
10009
10010 if (debug)
10011 printf("index %d, values %d %d\n", i, va, vb);
10012
10013 if (va < vb)
10014 return -1;
10015 else if (va > vb)
10016 return 1;
10017
10018 // values are equal, skip the the end of the digits, compare any trailing text
10019 continue;
10020 }
10021
10022 if (sa[i]==sb[i]) {
10023 continue;
10024 }
10025
10026 if (debug)
10027 printf("index %d, char [%c] [%c]\n", i, sa[i], sb[i]);
10028
10029 if (sa[i] == 0) // string sa is shorter
10030 return -1;
10031 else if (sb[i] == 0) // string sb is shorter
10032 return 1;
10033
10034 if (sa[i]<sb[i])
10035 return -1;
10036 else
10037 return 1;
10038 }
10039
10040 // NOT REACHED
10041}
10042
10043const bool cmp_events(const std::string& a, const std::string& b)
10044{
10045 return cmp_names(a.c_str(), b.c_str()) < 0;
10046}
10047
10048const bool cmp_events1(const std::string& a, const std::string& b)
10049{
10050 return a < b;
10051}
10052
10053const bool cmp_tags(const TAG& a, const TAG& b)
10054{
10055 return cmp_names(a.name, b.name) < 0;
10056}
10057
10058#if 0
10059static int cmp_tags(const void *a, const void *b)
10060{
10061 const TAG*sa = (const TAG*)a;
10062 const TAG*sb = (const TAG*)b;
10063 return cmp_names(sa->name, sb->name);
10064}
10065
10066static void sort_tags(int ntags, TAG* tags)
10067{
10068 qsort(tags, ntags, sizeof(TAG), cmp_tags);
10069}
10070#endif
10071
10072int xdb_get_data_index(HNDLE hDB, const char* str, void *value, int size, int index, int tid)
10073{
10074 HNDLE hKey;
10075 int status = db_find_key(hDB, 0, str, &hKey);
10076 if (status != DB_SUCCESS)
10077 return status;
10078
10079 KEY key;
10080 db_get_key(hDB, hKey, &key);
10081 if (index >= key.num_values)
10082 return DB_OUT_OF_RANGE;
10083
10084 status = db_get_data_index(hDB, hKey, value, &size, index, tid);
10085 return status;
10086}
10087
10088static int xdb_find_key(HNDLE hDB, HNDLE dir, const char* str, HNDLE* hKey, int tid, int size)
10089{
10090 int status = db_find_key(hDB, dir, str, hKey);
10091 if (status == DB_SUCCESS)
10092 return status;
10093
10094 db_create_key(hDB, dir, str, tid);
10095 status = db_find_key(hDB, dir, str, hKey);
10096 if (status != DB_SUCCESS || !*hKey) {
10097 cm_msg(MERROR, "xdb_find_key", "Invalid ODB path \"%s\"", str);
10098 str = "bad_xdb_find_key";
10099 db_create_key(hDB, dir, str, tid);
10100 db_find_key(hDB, dir, str, hKey);
10101 }
10102 assert(*hKey);
10103
10104 if (tid == TID_STRING) {
10105 db_set_data_index(hDB, *hKey, "", size, 0, TID_STRING);
10106 }
10107
10108 return status;
10109}
10110
10111static bool cmp_vars(const HistVar &a, const HistVar &b)
10112{
10113 return a.order < b.order;
10114}
10115
10116static void PrintHistPlot(const HistPlot& hp)
10117{
10118 printf("hist plot: %d variables\n", (int)hp.vars.size());
10119 printf("timescale: %s, minimum: %f, maximum: %f, zero_ylow: %d, log_axis: %d, show_run_markers: %d, show_values: %d, show_fill: %d, show_factor %d, enable_factor: %d\n", hp.timescale.c_str(), hp.minimum, hp.maximum, hp.zero_ylow, hp.log_axis, hp.show_run_markers, hp.show_values, hp.show_fill, hp.show_factor, hp.enable_factor);
10120
10121 for (size_t i=0; i<hp.vars.size(); i++) {
10122 printf("var[%d] event [%s][%s] formula [%s], colour [%s] label [%s] show_raw_value %d factor %f offset %f voffset %f order %d\n", (int)i, hp.vars[i].event_name.c_str(), hp.vars[i].tag_name.c_str(), hp.vars[i].formula.c_str(), hp.vars[i].colour.c_str(), hp.vars[i].label.c_str(), hp.vars[i].show_raw_value, hp.vars[i].factor, hp.vars[i].offset , hp.vars[i].voffset, hp.vars[i].order);
10123 }
10124}
10125
10126static std::string NextHistPlotColour(const HistPlot& hp)
10127{
10128 const char* const colour[] =
10129 {
10130 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
10131 "#A0C0D0", "#D0A060", "#C04010", "#807060",
10132 "#F0C000", "#2090A0", "#D040D0", "#90B000",
10133 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
10134 NULL };
10135
10136 for (int i=0; colour[i]; i++) {
10137 bool in_use = false;
10138
10139 for (size_t j=0; j<hp.vars.size(); j++)
10140 if (hp.vars[j].colour == colour[i]) {
10141 in_use = true;
10142 break;
10143 }
10144
10145 if (!in_use)
10146 return colour[i];
10147 }
10148
10149 return "#808080";
10150}
10151
10153{
10154 int order = 0;
10155 for (size_t i=0; i<hp.vars.size(); i++)
10156 if (hp.vars[i].order > order)
10157 order = hp.vars[i].order;
10158 return order + 10;
10159}
10160
10161static void SplitEventAndTagNames(std::string var_name, std::string& event_name, std::string& tag_name) {
10162 event_name = "";
10163 tag_name = "";
10164
10165 std::vector<size_t> colons;
10166
10167 for (size_t i = 0; i < var_name.size(); i++) {
10168 if (var_name[i] == ':') {
10169 colons.push_back(i);
10170 }
10171 }
10172
10173 if (colons.size() == 0) {
10174 // No colons - leave the tag name empty
10175 event_name = var_name;
10176 } else {
10177 size_t split_pos;
10178 size_t slash_pos = var_name.find("/");
10179 bool uses_per_variable_naming = (slash_pos != std::string::npos);
10180
10181 if (uses_per_variable_naming && colons.size() % 2 == 1) {
10182 size_t middle_colon_pos = colons[colons.size() / 2];
10183 std::string slash_to_mid = var_name.substr(slash_pos + 1, middle_colon_pos - slash_pos - 1);
10184 std::string mid_to_end = var_name.substr(middle_colon_pos + 1);
10185
10186 if (slash_to_mid == mid_to_end) {
10187 // Special case - we have a string of the form Beamlime/GS2:FC1:GS2:FC1.
10188 // Logger has already warned people that having colons in the equipment/event
10189 // names is a bad idea, so we only need to worry about them in the tag name.
10191 } else {
10192 // We have a string of the form Beamlime/Demand:GS2:FC1. Split at the first colon.
10193 split_pos = colons[0];
10194 }
10195 } else {
10196 // Normal case - split at the fist colon.
10197 split_pos = colons[0];
10198 }
10199
10200 event_name = var_name.substr(0, split_pos);
10201 tag_name = var_name.substr(split_pos + 1);
10202 }
10203}
10204
10205static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel)
10206{
10207 std::string path = "History/Display/";
10208 path += group;
10209 path += "/";
10210 path += panel;
10211
10212 MVOdb* o = odb->Chdir(path.c_str());
10213 if (!o) {
10214 return;
10215 }
10216
10217 o->RS("Timescale", &hp->timescale);
10218 o->RD("Minimum", &hp->minimum);
10219 o->RD("Maximum", &hp->maximum);
10220 o->RB("Zero ylow", &hp->zero_ylow);
10221 o->RB("Log axis", &hp->log_axis);
10222 o->RB("Zero ylow", &hp->zero_ylow);
10223 o->RB("Show run markers", &hp->show_run_markers);
10224 o->RB("Show values", &hp->show_values);
10225 o->RB("Show fill", &hp->show_fill);
10226 o->RB("Show factor", &hp->show_factor);
10227 //o->RB("Enable factor and offset", &hp->enable_factor);
10228
10229 std::vector<std::string> hist_vars;
10230 std::vector<std::string> hist_formula;
10231 std::vector<std::string> hist_colour;
10232 std::vector<std::string> hist_label;
10233 std::vector<bool> hist_show_raw_value;
10234 std::vector<double> hist_factor;
10235 std::vector<double> hist_offset;
10236 std::vector<double> hist_voffset;
10237
10238 o->RSA("Variables", &hist_vars);
10239 o->RSA("Formula", &hist_formula);
10240 o->RSA("Colour", &hist_colour);
10241 o->RSA("Label", &hist_label);
10242 o->RBA("Show raw value", &hist_show_raw_value);
10243 o->RDA("Factor", &hist_factor);
10244 o->RDA("Offset", &hist_offset);
10245 o->RDA("VOffset", &hist_voffset);
10246
10247 // fix broken plots with "factor" all zero. for reasons
10248 // unknown the new history code has corrupted many
10249 // history plot definitions like this. K.O.
10250 {
10251 bool all_zero = true;
10252 for (size_t i=0; i<hist_factor.size(); i++) {
10253 if (hist_factor[i] != 0)
10254 all_zero = false;
10255 }
10256 if (all_zero) {
10257 for (size_t i=0; i<hist_factor.size(); i++) {
10258 hist_factor[i] = 1.0;
10259 }
10260 }
10261 }
10262
10263 size_t num = std::max(hist_vars.size(), hist_formula.size());
10264 num = std::max(num, hist_colour.size());
10265 num = std::max(num, hist_label.size());
10266 num = std::max(num, hist_show_raw_value.size());
10267 num = std::max(num, hist_factor.size());
10268 num = std::max(num, hist_offset.size());
10269 num = std::max(num, hist_voffset.size());
10270
10271 hist_vars.resize(num);
10272 hist_formula.resize(num);
10273 hist_colour.resize(num);
10274 hist_label.resize(num);
10275 hist_show_raw_value.resize(num);
10276 hist_factor.resize(num, 1.0);
10277 hist_offset.resize(num, 0.0);
10278 hist_voffset.resize(num, 0.0);
10279
10280 for (size_t i=0; i<num; i++) {
10281 HistVar v;
10282
10284
10285 v.formula = hist_formula[i];
10286 v.colour = hist_colour[i];
10287 v.label = hist_label[i];
10289 v.factor = hist_factor[i];
10290 v.offset = hist_offset[i];
10291 v.voffset = hist_voffset[i];
10293
10294 // one-time migration of factor and offset to formula
10295 if (hp->enable_factor && v.formula.empty()) {
10296 if (v.factor!=1 || v.offset!=0 || v.voffset!=0) {
10297 v.formula = msprintf("%g%+g*(x%+g)", v.offset, v.factor, -v.voffset);
10298 }
10299 }
10300
10301 hp->vars.push_back(v);
10302 }
10303
10304// printf("Load from ODB %s: ", path.c_str());
10305// PrintHistPlot(*hp);
10306
10307 delete o;
10308}
10309
10311{
10312 hp->timescale = p->getparam("timescale");
10313 hp->minimum = strtod(p->getparam("minimum"), NULL);
10314 hp->maximum = strtod(p->getparam("maximum"), NULL);
10315 hp->zero_ylow = *p->getparam("zero_ylow");
10316 hp->log_axis = *p->getparam("log_axis");
10317 hp->show_run_markers = *p->getparam("run_markers");
10318 hp->show_values = *p->getparam("show_values");
10319 hp->show_fill = *p->getparam("show_fill");
10320 hp->show_factor = *p->getparam("show_factor");
10321 //hp->enable_factor = *p->getparam("enable_factor");
10322
10323 for (int index=0; ; index++) {
10324 char str[256];
10325 sprintf(str, "event%d", index);
10326
10327 //printf("param event %d: [%s] [%s] [%d]\n", index, str, p->getparam(str), *p->getparam(str));
10328
10329 if (!p->isparam(str))
10330 break;
10331
10332 if (*p->getparam(str) == '/') // "/empty"
10333 continue;
10334
10335 HistVar v;
10336
10337 v.event_name = p->xgetparam(str);
10338
10339 sprintf(str, "var%d", index);
10340 v.tag_name = p->xgetparam(str);
10341
10342 sprintf(str, "form%d", index);
10343 v.formula = p->xgetparam(str);
10344
10345 sprintf(str, "col%d", index);
10346 v.colour = p->xgetparam(str);
10347
10348 sprintf(str, "lab%d", index);
10349 v.label = p->xgetparam(str);
10350
10351 sprintf(str, "raw%d", index);
10352 v.show_raw_value = atoi(p->xgetparam(str).c_str());
10353
10354 sprintf(str, "factor%d", index);
10355 if (p->isparam(str)) {
10356 v.factor = atof(p->xgetparam(str).c_str());
10357 } else {
10358 v.factor = 1.0;
10359 }
10360
10361 sprintf(str, "offset%d", index);
10362 v.offset = atof(p->xgetparam(str).c_str());
10363
10364 sprintf(str, "voffset%d", index);
10365 v.voffset = atof(p->xgetparam(str).c_str());
10366
10367 sprintf(str, "ord%d", index);
10368 if (p->isparam(str)) {
10369 v.order = atoi(p->xgetparam(str).c_str());
10370 } else {
10372 }
10373
10374 hp->vars.push_back(v);
10375 }
10376
10377 /* correctly number newly added variables */
10378 for (size_t index=0; index<hp->vars.size(); index++) {
10379 if (hp->vars[index].order < 0)
10380 hp->vars[index].order = NextHistPlotOrder(*hp);
10381 }
10382
10383// printf("Load from param:\n");
10384// PrintHistPlot(*hp);
10385}
10386
10388{
10389 int seln = atoi(p->getparam("seln"));
10390 for (int i=0; i<seln; i++) {
10391 char str[256];
10392 sprintf(str, "sel%d", i);
10393
10394 std::string par = p->getparam(str);
10395 if (par.length() < 1)
10396 continue;
10397
10398 std::string event_name, tag_name;
10399 SplitEventAndTagNames(par, event_name, tag_name);
10400
10401 if (tag_name == "")
10402 continue;
10403
10404 HistVar v;
10405
10406 v.event_name = event_name;
10407 v.tag_name = tag_name;
10410
10411 hp.vars.push_back(v);
10412 }
10413}
10414
10415static void SaveHistPlotToOdb(MVOdb* odb, const HistPlot& hp, const char* group, const char* panel)
10416{
10417 if (strlen(group) < 1) {
10418 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid group name", group, panel);
10419 return;
10420 }
10421
10422 if (strlen(panel) < 1) {
10423 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid panel name", group, panel);
10424 return;
10425 }
10426
10427 std::string path = "History/Display/";
10428 path += group;
10429 path += "/";
10430 path += panel;
10431
10432// printf("Save to ODB %s: ", path.c_str());
10433// PrintHistPlot(hp);
10434
10435 MVOdb* o = odb->Chdir(path.c_str(), true);
10436
10437 o->WS("Timescale", hp.timescale.c_str());
10438 o->WD("Minimum", hp.minimum);
10439 o->WD("Maximum", hp.maximum);
10440 o->WB("Zero ylow", hp.zero_ylow);
10441 o->WB("Log axis", hp.log_axis);
10442 o->WB("Show run markers", hp.show_run_markers);
10443 o->WB("Show values", hp.show_values);
10444 o->WB("Show fill", hp.show_fill);
10445 o->WB("Show factor and offset", hp.show_factor);
10446 //o->WB("Enable factor and offset", hp.enable_factor);
10447
10448 std::vector<std::string> hist_vars;
10449 std::vector<std::string> hist_formula;
10450 std::vector<std::string> hist_colour;
10451 std::vector<std::string> hist_label;
10452 std::vector<bool> hist_show_raw_value;
10453 std::vector<double> hist_factor;
10454 std::vector<double> hist_offset;
10455 std::vector<double> hist_voffset;
10456
10457 for (size_t i=0; i<hp.vars.size(); i++) {
10458 hist_vars.push_back(hp.vars[i].event_name + ":" + hp.vars[i].tag_name);
10459 hist_formula.push_back(hp.vars[i].formula);
10460 hist_colour.push_back(hp.vars[i].colour);
10461 hist_label.push_back(hp.vars[i].label);
10462 hist_show_raw_value.push_back(hp.vars[i].show_raw_value);
10463 hist_factor.push_back(hp.vars[i].factor);
10464 hist_offset.push_back(hp.vars[i].offset);
10465 hist_voffset.push_back(hp.vars[i].voffset);
10466 }
10467
10468 if (hp.vars.size() > 0) {
10469 o->WSA("Variables", hist_vars, 64);
10470 o->WSA("Formula", hist_formula, 64);
10471 o->WSA("Colour", hist_colour, NAME_LENGTH);
10472 o->WSA("Label", hist_label, NAME_LENGTH);
10473 o->WBA("Show raw value", hist_show_raw_value);
10474 o->WDA("Factor", hist_factor);
10475 o->WDA("Offset", hist_offset);
10476 o->WDA("VOffset", hist_voffset);
10477 } else {
10478 o->Delete("Variables");
10479 o->Delete("Formula");
10480 o->Delete("Colour");
10481 o->Delete("Label");
10482 o->Delete("Show raw value");
10483 o->Delete("Factor");
10484 o->Delete("Offset");
10485 o->Delete("VOffset");
10486 }
10487
10488 delete o;
10489}
10490
10492{
10493 /* delete variables according to "hist_order" */
10494
10495 while (1) {
10496 bool something_deleted = false;
10497 for (unsigned i=0; i<hp.vars.size(); i++) {
10498 if (hp.vars[i].order <= 0) {
10499 hp.vars.erase(hp.vars.begin() + i);
10500 something_deleted = true;
10501 }
10502 }
10503 if (!something_deleted)
10504 break;
10505 }
10506}
10507
10509{
10510 /* sort variables according to "hist_order" */
10511
10512 bool need_sort = false;
10513 for (size_t i=1; i<hp.vars.size(); i++) {
10514 if (hp.vars[i-1].order >= hp.vars[i].order) {
10515 need_sort = true;
10516 }
10517 }
10518
10519 if (need_sort) {
10520 /* sort variables by order */
10521 std::sort(hp.vars.begin(), hp.vars.end(), cmp_vars);
10522
10523 /* renumber the variables according to the new sorted order */
10524 for (size_t index=0; index<hp.vars.size(); index++)
10525 hp.vars[index].order = (index+1)*10;
10526 }
10527}
10528
10529void show_hist_config_page(MVOdb* odb, Param* p, Return* r, const char *hgroup, const char *hpanel)
10530{
10531 int status;
10532 int max_display_events = 20;
10533 int max_display_tags = 200;
10534 char str[256], hcmd[256];
10535
10536 odb->RI("History/MaxDisplayEvents", &max_display_events, true);
10537 odb->RI("History/MaxDisplayTags", &max_display_tags, true);
10538
10539 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
10540
10541 if (equal_ustring(hcmd, "Clear history cache")) {
10542 //printf("clear history cache!\n");
10543 strcpy(hcmd, "Refresh");
10545 if (mh)
10546 mh->hs_clear_cache();
10547 }
10548
10549 //printf("cmd [%s]\n", cmd);
10550 //printf("cmdx [%s]\n", p->getparam("cmdx"));
10551
10552 HistPlot hp;
10553
10554 if (equal_ustring(hcmd, "refresh") || equal_ustring(hcmd, "save")) {
10557 } else {
10559 }
10560
10562
10563 if (strlen(p->getparam("seln")) > 0)
10565
10566 //hp->Print();
10567
10568 if (hcmd[0] && equal_ustring(hcmd, "save")) {
10570
10571 if (p->getparam("redir") && *p->getparam("redir"))
10572 redirect(r, p->getparam("redir"));
10573 else {
10574 sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
10575 redirect(r, str);
10576 }
10577 return;
10578 }
10579
10580 show_header(r, "History Config", "GET", "", 0);
10581 r->rsprintf("</table>"); //close header table
10582
10583 r->rsprintf("<table class=\"mtable\">"); //open main table
10584
10585 r->rsprintf("<tr><th colspan=11 class=\"subStatusTitle\">History Panel \"%s\" / \"%s\"</th></tr>\n", hgroup, hpanel);
10586
10587 /* menu buttons */
10588 r->rsprintf("<tr><td colspan=11>\n");
10589
10590 r->rsprintf("<input type=button value=Refresh ");
10591 r->rsprintf("onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">\n");
10592
10593 r->rsprintf("<input type=button value=Save ");
10594 r->rsprintf("onclick=\"document.form1.hcmd.value='Save';document.form1.submit()\">\n");
10595
10596 {
10597 r->rsprintf("<input type=button value=Cancel ");
10598 std::string url = "?cmd=oldhistory&group=";
10599 url += hgroup;
10600 url += "&panel=";
10601 url += hpanel;
10602 url += "&hcmd=Cancel";
10603 if (p->getparam("redir")) {
10604 url += "&redir=";
10605 url += urlEncode(p->getparam("redir"));
10606 }
10607 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10608 }
10609 {
10610 r->rsprintf("<input type=button value=\"Edit in ODB\"");
10611 std::string url = "?cmd=odb&odb_path=";
10612 url += "/History/Display/";
10613 url += urlEncode(hgroup);
10614 url += "/";
10615 url += urlEncode(hpanel);
10616 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10617 }
10618 {
10619 r->rsprintf("<input type=button value=\"Edit in new editor\"");
10620 std::string url = "?cmd=hs_edit";
10621 url += "&group=";
10622 url += urlEncode(hgroup);
10623 url += "&panel=";
10624 url += urlEncode(hpanel);
10625 if (p->getparam("redir")) {
10626 url += "&redir=";
10627 url += urlEncode(p->getparam("redir"));
10628 }
10629 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10630 }
10631 r->rsprintf("<input type=button value=\"Clear history cache\"");
10632 r->rsprintf("onclick=\"document.form1.hcmd.value='Clear history cache';document.form1.submit()\">\n");
10633 r->rsprintf("<input type=button value=\"Delete panel\"");
10634 r->rsprintf("onclick=\"window.location.search='?cmd=oldhistory&group=%s&panel=%s&hcmd=Delete%%20panel'\">\n", hgroup, hpanel);
10635 r->rsprintf("</td></tr>\n");
10636
10637 r->rsprintf("<tr><td colspan=11>\n");
10638
10639 /* sort_vars */
10640 int sort_vars = *p->getparam("sort_vars");
10641 r->rsprintf("<input type=checkbox %s name=sort_vars value=1 onclick=\"this.form.submit();\">Sort variable names", sort_vars?"checked":"");
10642
10643 /* old_vars */
10644 int old_vars = *p->getparam("old_vars");
10645 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":"");
10646
10647 if (hp.show_factor)
10648 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10649 else
10650 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10651 r->rsprintf("Show&nbsp;factor&nbsp;and&nbsp;offset\n");
10652
10653 /* hidden command for refresh */
10654 r->rsprintf("<input type=hidden name=cmd value=Oldhistory>\n");
10655 r->rsprintf("<input type=hidden name=hcmd value=Refresh>\n");
10656 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", hpanel);
10657 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", hgroup);
10658
10659 if (p->getparam("redir") && *p->getparam("redir"))
10660 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", p->getparam("redir"));
10661
10662 r->rsprintf("</td></tr>\n");
10663
10664 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Time scale (in units 'm', 'h', 'd'):</td>\n");
10665 r->rsprintf("<td colspan=3><input type=text size=12 name=timescale value=%s></td><td colspan=4></td></tr>\n", hp.timescale.c_str());
10666
10667 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Minimum (set to '-inf' for autoscale):</td>\n");
10668 r->rsprintf("<td colspan=3><input type=text size=12 name=minimum value=%f></td><td colspan=4></td></tr>\n", hp.minimum);
10669
10670 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Maximum (set to 'inf' for autoscale):</td>\n");
10671 r->rsprintf("<td colspan=3><input type=text size=12 name=maximum value=%f></td><td colspan=4></td></tr>\n", hp.maximum);
10672
10673 r->rsprintf("<tr><td colspan=11>");
10674
10675 if (hp.zero_ylow)
10676 r->rsprintf("<input type=checkbox checked name=zero_ylow value=1>");
10677 else
10678 r->rsprintf("<input type=checkbox name=zero_ylow value=1>");
10679 r->rsprintf("Zero&nbsp;Y;&nbsp;axis\n");
10680
10681 if (hp.log_axis)
10682 r->rsprintf("<input type=checkbox checked name=log_axis value=1>");
10683 else
10684 r->rsprintf("<input type=checkbox name=log_axis value=1>");
10685 r->rsprintf("Logarithmic&nbsp;Y&nbsp;axis\n");
10686
10687 if (hp.show_run_markers)
10688 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=run_markers value=1>");
10689 else
10690 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=run_markers value=1>");
10691 r->rsprintf("Show&nbsp;run&nbsp;markers\n");
10692
10693 if (hp.show_values)
10694 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_values value=1>");
10695 else
10696 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_values value=1>");
10697 r->rsprintf("Show&nbsp;values&nbsp;of&nbsp;variables\n");
10698
10699 if (hp.show_fill)
10700 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_fill value=1>");
10701 else
10702 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_fill value=1>");
10703 r->rsprintf("Show&nbsp;graph&nbsp;fill\n");
10704
10705 r->rsprintf("</td></tr>\n");
10706
10707 /*---- events and variables ----*/
10708
10709 /* get display event name */
10710
10712 if (mh == NULL) {
10713 r->rsprintf(str, "History is not configured\n");
10714 return;
10715 }
10716
10717 time_t t = time(NULL);
10718
10719 if (old_vars)
10720 t = 0;
10721
10722 std::vector<std::string> events;
10723
10724 if (!old_vars)
10726
10727 if (events.size() == 0)
10728 mh->hs_get_events(t, &events);
10729
10730#if 0
10731 for (unsigned i=0; i<events.size(); i++)
10732 printf("event %d: \"%s\"\n", i, events[i].c_str());
10733#endif
10734
10735 // has to be sorted or equipment name code below would not work
10736 //std::sort(events.begin(), events.end(), cmp_events);
10737 std::sort(events.begin(), events.end(), cmp_events1);
10738
10739 if (strlen(p->getparam("cmdx")) > 0) {
10740 r->rsprintf("<tr><th colspan=8 class=\"subStatusTitle\">List of available history variables</th></tr>\n");
10741 r->rsprintf("<tr><th colspan=1>Sel<th colspan=1>Equipment<th colspan=1>Event<th colspan=1>Variable</tr>\n");
10742
10743 std::string cmdx = p->xgetparam("cmdx");
10744 std::string xeqname;
10745
10746 int i=0;
10747 for (unsigned e=0; e<events.size(); e++) {
10748 std::string eqname;
10749 eqname = events[e].substr(0, events[e].find("/"));
10750
10751 if (eqname.length() < 1)
10752 eqname = events[e];
10753
10754 bool once = false;
10755 if (eqname != xeqname)
10756 once = true;
10757
10758 std::string qcmd = "Expand " + eqname;
10759
10760 //printf("param [%s] is [%s]\n", qcmd.c_str(), p->getparam(qcmd.c_str()));
10761
10762 bool collapsed = true;
10763
10764 if (cmdx == qcmd)
10765 collapsed = false;
10766
10767 if (strlen(p->getparam(qcmd.c_str())) > 0)
10768 collapsed = false;
10769
10770 if (collapsed) {
10771 if (eqname == xeqname)
10772 continue;
10773
10774 r->rsprintf("<tr align=left>\n");
10775 r->rsprintf("<td></td>\n");
10776 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10777 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", qcmd.c_str());
10778 r->rsprintf("<td>%s</td>\n", "");
10779 r->rsprintf("</tr>\n");
10780 xeqname = eqname;
10781 continue;
10782 }
10783
10784 if (once)
10785 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", qcmd.c_str(), 1);
10786
10787 std::string rcmd = "Expand " + events[e];
10788
10789 //printf("param [%s] is [%s]\n", rcmd.c_str(), p->getparam(rcmd.c_str()));
10790
10791 collapsed = true;
10792
10793 if (cmdx == rcmd)
10794 collapsed = false;
10795
10796 if (strlen(p->getparam(rcmd.c_str())) > 0)
10797 collapsed = false;
10798
10799 if (collapsed) {
10800 r->rsprintf("<tr align=left>\n");
10801 r->rsprintf("<td></td>\n");
10802 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10803 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10804 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", rcmd.c_str());
10805 r->rsprintf("</tr>\n");
10806 continue;
10807 }
10808
10809 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", rcmd.c_str(), 1);
10810
10811 xeqname = eqname;
10812
10813 std::vector<TAG> tags;
10814
10815 status = mh->hs_get_tags(events[e].c_str(), t, &tags);
10816
10817 if (status == HS_SUCCESS && tags.size() > 0) {
10818
10819 if (sort_vars)
10820 std::sort(tags.begin(), tags.end(), cmp_tags);
10821
10822 for (unsigned v=0; v<tags.size(); v++) {
10823
10824 for (unsigned j=0; j<tags[v].n_data; j++) {
10825 char tagname[256];
10826
10827 if (tags[v].n_data == 1)
10828 sprintf(tagname, "%s", tags[v].name);
10829 else
10830 sprintf(tagname, "%s[%d]", tags[v].name, j);
10831
10832 bool checked = false;
10833#if 0
10834 for (int index=0; index<MAX_VARS; index++) {
10835 if (equal_ustring(vars[index].event_name, events[e].c_str()) && equal_ustring(vars[index].var_name, tagname)) {
10836 checked = true;
10837 break;
10838 }
10839 }
10840#endif
10841
10842 r->rsprintf("<tr align=left>\n");
10843 r->rsprintf("<td><input type=checkbox %s name=\"sel%d\" value=\"%s:%s\"></td>\n", checked?"checked":"", i++, events[e].c_str(), tagname);
10844 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10845 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10846 r->rsprintf("<td>%s</td>\n", tagname);
10847 r->rsprintf("</tr>\n");
10848 }
10849 }
10850 }
10851 }
10852
10853 r->rsprintf("<tr>\n");
10854 r->rsprintf("<td></td>\n");
10855 r->rsprintf("<td>\n");
10856 r->rsprintf("<input type=hidden name=seln value=%d>\n", i);
10857 r->rsprintf("<input type=submit value=\"Add Selected\">\n");
10858 r->rsprintf("</td>\n");
10859 r->rsprintf("</tr>\n");
10860 }
10861
10862 r->rsprintf("<tr><td colspan=11 style='text-align:left'>New history: displayed_value = formula(history_value)</td></tr>\n");
10863 r->rsprintf("<tr><td colspan=11 style='text-align:left'>Old history: displayed_value = offset + factor*(history_value - voffset)</td></tr>\n");
10864 r->rsprintf("<tr><td colspan=11 style='text-align:left'>Formula format: \"3*x+4\", \"10*Math.sin(x)\", etc. all javascript math functions can be used</td></tr>\n");
10865 r->rsprintf("<tr><td colspan=11 style='text-align:left'>To display the raw history value instead of computed formula or offset value, check the \"raw\" checkbox</td></tr>\n");
10866 r->rsprintf("<tr><td colspan=11 style='text-align:left'>To reorder entries: enter new ordering in the \"order\" column and press \"refresh\"</td></tr>\n");
10867 r->rsprintf("<tr><td colspan=11 style='text-align:left'>To delete entries: enter \"-1\" or leave blank the \"order\" column and press \"refresh\"</td></tr>\n");
10868
10869 r->rsprintf("<tr>\n");
10870 r->rsprintf("<th>Col<th>Event<th>Variable<th>Formula<th>Colour<th>Label<th>Raw<th>Order");
10871 if (hp.show_factor) {
10872 r->rsprintf("<th>Factor<th>Offset<th>VOffset");
10873 }
10874 r->rsprintf("</tr>\n");
10875
10876 //print_vars(vars);
10877
10878 size_t nvars = hp.vars.size();
10879 for (size_t index = 0; index <= nvars; index++) {
10880
10881 r->rsprintf("<tr>");
10882
10883 if (index < nvars) {
10884 if (hp.vars[index].colour.empty())
10885 hp.vars[index].colour = NextHistPlotColour(hp);
10886 r->rsprintf("<td style=\"background-color:%s\">&nbsp;<td>\n", hp.vars[index].colour.c_str());
10887 } else {
10888 r->rsprintf("<td>&nbsp;<td>\n");
10889 }
10890
10891 /* event and variable selection */
10892
10893 r->rsprintf("<select name=\"event%d\" size=1 onChange=\"document.form1.submit()\">\n", (int)index);
10894
10895 /* enumerate events */
10896
10897 /* empty option */
10898 r->rsprintf("<option value=\"/empty\">&lt;empty&gt;\n");
10899
10900 if (index==nvars) { // last "empty" entry
10901 for (unsigned e=0; e<events.size(); e++) {
10902 const char *p = events[e].c_str();
10903 r->rsprintf("<option value=\"%s\">%s\n", p, p);
10904 }
10905 } else if ((int)events.size() > max_display_events) { // too many events
10906 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].event_name.c_str(), hp.vars[index].event_name.c_str());
10907 r->rsprintf("<option>(%d events omitted)\n", (int)events.size());
10908 } else { // show all events
10909 bool found = false;
10910 for (unsigned e=0; e<events.size(); e++) {
10911 const char *s = "";
10912 const char *p = events[e].c_str();
10913 if (equal_ustring(hp.vars[index].event_name.c_str(), p)) {
10914 s = "selected";
10915 found = true;
10916 }
10917 r->rsprintf("<option %s value=\"%s\">%s\n", s, p, p);
10918 }
10919 if (!found) {
10920 const char *p = hp.vars[index].event_name.c_str();
10921 r->rsprintf("<option selected value=\"%s\">%s\n", p, p);
10922 }
10923 }
10924
10925 r->rsprintf("</select></td>\n");
10926
10927 //if (hp.vars[index].order <= 0)
10928 // hp.vars[index].order = (index+1)*10;
10929
10930 if (index < nvars) {
10931 bool found_tag = false;
10932 std::string selected_tag = hp.vars[index].tag_name;
10933
10934 r->rsprintf("<td><select name=\"var%d\">\n", (int)index);
10935
10936 std::vector<TAG> tags;
10937
10938 status = mh->hs_get_tags(hp.vars[index].event_name.c_str(), t, &tags);
10939
10940 if (status == HS_SUCCESS && tags.size() > 0) {
10941
10942 if (/* DISABLES CODE */ (0)) {
10943 printf("Compare %d\n", cmp_names("AAA", "BBB"));
10944 printf("Compare %d\n", cmp_names("BBB", "AAA"));
10945 printf("Compare %d\n", cmp_names("AAA", "AAA"));
10946 printf("Compare %d\n", cmp_names("A", "AAA"));
10947 printf("Compare %d\n", cmp_names("A111", "A1"));
10948 printf("Compare %d\n", cmp_names("A111", "A2"));
10949 printf("Compare %d\n", cmp_names("A111", "A222"));
10950 printf("Compare %d\n", cmp_names("A111a", "A111b"));
10951 }
10952
10953 if (sort_vars)
10954 std::sort(tags.begin(), tags.end(), cmp_tags);
10955
10956 if (/* DISABLES CODE */ (0)) {
10957 printf("Event [%s] %d tags\n", hp.vars[index].event_name.c_str(), (int)tags.size());
10958
10959 for (unsigned v=0; v<tags.size(); v++) {
10960 printf("tag[%d] [%s]\n", v, tags[v].name);
10961 }
10962 }
10963
10964 unsigned count_tags = 0;
10965 for (unsigned v=0; v<tags.size(); v++)
10966 count_tags += tags[v].n_data;
10967
10968 //printf("output %d option tags\n", count_tags);
10969
10970 if ((int)count_tags < max_display_tags) {
10971 for (unsigned v=0; v<tags.size(); v++) {
10972
10973 for (unsigned j=0; j<tags[v].n_data; j++) {
10974 std::string tagname;
10975
10976 if (tags[v].n_data == 1)
10977 tagname = tags[v].name;
10978 else {
10979 char buf[256];
10980 sprintf(buf, "[%d]", j);
10981 tagname = std::string(tags[v].name) + buf;
10982 }
10983
10984 if (equal_ustring(selected_tag.c_str(), tagname.c_str())) {
10985 r->rsprintf("<option selected value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10986 found_tag = true;
10987 }
10988 else
10989 r->rsprintf("<option value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
10990
10991 //printf("%d [%s] [%s] [%s][%s] %d\n", (int)index, vars[index].event_name, tagname, vars[index].var_name, selected_var, found_var);
10992 }
10993 }
10994 }
10995 }
10996
10997 if (!found_tag)
10998 if (hp.vars[index].tag_name.length() > 0)
10999 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].tag_name.c_str(), hp.vars[index].tag_name.c_str());
11000
11001 r->rsprintf("</select></td>\n");
11002 r->rsprintf("<td><input type=text size=15 maxlength=256 name=\"form%d\" value=%s></td>\n", (int)index, hp.vars[index].formula.c_str());
11003 r->rsprintf("<td><input type=text size=8 maxlength=10 name=\"col%d\" value=%s></td>\n", (int)index, hp.vars[index].colour.c_str());
11004 r->rsprintf("<td><input type=text size=8 maxlength=%d name=\"lab%d\" value=\"%s\"></td>\n", NAME_LENGTH, (int)index, hp.vars[index].label.c_str());
11005 if (hp.vars[index].show_raw_value)
11006 r->rsprintf("<td><input type=checkbox checked name=\"raw%d\" value=1></td>", (int)index);
11007 else
11008 r->rsprintf("<td><input type=checkbox name=\"raw%d\" value=1></td>", (int)index);
11009 r->rsprintf("<td><input type=text size=3 maxlength=32 name=\"ord%d\" value=\"%d\"></td>\n", (int)index, hp.vars[index].order);
11010 if (hp.show_factor) {
11011 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"factor%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].factor);
11012 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"offset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].offset);
11013 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"voffset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].voffset);
11014 } else {
11015 r->rsprintf("<input type=hidden name=\"factor%d\" value=\"%f\">\n", (int)index, hp.vars[index].factor);
11016 r->rsprintf("<input type=hidden name=\"offset%d\" value=\"%f\">\n", (int)index, hp.vars[index].offset);
11017 r->rsprintf("<input type=hidden name=\"voffset%d\" value=\"%f\">\n", (int)index, hp.vars[index].voffset);
11018 }
11019 } else {
11020 r->rsprintf("<td colspan=2><input type=submit name=cmdx value=\"List all variables\"></td>\n");
11021 }
11022
11023 r->rsprintf("</tr>\n");
11024 }
11025
11026 r->rsprintf("</table>\n");
11027 //r->rsprintf("</form>\n");
11028 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11029 r->rsprintf("</form>\n");
11030 r->rsprintf("</body></html>\r\n");
11031}
11032
11033/*------------------------------------------------------------------*/
11034
11035void export_hist(MVOdb* odb, Return* r, const char *group, const char *panel, time_t endtime, int scale, int index, int labels)
11036{
11037 //HNDLE hDB, hkey, hkeypanel;
11038 //int size;
11039 int status;
11040 //char str[256];
11041
11042 int debug = 0;
11043
11044 ss_tzset(); // required for localtime_r()
11045
11046#if 0
11048
11049 /* check panel name in ODB */
11050 sprintf(str, "/History/Display/%s/%s", group, panel);
11052 if (!hkeypanel) {
11053 sprintf(str, "Cannot find /History/Display/%s/%s in ODB\n", group, panel);
11054 show_error(r, str);
11055 return;
11056 }
11057
11058 /* get runmarker flag */
11059 BOOL runmarker = 1;
11060 size = sizeof(runmarker);
11061 db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
11062
11063 if (scale == 0) {
11064 /* get timescale */
11065 std::string ts = "1h";
11066 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11067 if (status != DB_SUCCESS) {
11068 /* delete old integer key */
11069 db_find_key(hDB, hkeypanel, "Timescale", &hkey);
11070 if (hkey)
11072
11073 ts = "1h";
11074 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11075 }
11076
11077 scale = time_to_sec(ts.c_str());
11078 }
11079#endif
11080
11081 time_t now = ss_time();
11082
11083 if (endtime == 0)
11084 endtime = now;
11085
11088
11089 HistPlot hp;
11091
11092 time_t starttime = endtime - scale;
11093
11094 //printf("start %.0f, end %.0f, scale %.0f\n", (double)starttime, (double)endtime, (double)scale);
11095
11096 status = read_history(hp, /*hDB, group, panel,*/ index, hp.show_run_markers, starttime, endtime, 0, hsdata);
11097 if (status != HS_SUCCESS) {
11098 char str[256];
11099 sprintf(str, "History error, status %d\n", status);
11100 show_error(r, str);
11101 return;
11102 }
11103
11104 if (debug)
11105 hsdata->Print();
11106
11107 int *i_var = (int *)malloc(sizeof(int)*hsdata->nvars);
11108
11109 assert(i_var != NULL);
11110
11111 for (int i = 0; i < hsdata->nvars; i++)
11112 i_var[i] = -1;
11113
11114 time_t t = 0;
11115
11116 /* find first time where all variables are available */
11117 for (int i = 0; i < hsdata->nvars; i++)
11118 if (hsdata->odb_index[i] >= 0)
11119 if (hsdata->num_entries[i] > 0)
11120 if ((t == 0) || (hsdata->t[i][0] > t))
11121 t = hsdata->t[i][0];
11122
11123 if (t == 0 && hsdata->nvars > 1) {
11124 show_error(r, "No history available for choosen period");
11125 free(i_var);
11126 return;
11127 }
11128
11129 int run_index = -1;
11130 int state_index = -1;
11131 int n_run_number = 0;
11133 if (hp.show_run_markers)
11134 for (int i = 0; i < hsdata->nvars; i++) {
11135 if (hsdata->odb_index[i] == -2) {
11136 n_run_number = hsdata->num_entries[i];
11137 t_run_number = hsdata->t[i];
11138 run_index = i;
11139 } else if (hsdata->odb_index[i] == -1) {
11140 state_index = i;
11141 }
11142 }
11143
11144 //printf("runmarker %d, state %d, run %d\n", runmarker, state_index, run_index);
11145
11146 /* header */
11147 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
11148 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
11149 r->rsprintf("Accept-Ranges: bytes\r\n");
11150 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
11151 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
11152 r->rsprintf("Content-Type: text/plain\r\n");
11153 r->rsprintf("Content-disposition: attachment; filename=\"export.csv\"\r\n");
11154 r->rsprintf("\r\n");
11155
11156 /* output header line with variable names */
11157 if (hp.show_run_markers && t_run_number)
11158 r->rsprintf("Time, Timestamp, Run, Run State, ");
11159 else
11160 r->rsprintf("Time, Timestamp, ");
11161
11162 for (int i = 0, first = 1; i < hsdata->nvars; i++) {
11163 if (hsdata->odb_index[i] < 0)
11164 continue;
11165 if (hsdata->num_entries[i] <= 0)
11166 continue;
11167 if (!first)
11168 r->rsprintf(", ");
11169 first = 0;
11170 r->rsprintf("%s", hsdata->var_names[i]);
11171 }
11172 r->rsprintf("\n");
11173
11174 int i_run = 0;
11175
11176 do {
11177
11178 if (debug)
11179 printf("hsdata %p, t %d, irun %d\n", hsdata, (int)t, i_run);
11180
11181 /* find run number/state which is valid for t */
11182 if (hp.show_run_markers && t_run_number)
11183 while (i_run < n_run_number-1 && t_run_number[i_run+1] <= t)
11184 i_run++;
11185
11186 //printf("irun %d\n", i_run);
11187
11188 /* find index for all variables which is valid for t */
11189 for (int i = 0; i < hsdata->nvars; i++)
11190 while (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i] - 1 && hsdata->t[i][i_var[i]+1] <= t)
11191 i_var[i]++;
11192
11193 /* finish if last point for all variables reached */
11194 bool done = true;
11195 for (int i = 0 ; i < hsdata->nvars ; i++)
11196 if (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i]) {
11197 done = false;
11198 break;
11199 }
11200
11201 if (debug) {
11202 printf("step to time %d: ", (int)t);
11203 for (int i = 0; i < hsdata->nvars; i++) {
11204 printf(" [%d] %d, ", hsdata->num_entries[i], i_var[i]);
11205 }
11206 printf(" done: %d\n", done);
11207 }
11208
11209 if (done)
11210 break;
11211
11212 struct tm tms;
11213 localtime_r(&t, &tms);
11214
11215 char fmt[256];
11216 //strcpy(fmt, "%c");
11217 strcpy(fmt, "%Y.%m.%d %H:%M:%S");
11218 char str[256];
11219 strftime(str, sizeof(str), fmt, &tms);
11220
11221 if (t_run_number && run_index>=0 && state_index>=0) {
11222 if (t_run_number[i_run] <= t)
11223 r->rsprintf("%s, %d, %.0f, %.0f, ", str, (int)t, hsdata->v[run_index][i_run], hsdata->v[state_index][i_run]);
11224 else
11225 r->rsprintf("%s, %d, N/A, N/A, ", str, (int)t);
11226 } else
11227 r->rsprintf("%s, %d, ", str, (int)t);
11228
11229 if (debug) {
11230 for (int i= 0 ; i < hsdata->nvars ; i++)
11231 printf(" %d (%g)", i_var[i], hsdata->v[i][i_var[i]]);
11232 printf("\n");
11233 }
11234
11235 for (int i=0, first=1 ; i<hsdata->nvars ; i++) {
11236 if (i_var[i] < 0)
11237 continue;
11238 if (hsdata->odb_index[i] < 0)
11239 continue;
11240 if (!first)
11241 r->rsprintf(", ");
11242 first = 0;
11243 //r->rsprintf("(%d %g)", i_var[i], hsdata->v[i][i_var[i]]);
11244 r->rsprintf("%g", hsdata->v[i][i_var[i]]);
11245 }
11246 r->rsprintf("\n");
11247
11248 /* find next t as smallest delta t */
11249 int dt = -1;
11250 for (int i = 0 ; i < hsdata->nvars ; i++)
11251 if (i_var[i]>=0 && hsdata->odb_index[i]>=0 && hsdata->num_entries[i]>0 && i_var[i]<hsdata->num_entries[i]-1) {
11252 int xdt = hsdata->t[i][i_var[i]+1] - t;
11253 if (debug)
11254 printf("var %d, i_var %d->%d, t %d->%d, dt %d\n", i, i_var[i], i_var[i]+1, (int)hsdata->t[i][i_var[i]], (int)hsdata->t[i][i_var[i]+1], xdt);
11255 if (dt <= 0 || xdt < dt)
11256 dt = xdt;
11257 }
11258
11259 if (debug)
11260 printf("dt %d\n", dt);
11261
11262 if (dt <= 0)
11263 break;
11264
11265 t += dt;
11266
11267 } while (1);
11268
11269 free(i_var);
11270}
11271
11272/*------------------------------------------------------------------*/
11273
11274void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
11275{
11277 KEY key, ikey;
11278 int i, j, k, scale, index, width, size, status, labels;
11279 char hgroup[256], hpanel[256], hcmd[256];
11280 const char def_button[][NAME_LENGTH] = { "10m", "1h", "3h", "12h", "24h", "3d", "7d" };
11281
11283
11284 hcmd[0] = hgroup[0] = hpanel[0] = 0;
11285
11286 if (p->getparam("group") && *p->getparam("group"))
11287 mstrlcpy(hgroup, p->getparam("group"), sizeof(hgroup));
11288 if (p->getparam("panel") && *p->getparam("panel"))
11289 mstrlcpy(hpanel, p->getparam("panel"), sizeof(hpanel));
11290 if (p->getparam("hcmd") && *p->getparam("hcmd"))
11291 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
11292
11293 if (equal_ustring(hcmd, "Reset")) {
11294 std::string redir;
11295 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11296 redir += "?cmd=oldhistory&group=";
11297 redir += hgroup;
11298 redir += "&panel=";
11299 redir += hpanel;
11300 redirect(r, redir.c_str());
11301 return;
11302 }
11303
11304 if (equal_ustring(hcmd, "Query")) {
11305 show_query_page(p, r);
11306 return;
11307 }
11308
11309 if (equal_ustring(hcmd, "Cancel")) {
11310 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11311 if (p->getparam("redir") && *p->getparam("redir"))
11312 redirect(r, p->getparam("redir"));
11313 else {
11314 std::string redir;
11315 redir += "?cmd=oldhistory&group=";
11316 redir += hgroup;
11317 redir += "&panel=";
11318 redir += hpanel;
11319 redirect(r, redir.c_str());
11320 }
11321 return;
11322 }
11323
11324 if (equal_ustring(hcmd, "Config") ||
11325 equal_ustring(hcmd, "Save")
11326 || equal_ustring(hcmd, "Clear history cache")
11327 || equal_ustring(hcmd, "Refresh")) {
11328
11329 show_hist_config_page(odb, p, r, hgroup, hpanel);
11330 return;
11331 }
11332
11333 if (equal_ustring(hcmd, "New")) {
11334 show_header(r, "History", "GET", "", 0);
11335
11336 r->rsprintf("<table class=\"dialogTable\">");
11337 r->rsprintf("<tr><th class=\"subStatusTitle\" colspan=2>New History Item</th><tr>");
11338 r->rsprintf("<tr><td align=center colspan=2>\n");
11339 r->rsprintf("Select group: &nbsp;&nbsp;");
11340 r->rsprintf("<select id=\"group\" name=\"group\">\n");
11341
11342 /* list existing groups */
11343 db_find_key(hDB, 0, "/History/Display", &hkey);
11344 i = 0;
11345 if (hkey) {
11346 for (i = 0;; i++) {
11348
11349 if (!hkeyp)
11350 break;
11351
11352 db_get_key(hDB, hkeyp, &key);
11354 r->rsprintf("<option selected>%s</option>\n", key.name);
11355 else
11356 r->rsprintf("<option>%s</option>\n", key.name);
11357 }
11358 }
11359 if (!hkey || i == 0)
11360 r->rsprintf("<option>Default</option>\n");
11361 r->rsprintf("</select><p>\n");
11362
11363 r->rsprintf("Or enter new group name: &nbsp;&nbsp;");
11364 r->rsprintf("<input type=text size=15 maxlength=31 id=new_group name=new_group>\n");
11365
11366 r->rsprintf("<tr><td align=center colspan=2>\n");
11367 r->rsprintf("<br>Panel name: &nbsp;&nbsp;");
11368 r->rsprintf("<input type=text size=15 maxlength=31 id=panel name=panel><br><br>\n");
11369 r->rsprintf("</td></tr>\n");
11370
11371 r->rsprintf("<tr><td align=center colspan=2>");
11372 std::string str = "?cmd=oldhistory&hcmd=createnew";
11373 str += "&new_group='+document.getElementById('new_group').value+'";
11374 str += "&group='+document.getElementById('group').value+'";
11375 str += "&panel='+document.getElementById('panel').value+'";
11376 r->rsprintf("<input type=button value=Submit onclick=\"window.location.search='%s'\">\n", str.c_str());
11377 r->rsprintf("</td></tr>\n");
11378
11379 r->rsprintf("</table>\r\n");
11380 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11381 r->rsprintf("</form>\n");
11382 r->rsprintf("</body></html>\r\n");
11383 return;
11384 }
11385
11386 if (equal_ustring(hcmd, "Delete Panel")) {
11387 std::string path;
11388 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11389 path += "/History/Display/";
11390 path += hgroup;
11391 path += "/";
11392 path += hpanel;
11393 if (db_find_key(hDB, 0, path.c_str(), &hkey)==DB_SUCCESS)
11395
11396 redirect(r, "?cmd=oldhistory");
11397 return;
11398 }
11399
11400 if (equal_ustring(hcmd, "createnew")) {
11401
11402 /* strip leading/trailing spaces */
11403 while (hpanel[0] == ' ') {
11404 char str[256];
11405 mstrlcpy(str, hpanel+1, sizeof(str));
11406 mstrlcpy(hpanel, str, sizeof(hpanel));
11407 }
11408 while (strlen(hpanel)> 1 && hpanel[strlen(hpanel)-1] == ' ')
11409 hpanel[strlen(hpanel)-1] = 0;
11410
11411 /* use new group if present */
11412 if (p->isparam("new_group") && *p->getparam("new_group"))
11413 mstrlcpy(hgroup, p->getparam("new_group"), sizeof(hgroup));
11414
11415 /* configure that panel */
11416 show_hist_config_page(odb, p, r, hgroup, hpanel);
11417 return;
11418 }
11419
11420 const char* pscale = p->getparam("scale");
11421 if (pscale == NULL || *pscale == 0)
11422 pscale = p->getparam("hscale");
11423 const char* pwidth = p->getparam("width");
11424 if (pwidth == NULL || *pwidth == 0)
11425 pwidth = p->getparam("hwidth");
11426 const char* pheight = p->getparam("height");
11427 if (pheight == NULL || *pheight == 0)
11428 pheight = p->getparam("hheight");
11429 const char* pindex = p->getparam("index");
11430 if (pindex == NULL || *pindex == 0)
11431 pindex = p->getparam("hindex");
11432
11433 labels = 1;
11434 if (*p->getparam("labels") && atoi(p->getparam("labels")) == 0)
11435 labels = 0;
11436
11437 std::string bgcolor = "FFFFFF";
11438 if (*p->getparam("bgcolor"))
11439 bgcolor = p->xgetparam("bgcolor");
11440
11441 std::string fgcolor = "000000";
11442 if (*p->getparam("fgcolor"))
11443 fgcolor = p->xgetparam("fgcolor");
11444
11445 std::string gridcolor = "A0A0A0";
11446 if (*p->getparam("gcolor"))
11447 gridcolor = p->xgetparam("gcolor");
11448
11449 /* evaluate scale and offset */
11450
11451 time_t endtime = 0;
11452 if (p->isparam("time"))
11453 endtime = string_to_time(p->getparam("time"));
11454 else if (p->isparam("htime"))
11455 endtime = string_to_time(p->getparam("htime"));
11456
11457 if (pscale && *pscale)
11458 scale = time_to_sec(pscale);
11459 else
11460 scale = 0;
11461
11462 index = -1;
11463 if (pindex && *pindex)
11464 index = atoi(pindex);
11465
11466#ifdef BROKEN
11467 if (equal_ustring(hcmd, "Create ELog")) {
11468 std::string xurl;
11469 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &xurl, FALSE);
11470 if (status == DB_SUCCESS) {
11471 char url[256];
11472 get_elog_url(url, sizeof(url));
11473
11474 /*---- use external ELOG ----*/
11475 fsize = 100000;
11476 char* fbuffer = (char*)M_MALLOC(fsize);
11477 assert(fbuffer != NULL);
11478
11479 int width = 640;
11480 int height = 400;
11481
11482 if (equal_ustring(pmag, "Large")) {
11483 width = 1024;
11484 height = 768;
11485 } else if (equal_ustring(pmag, "Small")) {
11486 width = 320;
11487 height = 200;
11488 } else if (atoi(pmag) > 0) {
11489 width = atoi(pmag);
11490 height = 200;
11491 }
11492
11493 printf("hereA\n");
11494 generate_hist_graph(odb, r, hgroup, hpanel, fbuffer, &fsize, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11495
11496 /* save temporary file */
11497 std::string dir;
11498 db_get_value_string(hDB, 0, "/Elog/Logbook Dir", 0, &dir, TRUE);
11499 if (dir.length() > 0 && dir[dir.length()-1] != DIR_SEPARATOR)
11500 dir += DIR_SEPARATOR_STR;
11501
11502 time_t now = time(NULL);
11503 localtime_r(&now, &tms);
11504
11505 std::string file_name = msprintf("%02d%02d%02d_%02d%02d%02d_%s.gif",
11506 tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday,
11507 tms.tm_hour, tms.tm_min, tms.tm_sec, hpanel);
11508 std::string fname = dir + file_name;
11509
11510 /* save attachment */
11511 fh = open(fname.c_str(), O_CREAT | O_RDWR | O_BINARY, 0644);
11512 if (fh < 0) {
11513 cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", open() errno %d (%s)", fname.c_str(), errno, strerror(errno));
11514 } else {
11515 int wr = write(fh, fbuffer, fsize);
11516 if (wr != fsize) {
11517 cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", write(%d) returned %d, errno %d (%s)", fname.c_str(), fsize, wr, errno, strerror(errno));
11518 }
11519 close(fh);
11520 }
11521
11522 /* redirect to ELOG */
11523 if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11524 mstrlcat(url, "/", sizeof(url));
11525 mstrlcat(url, "?cmd=New&fa=", sizeof(url));
11526 mstrlcat(url, file_name, sizeof(url));
11527 redirect(r, url);
11528
11529 M_FREE(fbuffer);
11530 return;
11531
11532 } else {
11533 /*---- use internal ELOG ----*/
11534 std::string str = msprintf("\\HS\\%s.gif", hpanel);
11535 if (p->getparam("hscale") && *p->getparam("hscale"))
11536 str += msprintf("?scale=%s", p->getparam("hscale"));
11537 if (p->getparam("htime") && *p->getparam("htime")) {
11538 if (strchr(str.c_str(), '?'))
11539 str += "&";
11540 else
11541 str += "?";
11542 str += msprintf("time=%s", p->getparam("htime"));
11543 }
11544 //if (p->getparam("hoffset") && *p->getparam("hoffset")) {
11545 // if (strchr(str, '?'))
11546 // mstrlcat(str, "&", sizeof(str));
11547 // else
11548 // mstrlcat(str, "?", sizeof(str));
11549 // sprintf(str + strlen(str), "offset=%s", p->getparam("hoffset"));
11550 //}
11551 if (p->getparam("hwidth") && *p->getparam("hwidth")) {
11552 if (strchr(str.c_str(), '?'))
11553 str += "&";
11554 else
11555 str += "?";
11556 str += msprintf("width=%s", p->getparam("hwidth"));
11557 }
11558 if (p->getparam("hindex") && *p->getparam("hindex")) {
11559 if (strchr(str.c_str(), '?'))
11560 str += "&";
11561 else
11562 str += "?";
11563 str += msprintf("index=%s", p->getparam("hindex"));
11564 }
11565
11566 show_elog_new(r, hpanel, NULL, FALSE, str.c_str(), "../../EL/");
11567 return;
11568 }
11569 }
11570#endif
11571
11572 if (equal_ustring(hcmd, "Export")) {
11573 export_hist(odb, r, hgroup, hpanel, endtime, scale, index, labels);
11574 return;
11575 }
11576
11577 if (strstr(dec_path, ".gif")) {
11578 int width = 640;
11579 int height = 400;
11580 if (equal_ustring(pwidth, "Large")) {
11581 width = 1024;
11582 height = 768;
11583 } else if (equal_ustring(pwidth, "Small")) {
11584 width = 320;
11585 height = 200;
11586 } else if (atoi(pwidth) > 0) {
11587 width = atoi(pwidth);
11588 if (atoi(pheight) > 0)
11589 height = atoi(pheight);
11590 else
11591 height = (int)(0.625 * width);
11592 }
11593
11594 //printf("dec_path [%s], buf %p, %p, width %d, height %d, endtime %ld, scale %d, index %d, labels %d\n", dec_path, buffer, buffer_size, width, height, endtime, scale, index, labels);
11595
11596 generate_hist_graph(odb, r, hgroup, hpanel, buffer, buffer_size, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11597
11598 return;
11599 }
11600
11601 if (history_mode && index < 0)
11602 return;
11603
11604 time_t now = time(NULL);
11605
11606 /* evaluate offset shift */
11607 if (equal_ustring(p->getparam("shift"), "leftmaxall")) {
11608 if (endtime == 0)
11609 endtime = now;
11610 time_t last_written = 0;
11611 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 1, &last_written);
11612 if (status == HS_SUCCESS)
11613 endtime = last_written + scale/2;
11614 }
11615
11616 if (equal_ustring(p->getparam("shift"), "leftmax")) {
11617 if (endtime == 0)
11618 endtime = now;
11619 time_t last_written = 0;
11620 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 0, &last_written);
11621 if (status == HS_SUCCESS)
11622 if (last_written != endtime)
11623 endtime = last_written + scale/2;
11624 }
11625
11626 if (equal_ustring(p->getparam("shift"), "left")) {
11627 if (endtime == 0)
11628 endtime = now;
11629 endtime -= scale/2;
11630 //offset -= scale / 2;
11631 }
11632
11633 if (equal_ustring(p->getparam("shift"), "right")) {
11634 if (endtime == 0)
11635 endtime = now;
11636 endtime += scale/2;
11637 if (endtime > now)
11638 endtime = now;
11639 }
11640
11641 if (equal_ustring(p->getparam("shift"), "rightmax")) {
11642 endtime = 0;
11643 }
11644
11645 if (equal_ustring(p->getparam("shift"), "zoomin")) {
11646 if (endtime == 0)
11647 endtime = now;
11648 endtime -= scale / 4;
11649 scale /= 2;
11650 }
11651
11652 if (equal_ustring(p->getparam("shift"), "zoomout")) {
11653 if (endtime == 0)
11654 endtime = now;
11655 endtime += scale / 2;
11656 if (endtime > now)
11657 endtime = now;
11658 scale *= 2;
11659 }
11660
11661 int xrefresh = refresh;
11662 if (endtime != 0)
11663 xrefresh = 0;
11664 show_header(r, hpanel, "GET", "", xrefresh);
11665
11666 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
11667 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
11668 show_navigation_bar(r, "History");
11669
11670 r->rsprintf("<table class=\"mtable\">");
11671 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>History</th></tr>");
11672
11673 {
11674 /* check if panel exists */
11675 std::string path;
11676 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11677 path += "/History/Display/";
11678 path += hgroup;
11679 path += "/";
11680 path += hpanel;
11681 status = db_find_key(hDB, 0, path.c_str(), &hkey);
11682 if (status != DB_SUCCESS && !equal_ustring(hpanel, "All") && !equal_ustring(hpanel,"")) {
11683 r->rsprintf("<h1>Error: History panel \"%s\" in group \"%s\" does not exist</h1>\n", hpanel, hgroup);
11684 r->rsprintf("</table>\r\n");
11685 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11686 r->rsprintf("</form>\n");
11687 r->rsprintf("</body></html>\r\n");
11688 return;
11689 }
11690 }
11691
11692 /* define hidden field for parameters */
11693 if (pscale && *pscale)
11694 r->rsprintf("<input type=hidden name=hscale id=hscale value=%d>\n", scale);
11695 else {
11696 /* if no scale and offset given, get it from default */
11697 if (hpanel[0] && !equal_ustring(hpanel, "All") && hgroup[0]) {
11698 std::string path;
11699 path += "/History/Display/";
11700 path += hgroup;
11701 path += "/";
11702 path += hpanel;
11703 path += "/Timescale";
11704
11705 std::string scalestr = "1h";
11706 status = db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11707 if (status != DB_SUCCESS) {
11708 /* delete old integer key */
11709 db_find_key(hDB, 0, path.c_str(), &hkey);
11710 if (hkey)
11712
11713 scalestr = "1h";
11714 db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11715 }
11716
11717 r->rsprintf("<input type=hidden name=hscale id=hscale value=%s>\n", scalestr.c_str());
11718 scale = time_to_sec(scalestr.c_str());
11719 }
11720 }
11721
11722 if (endtime != 0)
11723 r->rsprintf("<input type=hidden name=htime id=htime value=%s>\n", time_to_string(endtime).c_str());
11724 if (pwidth && *pwidth)
11725 r->rsprintf("<input type=hidden name=hwidth id=hwidth value=%s>\n", pwidth);
11726 if (pheight && *pheight)
11727 r->rsprintf("<input type=hidden name=hheight id=hheight value=%s>\n", pheight);
11728 if (pindex && *pindex)
11729 r->rsprintf("<input type=hidden name=hindex id=hindex value=%s>\n", pindex);
11730
11731 r->rsprintf("</td></tr>\n");
11732
11733 if (hgroup[0] == 0) {
11734 /* "New" button */
11735 r->rsprintf("<tr><td colspan=2><input type=\"button\" name=\"New\" value=\"New\" ");
11736 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New'\"></td></tr>\n");
11737
11738 /* links for history panels */
11739 r->rsprintf("<tr><td colspan=2 style=\"text-align:left;\">\n");
11740 if (!hpanel[0])
11741 r->rsprintf("<b>Please select panel:</b><br>\n");
11742
11743 /* table for panel selection */
11744 r->rsprintf("<table class=\"historyTable\">");
11745
11746 /* "All" link */
11747 r->rsprintf("<tr><td colspan=2 class=\"titleCell\">\n");
11748 if (equal_ustring(hgroup, "All"))
11749 r->rsprintf("All &nbsp;&nbsp;");
11750 else
11751 r->rsprintf("<a href=\"?cmd=oldhistory&group=All\">ALL</a>\n");
11752 r->rsprintf("</td></tr>\n");
11753
11754 /* Setup History table links */
11755 db_find_key(hDB, 0, "/History/Display", &hkey);
11756 if (!hkey) {
11757 /* create default panel */
11758 char str[256];
11759 strcpy(str, "System:Trigger per sec.");
11760 strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11761 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables", str, 64, 2, TID_STRING);
11762 strcpy(str, "1h");
11763 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale", str, NAME_LENGTH, 1, TID_STRING);
11764
11765 strcpy(str, "1h");
11766 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale", str, NAME_LENGTH, 1, TID_STRING);
11767 i = 1;
11768 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11769 i = 1;
11770 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11771
11772 strcpy(str, "");
11773 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING);
11774 db_set_value_index(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING, FALSE);
11775 }
11776
11777 db_find_key(hDB, 0, "/History/Display", &hkey);
11778 if (hkey) {
11779 for (i = 0;; i++) {
11781
11782 if (!hkeyp)
11783 break;
11784
11785 // Group key
11786 db_get_key(hDB, hkeyp, &key);
11787
11788 char enc_name[256];
11789 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11790 urlEncode(enc_name, sizeof(enc_name));
11791
11793 r->rsprintf("<tr><td class=\"titleCell\">%s</td>\n<td>", key.name);
11794 else
11795 r->rsprintf("<tr><td class=\"titleCell\"><a href=\"?cmd=oldhistory&group=%s\">%s</a></td>\n<td>", enc_name, key.name);
11796
11797 for (j = 0;; j++) {
11798 // scan items
11800
11801 if (!hikeyp) {
11802 r->rsprintf("</tr>");
11803 break;
11804 }
11805 // Item key
11807
11808 char enc_iname[256];
11809 mstrlcpy(enc_iname, ikey.name, sizeof(enc_iname));
11810 urlEncode(enc_iname, sizeof(enc_iname));
11811
11812 if (equal_ustring(hpanel, ikey.name))
11813 r->rsprintf("<small><b>%s</b></small> &nbsp;", ikey.name);
11814 else
11815 r->rsprintf("<small><a href=\"?cmd=oldhistory&group=%s&panel=%s\">%s</a></small> &nbsp;\n", enc_name, enc_iname, ikey.name);
11816 }
11817 }
11818 }
11819
11820 r->rsprintf("</table></tr>\n");
11821
11822 } else {
11823 int found = 0;
11824
11825 /* show drop-down selectors */
11826 r->rsprintf("<tr><td colspan=2>\n");
11827
11828 r->rsprintf("Group:\n");
11829
11830 r->rsprintf("<select title=\"Select group\" id=\"fgroup\" onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value;\">\n");
11831
11832 db_find_key(hDB, 0, "/History/Display", &hkey);
11833 if (hkey) {
11834 hkeyp = 0;
11835 for (i = 0;; i++) {
11837
11838 if (!hikeyp)
11839 break;
11840
11841 if (i == 0)
11842 hkeyp = hikeyp;
11843
11844 // Group key
11846
11847 if (equal_ustring(key.name, hgroup)) {
11848 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11849 hkeyp = hikeyp;
11850 } else
11851 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11852 }
11853
11854 if (equal_ustring("ALL", hgroup)) {
11855 r->rsprintf("<option selected value=\"%s\">%s\n", "ALL", "ALL");
11856 } else {
11857 r->rsprintf("<option value=\"%s\">%s\n", "ALL", "ALL");
11858 }
11859
11860 r->rsprintf("</select>\n");
11861 r->rsprintf("&nbsp;&nbsp;Panel:\n");
11862 r->rsprintf("<select title=\"Select panel\" id=\"fpanel\" ");
11863 r->rsprintf("onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value+");
11864 r->rsprintf("'&panel='+document.getElementById('fpanel').value;\">\n");
11865
11866 found = 0;
11867 if (hkeyp) {
11868 for (i = 0;; i++) {
11869 // scan panels
11871
11872 if (!hikeyp)
11873 break;
11874
11875 // Item key
11877
11878 if (equal_ustring(hpanel, key.name)) {
11879 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11880 found = 1;
11881 } else
11882 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11883 }
11884 }
11885
11886 if (found)
11887 r->rsprintf("<option value=\"\">- all -\n");
11888 else
11889 r->rsprintf("<option selected value=\"\">- all -\n");
11890
11891 r->rsprintf("</select>\n");
11892 }
11893
11894 r->rsprintf("<noscript>\n");
11895 r->rsprintf("<input type=submit value=\"Go\">\n");
11896 r->rsprintf("</noscript>\n");
11897
11898 r->rsprintf("&nbsp;&nbsp;<input type=\"button\" name=\"New\" value=\"New\" ");
11899 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New&group=%s'\">\n", hgroup);
11900
11901 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Reset\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Reset&group=%s&panel=%s'\">\n", hgroup, hpanel);
11902
11903 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Query\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Query&group=%s&panel=%s'\">\n", hgroup, hpanel);
11904
11905 double xendtime = endtime;
11906 if (xendtime == 0)
11907 xendtime = now;
11908 double xstarttime = xendtime - scale;
11909
11910 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"New history\" onClick=\"window.location.href='?cmd=history&group=%s&panel=%s&A=%.0f&B=%.0f'\">\n", hgroup, hpanel, xstarttime, xendtime);
11911
11912 r->rsprintf("</td></tr>\n");
11913 }
11914
11915 //printf("hgroup [%s] hpanel [%s]\n", hgroup, hpanel);
11916
11917 /* check if whole group should be displayed */
11918 if (hgroup[0] && !equal_ustring(hgroup, "ALL") && hpanel[0] == 0) {
11919 std::string strwidth = "Small";
11920 db_get_value_string(hDB, 0, "/History/Display Settings/Width Group", 0, &strwidth, TRUE);
11921
11922 std::string path;
11923 path += "/History/Display/";
11924 path += hgroup;
11925 db_find_key(hDB, 0, path.c_str(), &hkey);
11926 if (hkey) {
11927 for (i = 0 ;; i++) { // scan group
11929
11930 if (!hikeyp)
11931 break;
11932
11934
11935 char enc_name[256];
11936 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11937 urlEncode(enc_name, sizeof(enc_name));
11938
11939 std::string ref;
11940 ref += "graph.gif?width=";
11941 ref += strwidth;
11942 ref += "&cmd=oldhistory&group=";
11943 ref += hgroup;
11944 ref += "&panel=";
11945 ref += enc_name;
11946
11947 std::string ref2;
11948 ref2 += "?cmd=oldhistory&group=";
11949 ref2 += hgroup;
11950 ref2 += "&panel=";
11951 ref2 += enc_name;
11952
11953 if (endtime != 0) {
11954 char tmp[256];
11955 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
11956 ref += "&";
11957 ref += tmp;
11958 ref2 += "?";
11959 ref2 += tmp;
11960 }
11961
11962 if (i % 2 == 0)
11963 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
11964 else
11965 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
11966 }
11967
11968 } else {
11969 r->rsprintf("Group \"%s\" not found", hgroup);
11970 }
11971 }
11972
11973 /* image panel */
11974 else if (hpanel[0] && !equal_ustring(hpanel, "All")) {
11975 /* navigation links */
11976 r->rsprintf("<tr><td>\n");
11977
11978 std::string path;
11979 path += "/History/Display/";
11980 path += hgroup;
11981 path += "/";
11982 path += hpanel;
11983 path += "/Buttons";
11984 db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11985 if (hkeybutton == 0) {
11986 /* create default buttons */
11987 db_create_key(hDB, 0, path.c_str(), TID_STRING);
11988 status = db_find_key(hDB, 0, path.c_str(), &hkeybutton);
11989 if (status != DB_SUCCESS || !hkey) {
11990 cm_msg(MERROR, "show_hist_page", "Cannot create history panel with invalid ODB path \"%s\"", path.c_str());
11991 return;
11992 }
11994 }
11995
11996 r->rsprintf("<script>\n");
11997 r->rsprintf("function histDisp(p) {\n");
11998 r->rsprintf(" var params = '?cmd=oldhistory&group=%s&panel=%s';\n", hgroup, hpanel);
11999 r->rsprintf(" params += '&'+p;\n");
12000 r->rsprintf(" if (document.getElementById(\'hscale\') !== null)\n");
12001 r->rsprintf(" params += '&hscale='+document.getElementById(\'hscale\').value;\n");
12002 r->rsprintf(" if (document.getElementById(\'htime\') !== null)\n");
12003 r->rsprintf(" params += '&htime='+document.getElementById(\'htime\').value;\n");
12004 r->rsprintf(" if (document.getElementById(\'hwdith\') !== null)\n");
12005 r->rsprintf(" params += '&hwidth='+document.getElementById(\'hwidth\').value;\n");
12006 r->rsprintf(" if (document.getElementById(\'hindex\') !== null)\n");
12007 r->rsprintf(" params += '&hindex='+document.getElementById(\'hindex\').value;\n");
12008 r->rsprintf(" window.location.search = params;\n");
12009 r->rsprintf("}\n\n");
12010 r->rsprintf("</script>\n");
12011
12013
12014 for (i = 0; i < key.num_values; i++) {
12015 char str[256];
12016 size = sizeof(str);
12018 r->rsprintf("<input type=\"button\" title=\"display last %s\" value=%s onclick=\"histDisp('scale=%s')\">\n", str, str, str);
12019 }
12020
12021 r->rsprintf("<input type=\"button\" value=\"<<<\" title=\"go back in time to last available data for all variables on the plot\" onclick=\"histDisp('shift=leftmaxall')\">");
12022 r->rsprintf("<input type=\"button\" value=\"<<\" title=\"go back in time to last available data\" onclick=\"histDisp('shift=leftmax')\">");
12023 r->rsprintf("<input type=\"button\" value=\"<\" title=\"go back in time\" onclick=\"histDisp('shift=left')\">");
12024
12025 r->rsprintf("<input type=\"button\" value=\" + \" title=\"zoom in\" onclick=\"histDisp('shift=zoomin')\">");
12026 r->rsprintf("<input type=\"button\" value=\" - \" title=\"zoom out\" onclick=\"histDisp('shift=zoomout')\">");
12027
12028 if (endtime != 0) {
12029 r->rsprintf("<input type=\"button\" value=\">\" title=\"go forward in time\" onclick=\"histDisp('shift=right')\">");
12030 r->rsprintf("<input type=\"button\" value=\">>\" title=\"go to currently updated fresh data\" onclick=\"histDisp('shift=rightmax')\">");
12031 }
12032
12033 r->rsprintf("<td>\n");
12034 r->rsprintf("<input type=\"button\" value=\"Large\" title=\"large display\" onclick=\"histDisp('width=Large')\">\n");
12035 r->rsprintf("<input type=\"button\" value=\"Small\" title=\"large display\" onclick=\"histDisp('width=Small')\">\n");
12036 r->rsprintf("<input type=\"button\" value=\"Create Elog\" title=\"large display\" onclick=\"histDisp('hcmd=Create Elog')\">\n");
12037 r->rsprintf("<input type=\"button\" value=\"Config\" title=\"large display\" onclick=\"histDisp('hcmd=Config')\">\n");
12038 r->rsprintf("<input type=\"button\" value=\"Export\" title=\"large display\" onclick=\"histDisp('hcmd=Export')\">\n");
12039 r->rsprintf("</tr>\n");
12040
12041 char paramstr[256];
12042
12043 paramstr[0] = 0;
12044 sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12045 if (endtime != 0)
12047 if (pwidth && *pwidth)
12048 sprintf(paramstr + strlen(paramstr), "&width=%s", pwidth);
12049 else {
12050 std::string wi = "640";
12051 db_get_value_string(hDB, 0, "/History/Display Settings/Width Individual", 0, &wi, TRUE);
12052 sprintf(paramstr + strlen(paramstr), "&width=%s", wi.c_str());
12053 }
12054 if (pheight && *pheight)
12055 sprintf(paramstr + strlen(paramstr), "&height=%s", pheight);
12056
12057 /* define image map */
12058 r->rsprintf("<map name=\"%s\">\r\n", hpanel);
12059
12060 if (!(pindex && *pindex)) {
12061 std::string path;
12062 path += "/History/Display/";
12063 path += hgroup;
12064 path += "/";
12065 path += hpanel;
12066 path += "/Variables";
12067 db_find_key(hDB, 0, path.c_str(), &hkey);
12068 if (hkey) {
12069 db_get_key(hDB, hkey, &key);
12070
12071 for (i = 0; i < key.num_values; i++) {
12072 std::string ref;
12073 //if (paramstr[0]) {
12074 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&%s&index=%d", hgroup, hpanel, paramstr, i);
12075 //} else {
12076 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&index=%d", hgroup, hpanel, i);
12077 //}
12078
12079 ref += "?cmd=oldhistory&group=";
12080 ref += hgroup;
12081 ref += "&panel=";
12082 ref += hpanel;
12083 if (paramstr[0]) {
12084 ref += "&";
12085 ref += paramstr;
12086 }
12087 ref += "&index=";
12088 ref += toString(i);
12089
12090 r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 30, 31 + 23 * i, 150, 30 + 23 * i + 17, ref.c_str());
12091 }
12092 }
12093 } else {
12094 std::string ref = "?cmd=oldhistory&group=";
12095 ref += hgroup;
12096 ref += "&panel=";
12097 ref += hpanel;
12098
12099 if (paramstr[0]) {
12100 ref += "&";
12101 ref += paramstr;
12102 }
12103
12104 if (equal_ustring(pwidth, "Large"))
12105 width = 1024;
12106 else if (equal_ustring(pwidth, "Small"))
12107 width = 320;
12108 else if (atoi(pwidth) > 0)
12109 width = atoi(pwidth);
12110 else
12111 width = 640;
12112
12113 r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 0, 0, width, 20, ref.c_str());
12114 }
12115
12116 r->rsprintf("</map>\r\n");
12117
12118 /* Display individual panels */
12119 if (pindex && *pindex)
12120 sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12121
12122 std::string ref;
12123 //sprintf(ref, "graph.gif?cmd=oldhistory&group=%s&panel=%s%s", hgroup, hpanel, paramstr);
12124 ref += "graph.gif?cmd=oldhistory&group=";
12125 ref += hgroup;
12126 ref += "&panel=";
12127 ref += hpanel;
12128 ref += paramstr;
12129
12130 /* put reference to graph */
12131 r->rsprintf("<tr><td colspan=2><img src=\"%s\" usemap=\"#%s\"></tr>\n", ref.c_str(), hpanel);
12132 }
12133
12134 else if (equal_ustring(hgroup, "All")) {
12135 /* Display all panels */
12136 db_find_key(hDB, 0, "/History/Display", &hkey);
12137 if (hkey)
12138 for (i = 0, k = 0;; i++) { // scan Groups
12140
12141 if (!hkeyp)
12142 break;
12143
12144 db_get_key(hDB, hkeyp, &key);
12145
12146 char enc_group_name[256];
12149
12150 for (j = 0;; j++, k++) {
12151 // scan items
12153
12154 if (!hikeyp)
12155 break;
12156
12158
12159 char enc_panel_name[256];
12162
12163 std::string ref;
12164 ref += "graph.gif?width=Small";
12165 ref += "&cmd=oldhistory&group=";
12167 ref += "&panel=";
12169
12170 std::string ref2;
12171 ref2 += "?cmd=oldhistory&group=";
12173 ref2 += "&panel=";
12175
12176 if (endtime != 0) {
12177 char tmp[256];
12178 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
12179 ref += "&";
12180 ref += tmp;
12181 ref2 += "&";
12182 ref2 += tmp;
12183 }
12184
12185 if (k % 2 == 0)
12186 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
12187 else
12188 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
12189 } // items loop
12190 } // Groups loop
12191 } // All
12192 r->rsprintf("</table>\r\n");
12193 r->rsprintf("</div>\n"); // closing for <div id="mmain">
12194 r->rsprintf("</form>\n");
12195 r->rsprintf("</body></html>\r\n");
12196}
12197
12198
12199/*------------------------------------------------------------------*/
12200
12201void send_icon(Return* r, const char *icon)
12202{
12203 int length;
12204 const unsigned char *picon;
12205 char str[256], format[256];
12206 time_t now;
12207
12208 if (strstr(icon, "favicon.ico") != 0) {
12209 length = sizeof(favicon_ico);
12211 } else if (strstr(icon, "favicon.png") != 0) {
12212 length = sizeof(favicon_png);
12214 } else
12215 return;
12216
12217 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
12218 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12219 r->rsprintf("Accept-Ranges: bytes\r\n");
12220
12221 /* set expiration time to one day */
12222 time(&now);
12223 now += (int) (3600 * 24);
12224 struct tm gmt_tms;
12225 gmtime_r(&now, &gmt_tms);
12226 strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12227 strftime(str, sizeof(str), format, &gmt_tms);
12228 r->rsprintf("Expires: %s\r\n", str);
12229
12230 if (equal_ustring(icon, "favicon.ico"))
12231 r->rsprintf("Content-Type: image/x-icon\r\n");
12232 else
12233 r->rsprintf("Content-Type: image/png\r\n");
12234
12235 r->rsprintf("Content-Length: %d\r\n\r\n", length);
12236
12237 r->rmemcpy(picon, length);
12238}
12239
12240/*------------------------------------------------------------------*/
12241
12243{
12244 std::string cookie_pwd;
12245 std::string cookie_wpwd;
12246 std::string cookie_cpwd;
12247 int refresh = 0;
12248 //int expand_equipment = 0;
12249};
12250
12251/*------------------------------------------------------------------*/
12252
12254{
12255 gMutex.lock();
12256 t->fTimeLocked = GetTimeSec();
12257}
12258
12260{
12262 gMutex.unlock();
12263}
12264
12265/*------------------------------------------------------------------*/
12266
12267void interprete(Param* p, Return* r, Attachment* a, const Cookies* c, const char *dec_path, RequestTrace* t)
12268/********************************************************************\
12269
12270 Routine: interprete
12271
12272 Purpose: Main interpreter of web commands
12273
12274 \********************************************************************/
12275{
12276 int status;
12277 HNDLE hkey, hDB;
12278
12279 //printf("dec_path [%s]\n", dec_path);
12280
12281 if (strstr(dec_path, "favicon.ico") != 0 ||
12282 strstr(dec_path, "favicon.png")) {
12283 send_icon(r, dec_path);
12284 return;
12285 }
12286
12287 const char* password = p->getparam("pwd");
12288 const char* wpassword = p->getparam("wpwd");
12289 const char* command = p->getparam("cmd");
12290
12291 //printf("interprete: dec_path [%s], command [%s]\n", dec_path, command);
12292
12294 MVOdb* odb = gOdb;
12295
12296 if (history_mode) {
12297 if (equal_ustring(command, "history")) {
12298 if (equal_ustring(command, "config")) {
12299 return;
12300 }
12301
12302 Lock(t);
12303 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12304 Unlock(t);
12305 return;
12306 }
12307 return;
12308 }
12309
12310 /* check for password */
12311 db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12312 if (!password[0] && hkey) {
12313 char str[256];
12314 int size = sizeof(str);
12315 db_get_data(hDB, hkey, str, &size, TID_STRING);
12316
12317 /* check for excemption */
12318 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12319 if (hkey == 0 && strcmp(c->cookie_pwd.c_str(), str) != 0) {
12320 Lock(t);
12322 Unlock(t);
12323 return;
12324 }
12325 }
12326
12327 /*---- redirect with cookie if password given --------------------*/
12328
12329 if (password[0]) {
12330 r->rsprintf("HTTP/1.1 302 Found\r\n");
12331 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12332
12333 time_t now;
12334 time(&now);
12335
12336 now += 3600 * 24;
12337
12338 struct tm gmt_tms;
12339 gmtime_r(&now, &gmt_tms);
12340
12341 char str[256];
12342 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12343
12344 r->rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12345 ss_crypt(password, "mi"), str);
12346
12347 r->rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12348 return;
12349 }
12350
12351 if (wpassword[0]) {
12352 /* check if password correct */
12353 if (!check_web_password(r, hDB, dec_path, ss_crypt(wpassword, "mi"), p->getparam("redir")))
12354 return;
12355
12356 r->rsprintf("HTTP/1.1 302 Found\r\n");
12357 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12358
12359 time_t now;
12360 time(&now);
12361
12362 now += 3600 * 24;
12363
12364 struct tm gmt_tms;
12365 gmtime_r(&now, &gmt_tms);
12366
12367 char str[256];
12368 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", &gmt_tms);
12369
12370 r->rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", ss_crypt(wpassword, "mi"), str);
12371
12372 sprintf(str, "./%s", p->getparam("redir"));
12373 r->rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12374 return;
12375 }
12376
12377 /*---- send sound file -------------------------------------------*/
12378
12379 if (strlen(dec_path) > 3 &&
12380 dec_path[strlen(dec_path)-3] == 'm' &&
12381 dec_path[strlen(dec_path)-2] == 'p' &&
12382 dec_path[strlen(dec_path)-1] == '3') {
12383 if (strrchr(dec_path, '/'))
12384 send_resource(r, strrchr(dec_path, '/')+1);
12385 else
12387 return;
12388 }
12389
12390 /*---- send midas.js and midas.css -------------------------------*/
12391
12392 if (strstr(dec_path, "midas.js")) {
12393 send_resource(r, "midas.js");
12394 return;
12395 }
12396
12397 if (strstr(dec_path, "midas.css")) {
12398 send_resource(r, "midas.css");
12399 return;
12400 }
12401
12402 /*---- send mhttpd.js --------------------------------------------*/
12403
12404 if (strstr(dec_path, "mhttpd.js")) {
12405 send_resource(r, "mhttpd.js");
12406 return;
12407 }
12408
12409 /*---- send obsolete.js ------------------------------------------*/
12410
12411 if (strstr(dec_path, "obsolete.js")) {
12412 send_resource(r, "obsolete.js");
12413 return;
12414 }
12415
12416 /*---- send the obsolete mhttpd.css ------------------------------*/
12417
12418 if (strstr(dec_path, "mhttpd.css")) {
12419 send_resource(r, "mhttpd.css");
12420 return;
12421 }
12422
12423 /*---- send controls.js ------------------------------------------*/
12424
12425 if (strstr(dec_path, "controls.js")) {
12426 send_resource(r, "controls.js");
12427 return;
12428 }
12429
12430 /*---- send example web page -------------------------------------*/
12431
12432 if (equal_ustring(command, "example")) {
12433 send_resource(r, "example.html");
12434 return;
12435 }
12436
12437 /*---- send example custom page -------------------------------------*/
12438
12439 if (equal_ustring(command, "custom_example")) {
12440 send_resource(r, "custom_example.html");
12441 return;
12442 }
12443
12444 if (equal_ustring(command, "plot_example")) {
12445 send_resource(r, "plot_example.html");
12446 return;
12447 }
12448
12449 /*---- script command --------------------------------------------*/
12450
12451 if (p->getparam("script") && *p->getparam("script")) {
12452
12453 std::string str = msprintf("%s?script=%s", dec_path, p->getparam("script"));
12454 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12455 return;
12456
12457 std::string path;
12458 path += "/Script/";
12459 path += p->getparam("script");
12460
12461 Lock(t);
12462
12463 cm_exec_script(path.c_str());
12464
12465 Unlock(t);
12466
12467 if (p->isparam("redir"))
12468 redirect2(r, p->getparam("redir"));
12469 else
12470 redirect2(r, "");
12471
12472 return;
12473 }
12474
12475 /*---- customscript command --------------------------------------*/
12476
12477 if (p->getparam("customscript") && *p->getparam("customscript")) {
12478
12479 std::string str = msprintf("%s?customscript=%s", dec_path, p->getparam("customscript"));
12480 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12481 return;
12482
12483 std::string path;
12484 path += "/CustomScript/";
12485 path += p->getparam("customscript");
12486
12487 Lock(t);
12488
12489 cm_exec_script(path.c_str());
12490
12491 Unlock(t);
12492
12493 if (p->isparam("redir"))
12494 redirect2(r, p->getparam("redir"));
12495 else
12496 redirect2(r, str.c_str());
12497
12498 return;
12499 }
12500
12501 /*---- send the new html pages -----------------------------------*/
12502
12503 if (equal_ustring(command, "start")) {
12504 send_resource(r, "start.html");
12505 return;
12506 }
12507
12508 if ((equal_ustring(command, "") || equal_ustring(command, "status")) && strlen(dec_path) == 0) {
12509 if (midas::odb::exists("/Custom/Status")) {
12510 midas::odb custom("/Custom");
12511
12512 std::string filename = custom["Status"];
12513 filename = add_custom_path(filename);
12514
12515 // if custom file exists, send it (like normal web server)
12516 if (ss_file_exist(filename.c_str())) {
12517 send_file(r, filename);
12518 return;
12519 }
12520 } else
12521 send_resource(r, "status.html");
12522 return;
12523 }
12524
12525 if (equal_ustring(command, "eqtable")) {
12526 send_resource(r, "eqtable.html");
12527 return;
12528 }
12529
12530 if (equal_ustring(command, "newODB")) {
12531 send_resource(r, "odb.html");
12532 return;
12533 }
12534
12535 if (equal_ustring(command, "programs")) {
12536 send_resource(r, "programs.html");
12537 return;
12538 }
12539
12540 if (equal_ustring(command, "alarms")) {
12541 send_resource(r, "alarms.html");
12542 return;
12543 }
12544
12545 if (equal_ustring(command, "transition")) {
12546 send_resource(r, "transition.html");
12547 return;
12548 }
12549
12550 if (equal_ustring(command, "messages")) {
12551 send_resource(r, "messages.html");
12552 return;
12553 }
12554
12555 if (equal_ustring(command, "config") &&
12556 !(dec_path[0] == 'H' && dec_path[1] == 'S' && dec_path[2] == '/')) {
12557 send_resource(r, "config.html");
12558 return;
12559 }
12560
12561 if (equal_ustring(command, "chat")) {
12562 send_resource(r, "chat.html");
12563 return;
12564 }
12565
12566 if (equal_ustring(command, "buffers")) {
12567 send_resource(r, "buffers.html");
12568 return;
12569 }
12570
12571 if (equal_ustring(command, "Show elog")) {
12572 send_resource(r, "elog_show.html");
12573 return;
12574 }
12575
12576 if (equal_ustring(command, "Query elog")) {
12577 send_resource(r, "elog_query_form.html");
12578 return;
12579 }
12580
12581 if (equal_ustring(command, "New elog")) {
12582 send_resource(r, "elog_edit.html");
12583 return;
12584 }
12585
12586 if (equal_ustring(command, "Edit elog")) {
12587 send_resource(r, "elog_edit.html");
12588 return;
12589 }
12590
12591 if (equal_ustring(command, "Reply Elog")) {
12592 send_resource(r, "elog_edit.html");
12593 return;
12594 }
12595
12596 if (equal_ustring(command, "Last elog")) {
12597 send_resource(r, "elog_show.html");
12598 return;
12599 }
12600
12601 if (equal_ustring(command, "Submit Query")) {
12602 send_resource(r, "elog_query.html");
12603 return;
12604 }
12605
12606 if (equal_ustring(dec_path, "spinning-wheel.gif")) {
12607 send_resource(r, "spinning-wheel.gif");
12608 return;
12609 }
12610
12611 /*---- java script commands --------------------------------------*/
12612
12613 if (equal_ustring(command, "jset") ||
12614 equal_ustring(command, "jget") ||
12615 equal_ustring(command, "jcopy") ||
12616 equal_ustring(command, "jpaste") ||
12617 equal_ustring(command, "jkey") ||
12618 equal_ustring(command, "jcreate") ||
12619 equal_ustring(command, "jresize") ||
12620 equal_ustring(command, "jlink") ||
12621 equal_ustring(command, "jrename") ||
12622 equal_ustring(command, "jreorder") ||
12623 equal_ustring(command, "jdelete") ||
12624 equal_ustring(command, "jmsg") ||
12625 equal_ustring(command, "jalm") ||
12626 equal_ustring(command, "jgenmsg") ||
12627 equal_ustring(command, "jrpc_rev0") ||
12628 equal_ustring(command, "jrpc_rev1") ||
12629 equal_ustring(command, "jrpc")) {
12630 Lock(t);
12631 javascript_commands(p, r, c->cookie_cpwd.c_str());
12632 Unlock(t);
12633 return;
12634 }
12635
12636 /*---- history editord -------------------------------------------*/
12637
12638 if (equal_ustring(command, "hs_edit")) {
12639 send_resource(r, "hs_edit.html");
12640 return;
12641 }
12642
12643 /*---- history command -------------------------------------------*/
12644
12645 if (equal_ustring(command, "oldhistory")) {
12646 Lock(t);
12647 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12648 Unlock(t);
12649 return;
12650 }
12651
12652 if (equal_ustring(command, "history")) {
12653 send_resource(r, "history.html");
12654 return;
12655 }
12656
12657 /*---- MSCB command ----------------------------------------------*/
12658
12659 if (equal_ustring(command, "MSCB")) {
12660 if (equal_ustring(command, "set")) {
12661 std::string str;
12662 str += dec_path;
12663 str += "?";
12664 str += add_param_to_url("cmd", command);
12665 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12666 return;
12667 }
12668
12669 Lock(t);
12670
12671#ifdef HAVE_MSCB
12672 show_mscb_page(p, r, c->refresh);
12673#else
12674 show_error(r, "MSCB support not compiled into this version of mhttpd");
12675#endif
12676
12677 Unlock(t);
12678 return;
12679 }
12680
12681 /*---- help command ----------------------------------------------*/
12682
12683 if (equal_ustring(command, "help")) {
12684 Lock(t);
12686 Unlock(t);
12687 return;
12688 }
12689
12690 /*---- trigger equipment readout ---------------------------*/
12691
12692 if (strncmp(command, "Trigger", 7) == 0) {
12693 std::string cmd;
12694 cmd += "?cmd=";
12695 cmd += command;
12696 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), cmd.c_str())) {
12697 return;
12698 }
12699
12700 Lock(t);
12701
12702 /* extract equipment name */
12703 char eq_name[NAME_LENGTH];
12704
12705 mstrlcpy(eq_name, command + 8, sizeof(eq_name));
12706 if (strchr(eq_name, ' '))
12707 *strchr(eq_name, ' ') = 0;
12708
12709 /* get frontend name */
12710 std::string path;
12711 path += "/Equipment/";
12712 path += eq_name;
12713 path += "/Common/Frontend name";
12714 char fe_name[NAME_LENGTH];
12715 int size = NAME_LENGTH;
12716 db_get_value(hDB, 0, path.c_str(), fe_name, &size, TID_STRING, TRUE);
12717
12718 /* and ID */
12719 path = "";
12720 path += "/Equipment/";
12721 path += eq_name;
12722 path += "/Common/Event ID";
12723 WORD event_id = 0;
12724 size = sizeof(event_id);
12725 db_get_value(hDB, 0, path.c_str(), &event_id, &size, TID_WORD, TRUE);
12726
12727 if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12728 std::string str;
12729 str += "Frontend \"";
12730 str += fe_name;
12731 str += "\" not running!";
12732 show_error(r, str.c_str());
12733 } else {
12734 HNDLE hconn;
12736 if (status != RPC_SUCCESS) {
12737 std::string str;
12738 str += "Cannot connect to frontend \"";
12739 str += fe_name;
12740 str +="\" !";
12741 show_error(r, str.c_str());
12742 } else {
12744 if (status != CM_SUCCESS)
12745 show_error(r, "Error triggering event");
12746 else
12747 redirect(r, "");
12748
12749 //cm_disconnect_client(hconn, FALSE);
12750 }
12751 }
12752
12753 Unlock(t);
12754
12755 return;
12756 }
12757
12758 /*---- switch to next subrun -------------------------------------*/
12759
12760 if (strncmp(command, "Next Subrun", 11) == 0) {
12761 int i = TRUE;
12762 db_set_value(hDB, 0, "/Logger/Next subrun", &i, sizeof(i), 1, TID_BOOL);
12763 redirect(r, "");
12764 return;
12765 }
12766
12767 /*---- cancel command --------------------------------------------*/
12768
12769 if (equal_ustring(command, "cancel")) {
12770 if (p->isparam("redir"))
12771 redirect(r, p->getparam("redir"));
12772 else
12773 redirect(r, "");
12774 return;
12775 }
12776
12777 /*---- set command -----------------------------------------------*/
12778
12779 if (equal_ustring(command, "set")) {
12780 char str[256];
12781 mstrlcpy(str, "?cmd=set", sizeof(str));
12782 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str))
12783 return;
12784
12785 const char* group = p->getparam("group");
12786 int index = atoi(p->getparam("index"));
12787 const char* value = p->getparam("value");
12788
12789 Lock(t);
12790 show_set_page(p, r, group, index, value);
12791 Unlock(t);
12792 return;
12793 }
12794
12795 /*---- find command ----------------------------------------------*/
12796
12797 if (equal_ustring(command, "find")) {
12798 const char* value = p->getparam("value");
12799 Lock(t);
12801 Unlock(t);
12802 return;
12803 }
12804
12805 /*---- CAMAC CNAF command ----------------------------------------*/
12806
12807 if (equal_ustring(command, "CNAF") || strncmp(dec_path, "CNAF", 4) == 0) {
12808 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), "?cmd=CNAF"))
12809 return;
12810
12811 Lock(t);
12812 show_cnaf_page(p, r);
12813 Unlock(t);
12814 return;
12815 }
12816
12817 /*---- ELog command ----------------------------------------------*/
12818
12819 if (equal_ustring(command, "elog")) {
12820 /* redirect to external ELOG if URL present */
12823 std::string external_elog_url;
12824 int size = sizeof(external_elog);
12825 status = db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
12826 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
12827 if (external_elog && (external_elog_url.length() > 0)) {
12828 redirect(r, external_elog_url.c_str());
12829 return;
12830 }
12831 send_resource(r, "elog_show.html");
12832 return;
12833 }
12834
12835 // special processing for "Elog last 7d", etc
12836
12837 char cmdx[32];
12838 mstrlcpy(cmdx, command, sizeof(cmdx));
12839 cmdx[9] = 0;
12840
12841 if (equal_ustring(cmdx, "Elog last")) {
12842 // "Elog last 7d", etc
12843 send_resource(r, "elog_query.html");
12844 return;
12845 }
12846
12847 if (equal_ustring(command, "Create ELog from this page")) {
12848 std::string redir;
12849 redir += "?cmd=New+elog";
12850 redir += "&odb_path=";
12851 redir += p->getparam("odb_path");
12852 redirect(r, redir.c_str());
12853 return;
12854 }
12855
12856 if (equal_ustring(command, "Submit elog")) {
12857 Lock(t);
12858 submit_elog(odb, p, r, a);
12859 Unlock(t);
12860 return;
12861 }
12862
12863 if (equal_ustring(command, "elog_att")) {
12864 Lock(t);
12866 Unlock(t);
12867 return;
12868 }
12869
12870 /*---- accept command --------------------------------------------*/
12871
12872 if (equal_ustring(command, "accept")) {
12873 int refresh = atoi(p->getparam("refr"));
12874
12875 /* redirect with cookie */
12876 r->rsprintf("HTTP/1.1 302 Found\r\n");
12877 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12878 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
12879
12880 time_t now;
12881 time(&now);
12882
12883 now += 3600 * 24 * 365;
12884
12885 struct tm gmt_tms;
12886 gmtime_r(&now, &gmt_tms);
12887
12888 char str[256];
12889 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12890
12891 r->rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
12892 r->rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
12893
12894 return;
12895 }
12896
12897#ifdef OBSOLETE
12898 /*---- slow control display --------------------------------------*/
12899
12900 if (equal_ustring(command, "eqtable")) {
12901 Lock(t);
12902 show_eqtable_page(p, r, c->refresh);
12903 Unlock(t);
12904 return;
12905 }
12906#endif
12907
12908 /*---- sequencer page --------------------------------------------*/
12909
12910 if (equal_ustring(command, "Sequencer")) {
12911 send_resource(r, "sequencer.html");
12912 return;
12913 }
12914
12915 // obsolete
12916 if (equal_ustring(command, "seq")) {
12917 send_resource(r, "sequencer.html");
12918 return;
12919 }
12920
12921 if (equal_ustring(command, "start_script")) {
12922 send_resource(r, "start_script.html");
12923 return;
12924 }
12925
12926 if (equal_ustring(command, "load_script")) {
12927 send_resource(r, "load_script.html");
12928 return;
12929 }
12930
12931 if (equal_ustring(command, "edit_script")) {
12932 send_resource(r, "edit_script.html");
12933 return;
12934 }
12935
12936 /*---- show ODB --------------------------------------------------*/
12937
12938 if (equal_ustring(command, "oldOdb")) {
12939 int write_access = TRUE;
12940 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
12941 if (hkey) {
12942 char str[256];
12943 int size = sizeof(str);
12944 db_get_data(hDB, hkey, str, &size, TID_STRING);
12945 if (strcmp(c->cookie_wpwd.c_str(), str) == 0)
12947 else
12949 }
12950
12951 std::string odb_path;
12952 if (p->getparam("odb_path") && *p->getparam("odb_path"))
12953 odb_path = p->getparam("odb_path");
12954
12955 Lock(t);
12956 show_odb_page(p, r, odb_path.c_str(), write_access);
12957 Unlock(t);
12958 return;
12959 }
12960
12961 /*---- New ODB browser --------------------------------------------*/
12962
12963 if (equal_ustring(command, "odb")) {
12964 send_resource(r, "odb.html");
12965 return;
12966 }
12967
12968 /*---- ODB show open records --------------------------------------*/
12969
12970 if (equal_ustring(command, "odb_sor")) {
12971 send_resource(r, "odb_sor.html");
12972 return;
12973 }
12974
12975 /*---- ODB show clients -------------------------------------------*/
12976
12977 if (equal_ustring(command, "odb_scl")) {
12978 send_resource(r, "odb_scl.html");
12979 return;
12980 }
12981
12982 /*---- old ODB path ----------------------------------------------*/
12983
12984 if ((command[0]==0) && dec_path[0]) {
12985 if (equal_ustring(dec_path, "root")) {
12986 std::string new_url = "./?cmd=odb";
12987 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
12988 redirect_307(r, new_url.c_str());
12989 return;
12990 }
12991 }
12992
12993 if ((command[0]==0) && dec_path[0]) {
12994 HNDLE hkey;
12996 //printf("try odb path [%s], status %d\n", dec_path, status);
12997 if (status == DB_SUCCESS) {
12998 int level = 0;
12999 for (const char* s = dec_path; *s; s++) {
13000 if (*s == '/')
13001 level++;
13002 }
13003 std::string new_url;
13004 if (level == 0) {
13005 // Top-level directory like /Logger, (which appears in dec_path as "Logger")
13006 new_url += "./";
13007 } else {
13008 for (int i=0; i<level; i++) {
13009 if (i>0)
13010 new_url += "/";
13011 new_url += "..";
13012 }
13013 }
13014 new_url += "?cmd=odb";
13015 new_url += "&odb_path=";
13017 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13018 redirect_307(r, new_url.c_str());
13019 return;
13020 }
13021 }
13022
13023 /*---- event dump ------------------------------------------------*/
13024
13025 if (equal_ustring(command, "event dump")) {
13026 send_resource(r, "event_dump.html");
13027 return;
13028 }
13029
13030 /*---- custom page -----------------------------------------------*/
13031
13032 if (equal_ustring(command, "custom")) {
13033 Lock(t);
13034 show_custom_page(p, r, c->cookie_cpwd.c_str());
13035 Unlock(t);
13036 return;
13037 }
13038
13039 /*---- custom page accessed by direct URL that used to be under /CS/... ----*/
13040
13041 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13042 std::string odb_path;
13043 std::string value;
13044 int status;
13045
13046 odb_path = "";
13047 odb_path += "/Custom/Images/";
13048 odb_path += dec_path;
13049 odb_path += "/Background";
13050
13051 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13052
13053 //printf("Try custom gif [%s] status %d\n", odb_path.c_str(), status);
13054
13055 if (status == DB_SUCCESS) {
13056 if (strstr(dec_path, "..")) {
13057 std::string str;
13058 str += "Invalid custom gif name \'";
13059 str += dec_path;
13060 str += "\' contains \'..\'";
13061 show_error_404(r, str.c_str());
13062 return;
13063 }
13064
13065 Lock(t);
13067 Unlock(t);
13068 return;
13069 }
13070
13071 bool found_custom = false;
13072
13073 odb_path = "";
13074 odb_path += "/Custom/";
13075 odb_path += dec_path;
13076
13077 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13078
13079 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13080
13081 if (status == DB_SUCCESS) {
13082 found_custom = true;
13083 } else {
13084 odb_path = "";
13085 odb_path += "/Custom/";
13086 odb_path += dec_path;
13087 odb_path += "&";
13088
13089 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13090
13091 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13092
13093 if (status == DB_SUCCESS) {
13094 found_custom = true;
13095 } else {
13096 odb_path = "";
13097 odb_path += "/Custom/";
13098 odb_path += dec_path;
13099 odb_path += "!";
13100
13101 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13102
13103 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13104
13105 if (status == DB_SUCCESS) {
13106 found_custom = true;
13107 }
13108 }
13109 }
13110
13111 if (found_custom) {
13112 //printf("custom file: serving [%s] value [%s]\n", dec_path, value.c_str());
13113 if (strstr(dec_path, "..")) {
13114 std::string str;
13115 str += "Invalid custom page name \'";
13116 str += dec_path;
13117 str += "\' contains \'..\'";
13118 show_error_404(r, str.c_str());
13119 return;
13120 }
13121
13122 p->setparam("page", dec_path);
13123 Lock(t);
13124 show_custom_page(p, r, c->cookie_cpwd.c_str());
13125 Unlock(t);
13126 return;
13127 }
13128 }
13129
13130 /* new custom pages */
13131 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13132 std::string custom_path;
13133 status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
13134 if ((status == DB_SUCCESS) && (custom_path.length() > 0)) {
13135 if (strstr(dec_path, "..")) {
13136 std::string str;
13137 str += "Invalid custom file name \'";
13138 str += dec_path;
13139 str += "\' contains \'..\'";
13140 show_error_404(r, str.c_str());
13141 return;
13142 }
13143
13144 std::string full_filename = add_custom_path(dec_path);
13145
13146 // if custom file exists, send it (like normal web server)
13147 if (ss_file_exist(full_filename.c_str())) {
13149 return;
13150 }
13151 }
13152 }
13153
13154 /*---- redirect if web page --------------------------------------*/
13155
13156 //if (strlen(command) > 0) {
13157 // if (send_resource(r, std::string(command) + ".html", false))
13158 // return;
13159 //}
13160
13161 /*---- serve url as a resource file ------------------------------*/
13162
13163 if (strlen(p->getparam("path")) > 0) {
13164 if (send_resource(r, p->getparam("path"), false)) {
13165 return;
13166 }
13167 }
13168
13169 /*---- show status -----------------------------------------------*/
13170
13171 if (elog_mode) {
13172 redirect(r, "EL/");
13173 return;
13174 }
13175
13176 /* header */
13177 r->rsprintf("HTTP/1.1 400 Bad Request\r\n");
13178 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
13179 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
13180 r->rsprintf("\r\n");
13181 r->rsprintf("Error: Invalid URL \"%s\" or query \"%s\" or command \"%s\"\n", p->getparam("path"), p->getparam("query"), command);
13182}
13183
13184/*------------------------------------------------------------------*/
13185
13186void decode_query(Param* pp, const char *query_string)
13187{
13188 int len = strlen(query_string);
13189 char *buf = (char *)malloc(len+1);
13190 assert(buf != NULL);
13191 memcpy(buf, query_string, len+1);
13192 char* p = buf;
13193 p = strtok(p, "&");
13194 while (p != NULL) {
13195 char *pitem = p;
13196 p = strchr(p, '=');
13197 if (p != NULL) {
13198 *p++ = 0;
13199 urlDecode(pitem); // parameter name
13200 if (!equal_ustring(pitem, "format"))
13201 urlDecode(p); // parameter value
13202
13203 pp->setparam(pitem, p); // decoded query parameters
13204
13205 p = strtok(NULL, "&");
13206 }
13207 }
13208 free(buf);
13209}
13210
13211void decode_get(Return* rr, char *string, const Cookies* c, const char* url, const char* query_string, RequestTrace* t)
13212{
13213 char path[256];
13214
13215 //printf("decode_get: string [%s], decode_url %d, url [%s], query_string [%s]\n", string, decode_url, url, query_string);
13216
13217 Param* param = new Param();
13218
13219 param->initparam();
13220
13221 if (url)
13222 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13223 else {
13224 mstrlcpy(path, string + 1, sizeof(path)); /* strip leading '/' */
13225
13226 if (strchr(path, '?'))
13227 *strchr(path, '?') = 0;
13228 }
13229
13230 param->setparam("path", path);
13231
13232 assert(query_string != NULL);
13233
13234 decode_query(param, query_string);
13235
13236 param->setparam("query", query_string);
13237
13238 char dec_path[256];
13239 mstrlcpy(dec_path, path, sizeof(dec_path));
13240
13241 interprete(param, rr, NULL, c, dec_path, t);
13242
13243 param->freeparam();
13244 delete param;
13245}
13246
13247/*------------------------------------------------------------------*/
13248
13249void decode_post(Return* rr, const char *header, const char *string, const char *boundary, int length, const Cookies* c, const char* url, RequestTrace* t)
13250{
13251 bool debug_decode_post = false;
13252
13253 Param* param = new Param;
13254
13255 param->initparam();
13256
13257 char path[256];
13258
13259 if (url)
13260 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13261 else {
13262 mstrlcpy(path, header + 1, sizeof(path)); /* strip leading '/' */
13263 if (strchr(path, '?'))
13264 *strchr(path, '?') = 0;
13265 if (strchr(path, ' '))
13266 *strchr(path, ' ') = 0;
13267 }
13268 param->setparam("path", path); // undecoded path
13269
13270 Attachment* a = new Attachment;
13271
13272 const char* pinit = string;
13273
13274 /* return if no boundary defined */
13275 if (!boundary[0])
13276 return;
13277
13278 if (strstr(string, boundary))
13279 string = strstr(string, boundary) + strlen(boundary);
13280
13282 printf("decode_post: -->[%s]<--\n", string);
13283
13284 do {
13285 //printf("decode_post: [%s]\n", string);
13286 if (strstr(string, "name=")) {
13287 const char* pitem = strstr(string, "name=") + 5;
13288 if (*pitem == '\"')
13289 pitem++;
13290
13291 //printf("decode_post: pitem [%s]\n", pitem);
13292
13293 if (strncmp(pitem, "attfile", 7) == 0) {
13294 int n = pitem[7] - '1';
13295
13296 char file_name[256];
13297 file_name[0] = 0;
13298
13299 /* evaluate file attachment */
13300 if (strstr(pitem, "filename=")) {
13301 const char* p = strstr(pitem, "filename=") + 9;
13302 if (*p == '\"')
13303 p++;
13304 if (strstr(p, "\r\n\r\n"))
13305 string = strstr(p, "\r\n\r\n") + 4;
13306 else if (strstr(p, "\r\r\n\r\r\n"))
13307 string = strstr(p, "\r\r\n\r\r\n") + 6;
13308
13309 mstrlcpy(file_name, p, sizeof(file_name));
13310
13311 char* pp = file_name;
13312 if (strchr(pp, '\"'))
13313 *strchr(pp, '\"') = 0;
13314
13315 /* set attachment filename */
13316 char str[256];
13317 sprintf(str, "attachment%d", n);
13319 printf("decode_post: [%s] = [%s]\n", str, file_name);
13320 param->setparam(str, file_name); // file_name should be decoded?
13321 }
13322
13323 /* find next boundary */
13324 const char* ptmp = string;
13325 const char* p = NULL;
13326 do {
13327 while (*ptmp != '-')
13328 ptmp++;
13329
13330 p = strstr(ptmp, boundary);
13331 if (p != NULL) {
13332 while (*p == '-')
13333 p--;
13334 if (*p == 10)
13335 p--;
13336 if (*p == 13)
13337 p--;
13338 p++;
13339 break;
13340 } else
13341 ptmp += strlen(ptmp);
13342
13343 } while (TRUE);
13344
13345 /* save pointer to file */
13346 if (file_name[0]) {
13347 size_t size = (POINTER_T) p - (POINTER_T) string;
13348 char* buf = (char*)malloc(size+1);
13349 if (!buf) {
13350 return;
13351 }
13352 memcpy(buf, string, size);
13353 buf[size] = 0; // make sure string is NUL terminated
13354 a->attachment_buffer[n] = buf;
13355 a->attachment_size[n] = size;
13357 printf("decode_post: attachment[%d] size %d data --->[%s]<---\n", n, (int)a->attachment_size[n], a->attachment_buffer[n]);
13358 }
13359
13360 string = strstr(p, boundary) + strlen(boundary);
13361 } else {
13362 const char* p = pitem;
13363 if (strstr(p, "\r\n\r\n"))
13364 p = strstr(p, "\r\n\r\n") + 4;
13365 else if (strstr(p, "\r\r\n\r\r\n"))
13366 p = strstr(p, "\r\r\n\r\r\n") + 6;
13367
13368 char* ppitem = (char*)strchr(pitem, '\"'); // NB: defeat "const char* string"
13369 if (ppitem)
13370 *ppitem = 0;
13371
13372 char* pb = (char*)(strstr(p, boundary)); // NB: defeat "const char* string"
13373 if (pb) {
13374 string = pb + strlen(boundary);
13375 *pb = 0;
13376 char* ptmp = (char*)(p + (strlen(p) - 1)); // NB: defeat "const char* string"
13377 while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13378 *ptmp-- = 0;
13379 } else {
13380 show_error(rr, "Invalid POST request");
13381 return;
13382 }
13384 printf("decode_post: [%s] = [%s]\n", pitem, p);
13385 param->setparam(pitem, p); // in decode_post()
13386 }
13387
13388 while (*string == '-' || *string == '\n' || *string == '\r')
13389 string++;
13390 }
13391
13392 } while ((POINTER_T) string - (POINTER_T) pinit < length);
13393
13394 char dec_path[256];
13395 mstrlcpy(dec_path, path, sizeof(dec_path));
13396
13397 interprete(param, rr, a, c, dec_path, t);
13398
13399 delete a;
13400 delete param;
13401}
13402
13403/*------------------------------------------------------------------*/
13404
13406{
13407 HNDLE hDB, hKeyEq, hKey;
13409 int i, status;
13410 KEY key;
13411
13412 /* check /Runinfo structure */
13414 assert(status == DB_SUCCESS);
13415
13416 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), FALSE);
13417 if (status == DB_STRUCT_MISMATCH) {
13418 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), TRUE);
13419 if (status == DB_SUCCESS) {
13420 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo corrected successfully");
13421 } else {
13422 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13423 return 0;
13424 }
13425 } else if (status == DB_NO_KEY) {
13426 cm_msg(MERROR, "check_odb_records", "ODB subtree /Runinfo does not exist");
13427 status = db_create_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str());
13428 if (status == DB_SUCCESS) {
13429 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo created successfully");
13430 } else {
13431 cm_msg(MERROR, "check_odb_records", "Cannot create ODB subtree /Runinfo, db_create_record() status %d", status);
13432 return 0;
13433 }
13434 } else if (status != DB_SUCCESS) {
13435 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13436 return 0;
13437 }
13438
13439 /* check /Equipment/<name>/Common structures */
13440 if (db_find_key(hDB, 0, "/equipment", &hKeyEq) == DB_SUCCESS) {
13441 for (i = 0 ;; i++) {
13443 if (!hKey)
13444 break;
13445 db_get_key(hDB, hKey, &key);
13446
13448 if (status == DB_STRUCT_MISMATCH) {
13450 if (status == DB_SUCCESS) {
13451 cm_msg(MINFO, "check_odb_records", "ODB subtree /Equipment/%s/Common corrected successfully", key.name);
13452 } else {
13453 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13454 }
13455 } else if (status != DB_SUCCESS) {
13456 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13457 }
13458 }
13459 }
13460
13461 return CM_SUCCESS;
13462}
13463
13464
13465/*------------------------------------------------------------------*/
13466
13467std::atomic_bool _abort{false};
13468
13469void ctrlc_handler(int sig)
13470{
13471 _abort = true;
13472}
13473
13474/*------------------------------------------------------------------*/
13475
13476#ifdef HAVE_MONGOOSE6
13477static std::vector<std::string> gUserAllowedHosts;
13478#endif
13479static std::vector<std::string> gAllowedHosts;
13480#ifdef HAVE_MONGOOSE6
13481static const std::string gOdbAllowedHosts = "/Experiment/Security/mhttpd hosts/Allowed hosts";
13482#endif
13483
13484#ifdef HAVE_MONGOOSE6
13485static void load_allowed_hosts(HNDLE hDB, HNDLE hKey, int index, void* info)
13486{
13487 if (hKey != 0)
13488 cm_msg(MINFO, "load_allowed_hosts", "Reloading mhttpd hosts access control list via hotlink callback");
13489
13490 gAllowedHosts.clear();
13491
13492 // copy the user allowed hosts
13493 for (unsigned int i=0; i<gUserAllowedHosts.size(); i++)
13494 gAllowedHosts.push_back(gUserAllowedHosts[i]);
13495
13496 int total = 0;
13497 int last = 0;
13498 for (int i=0; ; i++) {
13499 std::string s;
13500 int status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), i, &s, FALSE);
13501 //printf("get %d, status %d, string [%s]\n", i, status, s.c_str());
13502 if (status != DB_SUCCESS) {
13503 total = i;
13504 break;
13505 }
13506
13507 if (s.length() < 1) // skip emties
13508 continue;
13509
13510 if (s[0] == '#') // skip commented-out entries
13511 continue;
13512
13513 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
13514 gAllowedHosts.push_back(s);
13515 last = i;
13516 }
13517
13518 //printf("total %d, last %d\n", total, last);
13519
13520 if (total - last < 5) {
13521 int new_size = last + 10;
13522 //printf("new size %d\n", new_size);
13523 int status = db_resize_string(hDB, 0, gOdbAllowedHosts.c_str(), new_size, 256);
13524 if (status != DB_SUCCESS) {
13525 cm_msg(MERROR, "load_allowed_hosts", "Cannot resize the allowed hosts access control list, db_resize_string(%d) status %d", new_size, status);
13526 }
13527 }
13528}
13529
13530static int init_allowed_hosts()
13531{
13532 HNDLE hDB;
13533 HNDLE hKey;
13534 int status;
13535
13537
13538 // create "allowed hosts" so we can watch it
13539
13540 std::string s;
13541 status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), 0, &s, TRUE);
13542
13543 if (status != DB_SUCCESS) {
13544 cm_msg(MERROR, "init_allowed_hosts", "Cannot create the mhttpd hosts access control list, db_get_value_string() status %d", status);
13545 return status;
13546 }
13547
13548 status = db_find_key(hDB, 0, gOdbAllowedHosts.c_str(), &hKey);
13549
13550 if (status != DB_SUCCESS || hKey == 0) {
13551 cm_msg(MERROR, "init_allowed_hosts", "Cannot find the mhttpd hosts access control list, db_find_key() status %d", status);
13552 return status;
13553 }
13554
13555 load_allowed_hosts(hDB, 0, 0, NULL);
13556
13558
13559 if (status != DB_SUCCESS) {
13560 cm_msg(MERROR, "init_allowed_hosts", "Cannot watch the mhttpd hosts access control list, db_watch() status %d", status);
13561 return status;
13562 }
13563
13564 return SUCCESS;
13565}
13566
13567 int check_midas_acl(const struct sockaddr *sa, int len) {
13568 // access control list is empty?
13569 if (gAllowedHosts.size() == 0)
13570 return 1;
13571
13572 char hname[NI_MAXHOST];
13573 hname[0] = 0;
13574
13575 int status;
13576 const char* status_string = "success";
13577
13578 status = getnameinfo(sa, len, hname, sizeof(hname), NULL, 0, 0);
13579
13580 if (status)
13582
13583 //printf("connection from [%s], status %d (%s)\n", hname, status, status_string);
13584
13585 if (status != 0) {
13586 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, status, status_string);
13587 return 0;
13588 }
13589
13590 /* always permit localhost */
13591 if (strcmp(hname, "localhost.localdomain") == 0)
13592 return 1;
13593 if (strcmp(hname, "localhost") == 0)
13594 return 1;
13595
13596 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++)
13597 if (gAllowedHosts[i] == hname) {
13598 return 1;
13599 }
13600
13601 printf("Rejecting connection from \'%s\'\n", hname);
13602 return 0;
13603 }
13604
13605int open_listening_socket(int port)
13606{
13607 int status;
13608 struct sockaddr_in bind_addr;
13609
13610 /* create a new socket */
13611 int lsock = socket(AF_INET, SOCK_STREAM, 0);
13612
13613 if (lsock == -1) {
13614 printf("Cannot create socket, socket() errno %d (%s)\n", errno, strerror(errno));
13615 return -1;
13616 }
13617
13618 /* bind local node name and port to socket */
13619 memset(&bind_addr, 0, sizeof(bind_addr));
13620 bind_addr.sin_family = AF_INET;
13621 bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13622 bind_addr.sin_port = htons((short) port);
13623
13624 /* try reusing address */
13625 int flag = 1;
13626 status = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13627
13628 if (status < 0) {
13629 printf("Cannot setsockopt(SOL_SOCKET, SO_REUSEADDR), errno %d (%s)\n", errno, strerror(errno));
13630 return -1;
13631 }
13632
13633 status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13634
13635 if (status < 0) {
13636 printf("Cannot bind() to port %d, bind() errno %d (%s)\n", port, errno, strerror(errno));
13637 return -1;
13638 }
13639
13640 /* listen for connection */
13642 if (status < 0) {
13643 printf("Cannot listen() on port %d, errno %d (%s), bye!\n", port, errno, strerror(errno));
13644 return -1;
13645 }
13646
13647 printf("mhttpd is listening on port %d\n", port);
13648
13649 return lsock;
13650}
13651#endif
13652
13653/*------------------------------------------------------------------*/
13654
13655int try_file_mg(const char* try_dir, const char* filename, std::string& path, FILE** fpp, bool trace)
13656{
13657 if (fpp)
13658 *fpp = NULL;
13659 if (!try_dir)
13660 return SS_FILE_ERROR;
13661 if (strlen(try_dir) < 1)
13662 return SS_FILE_ERROR;
13663
13664 path = try_dir;
13665 if (path[path.length()-1] != DIR_SEPARATOR)
13666 path += DIR_SEPARATOR_STR;
13667 path += filename;
13668
13669 FILE* fp = fopen(path.c_str(), "r");
13670
13671 if (trace) {
13672 if (fp)
13673 printf("file \"%s\": OK!\n", path.c_str());
13674 else
13675 printf("file \"%s\": not found.\n", path.c_str());
13676 }
13677
13678 if (!fp)
13679 return SS_FILE_ERROR;
13680 else if (fpp)
13681 *fpp = fp;
13682 else
13683 fclose(fp);
13684
13685 return SUCCESS;
13686}
13687
13688int find_file_mg(const char* filename, std::string& path, FILE** fpp, bool trace)
13689{
13690 std::string exptdir = cm_get_path();
13691
13692 if (try_file_mg(".", filename, path, fpp, trace) == SUCCESS)
13693 return SUCCESS;
13694
13695 if (try_file_mg(getenv("MIDAS_DIR"), filename, path, fpp, trace) == SUCCESS)
13696 return SUCCESS;
13697
13698 if (try_file_mg(exptdir.c_str(), filename, path, fpp, trace) == SUCCESS)
13699 return SUCCESS;
13700
13701 if (try_file_mg(getenv("MIDASSYS"), filename, path, fpp, trace) == SUCCESS)
13702 return SUCCESS;
13703
13704 // setup default filename
13705 try_file_mg(exptdir.c_str(), filename, path, NULL, false);
13706 return SS_FILE_ERROR;
13707}
13708
13709#ifdef HAVE_MONGOOSE6
13710#include "mongoose6.h"
13711#endif
13712
13713#ifdef HAVE_MONGOOSE616
13714#undef closesocket
13715#include "mongoose616.h"
13716// cs_md5() in not in mongoose.h
13717extern void cs_md5(char buf[33], ...);
13718#endif
13719
13720static bool verbose_mg = false;
13721static bool trace_mg = false;
13722static bool trace_mg_recv = false;
13723static bool trace_mg_send = false;
13724static bool trace_mg_verbose = false;
13725#ifdef HAVE_MONGOOSE616
13726static bool multithread_mg = true;
13727#endif
13728
13729#ifdef HAVE_MONGOOSE6
13730static struct mg_mgr mgr_mg;
13731#endif
13732
13734 std::string username;
13735 std::string realm;
13736 std::string password;
13737};
13738
13739class Auth {
13740public:
13741 std::string realm;
13742 std::string passwd_filename;
13743 std::vector<AuthEntry> passwords;
13744public:
13745 int Init();
13746};
13747
13748static bool read_passwords(Auth* auth);
13749
13751{
13752 std::string exptname = cm_get_experiment_name();
13753
13754 if (!exptname.empty())
13755 realm = exptname;
13756 else
13757 realm = "midas";
13758
13759 bool ok = read_passwords(this);
13760 if (!ok) {
13761 cm_msg(MERROR, "mongoose", "mongoose web server password file \"%s\" has no passwords for realm \"%s\"", passwd_filename.c_str(), realm.c_str());
13762 cm_msg(MERROR, "mongoose", "please add passwords by running: htdigest %s %s midas", passwd_filename.c_str(), realm.c_str());
13763 return SS_FILE_ERROR;
13764 }
13765
13766 return SUCCESS;
13767}
13768
13770
13771static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri,
13772 size_t uri_len, const char *ha1, size_t ha1_len,
13773 const char *nonce, size_t nonce_len, const char *nc,
13774 size_t nc_len, const char *cnonce, size_t cnonce_len,
13775 const char *qop, size_t qop_len, char *resp) {
13776 static const char colon[] = ":";
13777 static const size_t one = 1;
13778 char ha2[33];
13779
13780 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
13781 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
13782 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
13783 colon, one, ha2, sizeof(ha2) - 1, NULL);
13784}
13785
13786/*
13787 * Check for authentication timeout.
13788 * Clients send time stamp encoded in nonce. Make sure it is not too old,
13789 * to prevent replay attacks.
13790 * Assumption: nonce is a hexadecimal number of seconds since 1970.
13791 */
13792static int xmg_check_nonce(const char *nonce) {
13793 unsigned long now = (unsigned long) time(NULL);
13794 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
13795 return now < val || now - val < 3600;
13796}
13797
13798/*
13799 * Authenticate HTTP request against opened passwords file.
13800 * Returns 1 if authenticated, 0 otherwise.
13801 */
13802
13804 const char *domain) {
13805 mg_printf(c,
13806 "HTTP/1.1 401 Unauthorized\r\n"
13807 "WWW-Authenticate: Digest qop=\"auth\", "
13808 "realm=\"%s\", nonce=\"%lu\"\r\n"
13809 "Content-Length: 0\r\n\r\n",
13810 domain, (unsigned long) time(NULL));
13811}
13812
13814{
13815 std::string path;
13816 FILE *fp;
13817 int status = find_file_mg("htpasswd.txt", path, &fp, trace_mg||verbose_mg);
13818
13819 auth->passwd_filename = path;
13820 auth->passwords.clear();
13821
13822 if (status != SUCCESS || fp == NULL) {
13823 cm_msg(MERROR, "mongoose", "mongoose web server cannot find password file \"%s\"", path.c_str());
13824 cm_msg(MERROR, "mongoose", "please create password file: touch %s", path.c_str());
13825 return false;
13826 }
13827
13828 bool have_realm = false;
13829 char buf[256];
13830
13831 /*
13832 * Read passwords file line by line. If should have htdigest format,
13833 * i.e. each line should be a colon-separated sequence:
13834 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
13835 */
13836 while (fgets(buf, sizeof(buf), fp) != NULL) {
13837 char f_user[256];
13838 char f_domain[256];
13839 char f_ha1[256];
13840
13841 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3) {
13842 AuthEntry e;
13843 e.realm = f_domain;
13844 e.username = f_user;
13845 e.password = f_ha1;
13846
13847 if (e.realm == auth->realm) {
13848 have_realm = true;
13849 auth->passwords.push_back(e);
13850 }
13851 }
13852 }
13853
13854 fclose(fp);
13855
13856 return have_realm;
13857}
13858
13859#ifdef HAVE_MONGOOSE6
13860std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13861{
13862 assert(!"this code is untested!");
13863
13864 char* buf = NULL;
13865 int buf_size = 0;
13866
13867 while (1) {
13868 if (buf_size == 0) {
13869 buf_size = 256;
13870 buf = (char*)malloc(buf_size);
13871 assert(buf != NULL);
13872 }
13873
13874 int size = mg_http_parse_header(hdr, var_name, buf, buf_size);
13875
13876 if (size <= 0) {
13877 free(buf);
13878 return "";
13879 }
13880
13881 if (size < buf_size) {
13882 std::string s = buf;
13883 free(buf);
13884 return s;
13885 }
13886
13887 buf_size = buf_size*2 + 16;
13888 buf = (char*)realloc(buf, buf_size);
13889 assert(buf != NULL);
13890 }
13891}
13892#endif
13893
13894#ifdef HAVE_MONGOOSE616
13895std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13896{
13897 char* buf = NULL;
13898 int buf_size = 0;
13899 int size = mg_http_parse_header2(hdr, var_name, &buf, buf_size);
13900 if (size <= 0)
13901 return "";
13902 assert(buf != NULL);
13903 std::string s = buf;
13904 free(buf);
13905 return s;
13906}
13907#endif
13908
13909static std::string check_digest_auth(struct http_message *hm, Auth* auth)
13910{
13911 char expected_response[33];
13912
13913 //printf("HereA!\n");
13914
13915 /* Parse "Authorization:" header, fail fast on parse error */
13916 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
13917
13918 if (!hdr)
13919 return "";
13920
13921 //printf("HereB!\n");
13922
13923 std::string user = find_var_mg(hdr, "username");
13924 std::string cnonce = find_var_mg(hdr, "cnonce");
13925 std::string response = find_var_mg(hdr, "response");
13926 std::string uri = find_var_mg(hdr, "uri");
13927 std::string qop = find_var_mg(hdr, "qop");
13928 std::string nc = find_var_mg(hdr, "nc");
13929 std::string nonce = find_var_mg(hdr, "nonce");
13930
13931 if (user.length()<1) return "";
13932 if (cnonce.length()<1) return "";
13933 if (response.length()<1) return "";
13934 if (uri.length()<1) return "";
13935 if (qop.length()<1) return "";
13936 if (nc.length()<1) return "";
13937 if (nonce.length()<1) return "";
13938
13939 if (xmg_check_nonce(nonce.c_str()) == 0) return "";
13940 //printf("HereB8!\n");
13941
13942 //printf("HereC!\n");
13943
13944 const char* uri_end = strchr(hm->uri.p, ' ');
13945 if (!uri_end) return "";
13946
13947 size_t uri_length = uri_end - hm->uri.p;
13948
13949 if (uri_length != uri.length())
13950 return "";
13951
13952 int cmp = strncmp(hm->uri.p, uri.c_str(), uri_length);
13953
13954 //printf("check URI: message %d %d [%d] authorization [%s]\n", (int)hm->uri.len, uri_length, cmp, uri);
13955
13956 if (cmp != 0)
13957 return "";
13958
13959 for (unsigned i=0; i<auth->passwords.size(); i++) {
13960 AuthEntry* e = &auth->passwords[i];
13961 if (e->username != user)
13962 continue;
13963 if (e->realm != auth->realm)
13964 continue;
13965 const char* f_ha1 = e->password.c_str();
13966 int uri_len = hm->uri.len;
13967 if (hm->uri.p[uri_len] == '?')
13968 uri_len += hm->query_string.len + 1; // "+1" accounts for the "?" character
13969 xmg_mkmd5resp(hm->method.p, hm->method.len,
13970 hm->uri.p, uri_len,
13971 f_ha1, strlen(f_ha1),
13972 nonce.c_str(), nonce.length(),
13973 nc.c_str(), nc.length(),
13974 cnonce.c_str(), cnonce.length(),
13975 qop.c_str(), qop.length(),
13977 int cmp = strcasecmp(response.c_str(), expected_response);
13978 //printf("digest_auth: expected %s, got %s, cmp %d\n", expected_response, response.c_str(), cmp);
13979 if (cmp == 0) {
13980 return e->username;
13981 }
13982 }
13983
13984 return "";
13985}
13986
13987#ifdef HAVE_MONGOOSE616
13988
13989struct HostlistCacheEntry
13990{
13991 time_t time_created = 0;
13993 int count_used = 0;
13994 bool ipv4 = false;
13995 bool ipv6 = false;
13996 uint32_t ipv4addr = 0;
13997 struct in6_addr ipv6addr;
13998 std::string hostname;
13999 int gai_status = 0;
14000 std::string gai_strerror;
14001 bool ok = false;
14002};
14003
14004static std::vector<HostlistCacheEntry*> gHostlistCache;
14005
14006static void print_hostlist_cache()
14007{
14008 time_t now = time(NULL);
14009
14010 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14012 if (!e) {
14013 // empty slot
14014 continue;
14015 }
14016
14017 printf("%3d: %s \"%s\", ok %d, count_used %d, age created: %d, last_used %d",
14018 i,
14019 e->ipv4?"IPv4":(e->ipv6?"IPv6":"????"),
14020 e->hostname.c_str(),
14021 e->ok,
14022 e->count_used,
14023 (int)(now - e->time_created),
14024 (int)(now - e->time_last_used));
14025
14026 if (e->gai_status) {
14027 printf(", getnameinfo() status %d (%s)", e->gai_status, e->gai_strerror.c_str());
14028 }
14029
14030 printf("\n");
14031 }
14032}
14033
14034static bool mongoose_check_hostlist(const union socket_address *sa)
14035{
14036 time_t now = time(NULL);
14037 bool ipv4 = false;
14038 bool ipv6 = false;
14039 uint32_t ipv4addr = 0;
14040 struct in6_addr ipv6addr;
14041
14042 if (sa->sa.sa_family == AF_INET) {
14043 ipv4 = true;
14044 ipv4addr = sa->sin.sin_addr.s_addr;
14045 } else if (sa->sa.sa_family == AF_INET6) {
14046 ipv6 = true;
14047 memcpy(&ipv6addr, &sa->sin6.sin6_addr, sizeof(ipv6addr));
14048 } else {
14049 printf("Rejecting connection from unknown address family %d (AF_xxx)\n", sa->sa.sa_family);
14050 return false;
14051 }
14052
14053 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14055 if (!e) {
14056 // empty slot
14057 continue;
14058 }
14059
14060 if ((ipv4 == e->ipv4) && (ipv4addr == e->ipv4addr)) {
14061 // IPv4 address match
14062 e->time_last_used = now;
14063 e->count_used++;
14064 return e->ok;
14065 }
14066
14067 if ((ipv6 == e->ipv6) && (memcmp(&ipv6addr, &e->ipv6addr, sizeof(ipv6addr)) == 0)) {
14068 // IPv6 address match
14069 e->time_last_used = now;
14070 e->count_used++;
14071 return e->ok;
14072 }
14073
14074 // not this one. maybe expire old entries?
14075
14076 if (e->time_last_used < now - 24*60*60) {
14077 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);
14079 delete e;
14080 }
14081 }
14082
14083 // not found in cache
14084
14085 assert(ipv4 || ipv6);
14086
14088
14089 bool found = false;
14090 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14091 if (gHostlistCache[i] == NULL) {
14092 gHostlistCache[i] = e;
14093 found = true;
14094 }
14095 }
14096 if (!found) {
14097 gHostlistCache.push_back(e);
14098 }
14099
14100 e->time_created = now;
14101 e->time_last_used = now;
14102 e->count_used = 1;
14103 e->ipv4 = ipv4;
14104 e->ipv6 = ipv6;
14105 if (ipv4)
14106 e->ipv4addr = ipv4addr;
14107 if (ipv6)
14108 memcpy(&e->ipv6addr, &ipv6addr, sizeof(ipv6addr));
14109 e->ok = false;
14110
14111 char hname[NI_MAXHOST];
14112 hname[0] = 0;
14113
14114 e->gai_status = getnameinfo(&sa->sa, sizeof(*sa), hname, sizeof(hname), NULL, 0, 0);
14115
14116 if (e->gai_status) {
14117 e->gai_strerror = gai_strerror(e->gai_status);
14118
14119 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, e->gai_status, e->gai_strerror.c_str());
14120
14121 e->ok = false;
14122 return e->ok;
14123 }
14124
14125 printf("connection from \"%s\"\n", hname);
14126
14127 e->hostname = hname;
14128
14129 /* always permit localhost */
14130 if (e->hostname == "localhost.localdomain")
14131 e->ok = true;
14132 else if (e->hostname == "localhost")
14133 e->ok = true;
14134 else {
14135 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++) {
14136 if (e->hostname == gAllowedHosts[i]) {
14137 e->ok = true;
14138 }
14139 }
14140 }
14141
14142 if (!e->ok) {
14143 printf("Rejecting connection from \'%s\'\n", hname);
14144 }
14145
14147
14148 return e->ok;
14149}
14150
14151#endif
14152
14153static std::string mgstr(const mg_str* s)
14154{
14155 return std::string(s->p, s->len);
14156}
14157
14158static const std::string find_header_mg(const struct http_message *msg, const char* name)
14159{
14160 size_t nlen = strlen(name);
14161 for (int i=0; i<MG_MAX_HTTP_HEADERS; i++) {
14162 if (msg->header_names[i].len != nlen)
14163 continue;
14164 if (strncmp(msg->header_names[i].p, name, nlen) != 0)
14165 continue;
14166 return mgstr(&msg->header_values[i]);
14167 }
14168 return "";
14169}
14170
14171static const std::string find_cookie_mg(const struct http_message *msg, const char* cookie_name)
14172{
14173 const std::string cookies = find_header_mg(msg, "Cookie");
14174 if (cookies.length() < 1)
14175 return "";
14176 const char* p = strstr(cookies.c_str(), cookie_name);
14177 if (!p)
14178 return "";
14179 const char* v = p+strlen(cookie_name);
14180 if (*v != '=')
14181 return "";
14182 v++;
14183 //printf("cookie [%s] value [%s]\n", cookie_name, v);
14184 return v;
14185}
14186
14187// Generic event handler
14188
14189static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
14190{
14191 struct mbuf *io = &nc->recv_mbuf;
14192 switch (ev) {
14193 case MG_EV_POLL: // periodic call from loop_mg() via mg_mgr_poll()
14194 break;
14195 case MG_EV_ACCEPT:
14196 if (trace_mg)
14197 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> accept\n", nc, ev, ev_data);
14198 break;
14199 case MG_EV_RECV:
14200 if (trace_mg)
14201 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> recv %d, buffered %d bytes\n", nc, ev, ev_data, *(int*)ev_data, (int)io->len);
14202#if 0
14203 // This event handler implements simple TCP echo server
14204 mg_send(nc, io->buf, io->len); // Echo received data back
14205 mbuf_remove(io, io->len); // Discard data from recv buffer
14206#endif
14207 break;
14208 case MG_EV_SEND:
14209 if (trace_mg)
14210 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> send %d bytes\n", nc, ev, ev_data, *(int*)ev_data);
14211 break;
14212 case MG_EV_CLOSE:
14213 if (trace_mg)
14214 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> close\n", nc, ev, ev_data);
14215 break;
14216 default:
14217 if (trace_mg)
14218 printf("handle_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
14219 break;
14220 }
14221}
14222
14224{
14225 // extract password cookies
14226
14227 char cookie_pwd[256]; // general access password
14228 char cookie_wpwd[256]; // "write mode" password
14229 char cookie_cpwd[256]; // custom page and javascript password
14230
14231 cookie_pwd[0] = 0;
14232 cookie_wpwd[0] = 0;
14233 cookie_cpwd[0] = 0;
14234
14235 std::string s = find_cookie_mg(msg, "midas_pwd");
14236 if (s.length() > 0) {
14237 mstrlcpy(cookie_pwd, s.c_str(), sizeof(cookie_pwd));
14238 cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
14239 }
14240
14241 s = find_cookie_mg(msg, "midas_wpwd");
14242 if (s.length()) {
14243 mstrlcpy(cookie_wpwd, s.c_str(), sizeof(cookie_pwd));
14244 cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
14245 }
14246
14247 s = find_cookie_mg(msg, "cpwd");
14248 if (s.length()) {
14249 mstrlcpy(cookie_cpwd, s.c_str(), sizeof(cookie_pwd));
14250 cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
14251 }
14252
14253 // extract refresh rate
14254 c->refresh = DEFAULT_REFRESH;
14255 s = find_cookie_mg(msg, "midas_refr");
14256 if (s.length() > 0)
14257 c->refresh = atoi(s.c_str());
14258
14259 // extract equipment expand flag
14260 //c->expand_equipment = 0;
14261 //s = find_cookie_mg(msg, "midas_expeq");
14262 //if (s.length() > 0)
14263 // c->expand_equipment = atoi(s.c_str());
14264
14265 c->cookie_pwd = cookie_pwd;
14266 c->cookie_wpwd = cookie_wpwd;
14267 c->cookie_cpwd = cookie_cpwd;
14268}
14269
14270#define RESPONSE_SENT 1
14271#define RESPONSE_QUEUED 2
14272#define RESPONSE_501 3
14273
14274static int handle_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14275{
14277
14278 decode_cookies(&cookies, msg);
14279
14280 // lock shared structures
14281
14282#ifdef HAVE_MONGOOSE6
14284 assert(status == SS_SUCCESS);
14285#endif
14286
14287 //t->fTimeLocked = GetTimeSec();
14288
14289 // prepare return buffer
14290
14291 Return *rr = new Return();
14292
14293 rr->zero();
14294
14295 // call midas
14296
14297 decode_get(rr, NULL, &cookies, uri, query_string, t);
14298
14299 if (trace_mg)
14300 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14301
14303
14304 if (rr->return_length == -1) {
14305 delete rr;
14306#ifdef HAVE_MONGOOSE6
14307 //t->fTimeUnlocked = GetTimeSec();
14309#endif
14310 return RESPONSE_501;
14311 }
14312
14313 if (rr->return_length == 0)
14314 rr->return_length = strlen(rr->return_buffer);
14315
14316 //t->fTimeUnlocked = GetTimeSec();
14317
14318#ifdef HAVE_MONGOOSE6
14320#endif
14321
14322 mg_send(nc, rr->return_buffer, rr->return_length);
14323
14324 if (!strstr(rr->return_buffer, "Content-Length")) {
14325 // cannot do pipelined http if response generated by mhttpd
14326 // decode_get() has no Content-Length header.
14327 // must close the connection.
14329 }
14330
14331 t->fTimeSent = GetTimeSec();
14332
14333 delete rr;
14334
14335 return RESPONSE_SENT;
14336}
14337
14338#ifdef HAVE_MONGOOSE616
14339
14340static uint32_t s_ncseqno = 1;
14341
14342struct MongooseNcUserData
14343{
14344 uint32_t ncseqno = 0;
14345
14346 MongooseNcUserData() // ctor
14347 {
14348 ncseqno = s_ncseqno++;
14349 //printf("MongooseNcUserData::ctor! ncseqno %d\n", ncseqno);
14350 }
14351
14352 ~MongooseNcUserData() // ctor
14353 {
14354 //printf("MongooseNcUserData::dtor! ncseqno %d\n", ncseqno);
14355 }
14356};
14357
14358static uint32_t GetNcSeqno(const mg_connection* nc)
14359{
14360 if (nc == NULL)
14361 return 0;
14362 if (nc->user_data == NULL)
14363 return 0;
14365 return ncud->ncseqno;
14366}
14367
14368static uint32_t s_wseqno = 1;
14369
14370struct MongooseWorkObject
14371{
14372 uint32_t wseqno = 0;
14373 mg_connection* nc = NULL;
14374 uint32_t wncseqno = 0;
14375 bool http_get = false;
14376 bool http_post = false;
14377 bool mjsonrpc = false;
14379 std::string origin;
14380 std::string uri;
14381 std::string query_string;
14382 std::string post_body;
14383 std::string post_boundary;
14384 RequestTrace* t = NULL;
14385 bool send_done = false;
14386
14388 {
14389 wseqno = s_wseqno++;
14390 nc = xnc;
14391 wncseqno = GetNcSeqno(nc);
14392
14393 //printf("MongooseWorkObject::ctor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14394 }
14395
14396 ~MongooseWorkObject() // dtor
14397 {
14398 //printf("MongooseWorkObject::dtor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14399
14400 // poison pointers
14401 nc = NULL;
14402 t = NULL;
14403 }
14404};
14405
14407{
14408 std::atomic_bool fIsRunning{false};
14409 std::thread* fThread = NULL; // thread
14410 void* fNc = NULL; // thread is attached to this network connection
14411 std::mutex fMutex;
14412 std::deque<MongooseWorkObject*> fQueue;
14413 std::condition_variable fNotify;
14414
14415 //MongooseThreadObject() // ctor
14416 //{
14417 // printf("MongooseThreadObject %p created!\n", this);
14418 //}
14419
14420 //~MongooseThreadObject() // dtor
14421 //{
14422 // printf("MongooseThreadObject %p destroyed!\n", this);
14423 //}
14424};
14425
14426static std::vector<MongooseThreadObject*> gMongooseThreads;
14427
14429
14431{
14432 //printf("FindThread: nc %p, thread %s\n", nc, ss_tid_to_string(ss_gettid()).c_str());
14433
14435
14436 for (auto it : gMongooseThreads) {
14438 if (to->fNc == nc) {
14439 //printf("to %p, nc %p: found thread\n", to, nc);
14440 return to;
14441 }
14442 if (to->fNc == NULL) {
14444 }
14445 }
14446
14447 if (last_not_connected) {
14449 to->fNc = nc;
14450 //printf("to %p, nc %p: reusing thread\n", to, nc);
14451 return to;
14452 }
14453
14455
14456 to->fNc = nc;
14457
14458 //printf("to %p, nc %p: new thread\n", to, nc);
14459
14460 gMongooseThreads.push_back(to);
14461
14462 printf("Mongoose web server is using %d threads \r", (int)gMongooseThreads.size());
14463 fflush(stdout);
14464
14465 to->fThread = new std::thread(mongoose_thread, to);
14466
14467 return to;
14468}
14469
14470void FreeThread(void* nc)
14471{
14472 //printf("FreeThread, nc %p\n", nc);
14473
14474 for (auto it : gMongooseThreads) {
14476 if (to->fNc == nc) {
14477 //printf("to %p, nc %p: connection closed\n", to, nc);
14478 to->fNc = NULL;
14479 return;
14480 }
14481 }
14482
14483 //printf("to %p, nc %p: connection closed, but no thread\n", nullptr, nc);
14484}
14485
14487{
14488 w->nc = nc;
14490 assert(to->fNc == nc);
14491 to->fMutex.lock();
14492 to->fQueue.push_back(w);
14493 to->fMutex.unlock();
14494 to->fNotify.notify_one();
14495}
14496
14497static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag = false);
14498
14499static int queue_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14500{
14502 w->http_get = true;
14503 decode_cookies(&w->cookies, msg);
14504 w->uri = uri;
14505 w->query_string = query_string;
14506 w->t = t;
14507
14508 mongoose_queue(nc, w);
14509
14510 return RESPONSE_QUEUED;
14511}
14512
14513static int queue_decode_post(struct mg_connection *nc, const http_message* msg, const char* boundary, const char* uri, const char* query_string, RequestTrace* t)
14514{
14516 w->http_post = true;
14517 decode_cookies(&w->cookies, msg);
14518 w->uri = uri;
14519 w->query_string = query_string;
14520 w->post_body = mgstr(&msg->body);
14521 w->post_boundary = boundary;
14522 w->t = t;
14523
14524 mongoose_queue(nc, w);
14525
14526 return RESPONSE_QUEUED;
14527}
14528
14529static int queue_mjsonrpc(struct mg_connection *nc, const std::string& origin, const std::string& post_body, RequestTrace* t)
14530{
14532 w->mjsonrpc = true;
14533 w->origin = origin;
14534 w->post_body = post_body;
14535 w->t = t;
14536
14537 mongoose_queue(nc, w);
14538
14539 return RESPONSE_QUEUED;
14540}
14541
14543{
14544 // lock shared structures
14545
14546 //int status = ss_mutex_wait_for(request_mutex, 0);
14547 //assert(status == SS_SUCCESS);
14548
14549 //w->t->fTimeLocked = GetTimeSec();
14550
14551 // prepare return buffer
14552
14553 Return *rr = new Return();
14554
14555 rr->zero();
14556
14557 // call midas
14558
14559 decode_get(rr, NULL, &w->cookies, w->uri.c_str(), w->query_string.c_str(), w->t);
14560
14561 if (trace_mg)
14562 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14563
14564 w->t->fTimeProcessed = GetTimeSec();
14565
14566 if (rr->return_length == -1) {
14567 delete rr;
14568 //w->t->fTimeUnlocked = GetTimeSec();
14569 //ss_mutex_release(request_mutex);
14570 return RESPONSE_501;
14571 }
14572
14573 if (rr->return_length == 0)
14574 rr->return_length = strlen(rr->return_buffer);
14575
14576 //w->t->fTimeUnlocked = GetTimeSec();
14577
14578 //ss_mutex_release(request_mutex);
14579
14580 bool close_flag = false;
14581
14582 if (!strstr(rr->return_buffer, "Content-Length")) {
14583 // cannot do pipelined http if response generated by mhttpd
14584 // decode_get() has no Content-Length header.
14585 // must close the connection.
14586 close_flag = true;
14587 }
14588
14589 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14590
14591 w->t->fTimeSent = GetTimeSec();
14592
14593 delete rr;
14594
14595 return RESPONSE_SENT;
14596}
14597
14599{
14600 const char* post_data = w->post_body.c_str();
14601 int post_data_len = w->post_body.length();
14602
14603 // lock shared strctures
14604
14605 //int status = ss_mutex_wait_for(request_mutex, 0);
14606 //assert(status == SS_SUCCESS);
14607
14608 // prepare return buffer
14609
14610 Return* rr = new Return;
14611
14612 rr->zero();
14613
14614 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14615
14616 decode_post(rr, NULL, (char*)post_data, w->post_boundary.c_str(), post_data_len, &w->cookies, w->uri.c_str(), w->t);
14617
14618 if (trace_mg)
14619 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14620
14621 if (rr->return_length == -1) {
14622 //ss_mutex_release(request_mutex);
14623 delete rr;
14624 return RESPONSE_501;
14625 }
14626
14627 if (rr->return_length == 0)
14628 rr->return_length = strlen(rr->return_buffer);
14629
14630 //ss_mutex_release(request_mutex);
14631
14632 bool close_flag = false;
14633 if (!strstr(rr->return_buffer, "Content-Length")) {
14634 // cannot do pipelined http if response generated by mhttpd
14635 // decode_get() has no Content-Length header.
14636 // must close the connection.
14637 close_flag = true;
14638 }
14639
14640 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14641
14642 delete rr;
14643
14644 return RESPONSE_SENT;
14645
14646}
14647
14649{
14650 w->t->fRPC = w->post_body;
14651
14652 //int status = ss_mutex_wait_for(request_mutex, 0);
14653 //assert(status == SS_SUCCESS);
14654
14655 //gMutex.lock();
14656 //w->t->fTimeLocked = GetTimeSec();
14657
14658 MJsonNode* reply = mjsonrpc_decode_post_data(w->post_body.c_str());
14659
14660 //w->t->fTimeUnlocked = GetTimeSec();
14661 //gMutex.unlock();
14662
14663 //ss_mutex_release(request_mutex);
14664
14665 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14666 const char* ptr;
14667 size_t size;
14668 reply->GetArrayBuffer(&ptr, &size);
14669
14670 std::string headers;
14671 headers += "HTTP/1.1 200 OK\n";
14672 if (w->origin.length() > 0)
14673 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14674 else
14675 headers += "Access-Control-Allow-Origin: *\n";
14676 headers += "Access-Control-Allow-Credentials: true\n";
14677 headers += "Content-Length: " + toString(size) + "\n";
14678 headers += "Content-Type: application/octet-stream\n";
14679 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14680
14681 //printf("sending headers: %s\n", headers.c_str());
14682 //printf("sending reply: %s\n", reply_string.c_str());
14683
14684 std::string send = headers + "\n";
14685
14686 w->t->fTimeProcessed = GetTimeSec();
14687
14688 mongoose_send(nc, w, send.c_str(), send.length(), ptr, size);
14689
14690 w->t->fTimeSent = GetTimeSec();
14691
14692 delete reply;
14693
14694 return RESPONSE_SENT;
14695 }
14696
14697 std::string reply_string = reply->Stringify();
14698 int reply_length = reply_string.length();
14699
14700 std::string headers;
14701 headers += "HTTP/1.1 200 OK\n";
14702 if (w->origin.length() > 0)
14703 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14704 else
14705 headers += "Access-Control-Allow-Origin: *\n";
14706 headers += "Access-Control-Allow-Credentials: true\n";
14707 headers += "Content-Length: " + toString(reply_length) + "\n";
14708 headers += "Content-Type: application/json\n";
14709 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14710
14711 if (trace_mg_verbose) {
14712 printf("-----------------------\nSending headers: %s", headers.c_str());
14713 std::string r = reply_string.substr(0, 128);
14714 printf("-----------------------\nSending reply (%d bytes): %s\n\n\n", (int)reply_string.size(), r.c_str());
14715 }
14716
14717 std::string send = headers + "\n" + reply_string;
14718
14719 w->t->fTimeProcessed = GetTimeSec();
14720
14721 mongoose_send(nc, w, send.c_str(), send.length(), NULL, 0);
14722
14723 w->t->fTimeSent = GetTimeSec();
14724
14725 delete reply;
14726
14727 return RESPONSE_SENT;
14728}
14729
14731{
14732 if (w->http_get)
14733 return thread_http_get(nc, w);
14734 else if (w->http_post)
14735 return thread_http_post(nc, w);
14736 else if (w->mjsonrpc)
14737 return thread_mjsonrpc(nc, w);
14738 else
14739 return RESPONSE_501;
14740}
14741
14742#endif
14743
14744static int handle_decode_post(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14745{
14746
14747 char boundary[256];
14748 boundary[0] = 0;
14749 const std::string ct = find_header_mg(msg, "Content-Type");
14750 if (ct.length() > 0) {
14751 const char* s = strstr(ct.c_str(), "boundary=");
14752 if (s)
14753 mstrlcpy(boundary, s+9, sizeof(boundary));
14754 }
14755
14756#ifdef HAVE_MONGOOSE616
14757 if (multithread_mg)
14758 return queue_decode_post(nc, msg, boundary, uri, query_string, t);
14759#endif
14760
14762
14763 decode_cookies(&cookies, msg);
14764
14765 const char* post_data = msg->body.p;
14766 int post_data_len = msg->body.len;
14767
14768 // lock shared strctures
14769
14770#ifdef HAVE_MONGOOSE6
14772 assert(status == SS_SUCCESS);
14773#endif
14774
14775 // prepare return buffer
14776
14777 Return* rr = new Return;
14778
14779 rr->zero();
14780
14781 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14782
14783 decode_post(rr, NULL, (char*)post_data, boundary, post_data_len, &cookies, uri, t);
14784
14785 if (trace_mg)
14786 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14787
14788 if (rr->return_length == -1) {
14789#ifdef HAVE_MONGOOSE6
14791#endif
14792 delete rr;
14793 return RESPONSE_501;
14794 }
14795
14796 if (rr->return_length == 0)
14797 rr->return_length = strlen(rr->return_buffer);
14798
14799#ifdef HAVE_MONGOOSE6
14801#endif
14802
14803 mg_send(nc, rr->return_buffer, rr->return_length);
14804
14805 if (!strstr(rr->return_buffer, "Content-Length")) {
14806 // cannot do pipelined http if response generated by mhttpd
14807 // decode_get() has no Content-Length header.
14808 // must close the connection.
14810 }
14811
14812 delete rr;
14813
14814 return RESPONSE_SENT;
14815}
14816
14817static int handle_http_get(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14818{
14819 std::string query_string = mgstr(&msg->query_string);
14820
14821 if (trace_mg||verbose_mg)
14822 printf("handle_http_get: uri [%s], query [%s]\n", uri, query_string.c_str());
14823
14824 if (query_string == "mjsonrpc_schema") {
14825 MJsonNode* s = mjsonrpc_get_schema();
14826 std::string reply = s->Stringify();
14827 delete s;
14828
14829 int reply_length = reply.length();
14830
14831 const std::string origin_header = find_header_mg(msg, "Origin");
14832
14833 std::string headers;
14834 headers += "HTTP/1.1 200 OK\n";
14835 if (origin_header.length() > 0)
14836 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14837 else
14838 headers += "Access-Control-Allow-Origin: *\n";
14839 headers += "Access-Control-Allow-Credentials: true\n";
14840 headers += "Content-Length: " + toString(reply_length) + "\n";
14841 headers += "Content-Type: application/json\n";
14842 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14843
14844 //printf("sending headers: %s\n", headers.c_str());
14845 //printf("sending reply: %s\n", reply.c_str());
14846
14847 std::string send = headers + "\n" + reply;
14848
14850
14851 mg_send(nc, send.c_str(), send.length());
14852
14853 t->fTimeSent = GetTimeSec();
14854
14855 return RESPONSE_SENT;
14856 }
14857
14858 if (query_string == "mjsonrpc_schema_text") {
14859 MJsonNode* s = mjsonrpc_get_schema();
14860 std::string reply = mjsonrpc_schema_to_text(s);
14861 delete s;
14862
14863 int reply_length = reply.length();
14864
14865 const std::string origin_header = find_header_mg(msg, "Origin");
14866
14867 std::string headers;
14868 headers += "HTTP/1.1 200 OK\n";
14869 if (origin_header.length() > 0)
14870 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14871 else
14872 headers += "Access-Control-Allow-Origin: *\n";
14873 headers += "Access-Control-Allow-Credentials: true\n";
14874 headers += "Content-Length: " + toString(reply_length) + "\n";
14875 headers += "Content-Type: text/plain\n";
14876 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14877
14878 //printf("sending headers: %s\n", headers.c_str());
14879 //printf("sending reply: %s\n", reply.c_str());
14880
14881 std::string send = headers + "\n" + reply;
14882
14884
14885 mg_send(nc, send.c_str(), send.length());
14886
14887 t->fTimeSent = GetTimeSec();
14888
14889 return RESPONSE_SENT;
14890 }
14891
14892#ifdef HAVE_MONGOOSE616
14893 if (multithread_mg)
14894 return queue_decode_get(nc, msg, uri, query_string.c_str(), t);
14895#endif
14896
14897 return handle_decode_get(nc, msg, uri, query_string.c_str(), t);
14898}
14899
14900static int handle_http_post(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14901{
14902 std::string query_string = mgstr(&msg->query_string);
14903 std::string post_data = mgstr(&msg->body);
14904
14905 if (trace_mg||verbose_mg)
14906 printf("handle_http_post: uri [%s], query [%s], post data %d bytes\n", uri, query_string.c_str(), (int)post_data.length());
14907 if (trace_mg_verbose)
14908 printf("handle_http_post: post data = \n%s\n", post_data.c_str());
14909
14910 if (query_string.substr(0, 8) == "mjsonrpc") { // ignore any parameter after "mjsonrpc"
14911 const std::string origin_header = find_header_mg(msg, "Origin");
14912 const std::string ctype_header = find_header_mg(msg, "Content-Type");
14913
14914 if (strstr(ctype_header.c_str(), "application/json") == NULL) {
14915 std::string headers;
14916 headers += "HTTP/1.1 415 Unsupported Media Type\n";
14917 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14918
14919 //printf("sending headers: %s\n", headers.c_str());
14920 //printf("sending reply: %s\n", reply.c_str());
14921
14922 if (trace_mg_verbose)
14923 printf("handle_http_post: unsupported media type \"%s\"\n", ctype_header.c_str());
14924
14925 std::string send = headers + "\n";
14926
14928
14929 mg_send(nc, send.c_str(), send.length());
14930
14931 t->fTimeSent = GetTimeSec();
14932
14933 return RESPONSE_SENT;
14934 }
14935
14936#ifdef HAVE_MONGOOSE616
14937 if (multithread_mg)
14938 return queue_mjsonrpc(nc, origin_header, post_data, t);
14939#endif
14940
14941 //printf("post body: %s\n", post_data.c_str());
14942
14943 t->fRPC = post_data;
14944
14945#ifdef HAVE_MONGOOSE6
14947 assert(status == SS_SUCCESS);
14948#endif
14949
14950 //t->fTimeLocked = GetTimeSec();
14951
14952 MJsonNode* reply = mjsonrpc_decode_post_data(post_data.c_str());
14953
14954 //t->fTimeUnlocked = GetTimeSec();
14955
14956#ifdef HAVE_MONGOOSE6
14958#endif
14959
14960 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14961 const char* ptr;
14962 size_t size;
14963 reply->GetArrayBuffer(&ptr, &size);
14964
14965 std::string headers;
14966 headers += "HTTP/1.1 200 OK\n";
14967 if (origin_header.length() > 0)
14968 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14969 else
14970 headers += "Access-Control-Allow-Origin: *\n";
14971 headers += "Access-Control-Allow-Credentials: true\n";
14972 headers += "Content-Length: " + toString(size) + "\n";
14973 headers += "Content-Type: application/octet-stream\n";
14974 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14975
14976 //printf("sending headers: %s\n", headers.c_str());
14977 //printf("sending reply: %s\n", reply_string.c_str());
14978
14979 std::string send = headers + "\n";
14980
14982
14983 mg_send(nc, send.c_str(), send.length());
14984 mg_send(nc, ptr, size);
14985
14986 t->fTimeSent = GetTimeSec();
14987
14988 delete reply;
14989
14990 return RESPONSE_SENT;
14991 }
14992
14993 std::string reply_string = reply->Stringify();
14994 int reply_length = reply_string.length();
14995
14996 std::string headers;
14997 headers += "HTTP/1.1 200 OK\n";
14998 if (origin_header.length() > 0)
14999 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
15000 else
15001 headers += "Access-Control-Allow-Origin: *\n";
15002 headers += "Access-Control-Allow-Credentials: true\n";
15003 headers += "Content-Length: " + toString(reply_length) + "\n";
15004 headers += "Content-Type: application/json\n";
15005 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15006
15007 //printf("sending headers: %s\n", headers.c_str());
15008 //printf("sending reply: %s\n", reply_string.c_str());
15009
15010 std::string send = headers + "\n" + reply_string;
15011
15013
15014 mg_send(nc, send.c_str(), send.length());
15015
15016 t->fTimeSent = GetTimeSec();
15017
15018 delete reply;
15019
15020 return RESPONSE_SENT;
15021 }
15022
15023 return handle_decode_post(nc, msg, uri, query_string.c_str(), t);
15024}
15025
15027{
15028 //
15029 // JSON-RPC CORS pre-flight request, see
15030 // https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
15031 //
15032 // OPTIONS /resources/post-here/ HTTP/1.1
15033 // Host: bar.other
15034 // User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
15035 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
15036 // Accept-Language: en-us,en;q=0.5
15037 // Accept-Encoding: gzip,deflate
15038 // Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
15039 // Connection: keep-alive
15040 // Origin: http://foo.example
15041 // Access-Control-Request-Method: POST
15042 // Access-Control-Request-Headers: X-PINGOTHER
15043 //
15044 // HTTP/1.1 200 OK
15045 // Date: Mon, 01 Dec 2008 01:15:39 GMT
15046 // Server: Apache/2.0.61 (Unix)
15047 // Access-Control-Allow-Origin: http://foo.example
15048 // Access-Control-Allow-Methods: POST, GET, OPTIONS
15049 // Access-Control-Allow-Headers: X-PINGOTHER
15050 // Access-Control-Max-Age: 1728000
15051 // Vary: Accept-Encoding, Origin
15052 // Content-Encoding: gzip
15053 // Content-Length: 0
15054 // Keep-Alive: timeout=2, max=100
15055 // Connection: Keep-Alive
15056 // Content-Type: text/plain
15057 //
15058
15059 const std::string origin_header = find_header_mg(msg, "Origin");
15060
15061 if (trace_mg||verbose_mg)
15062 printf("handle_http_options_cors: origin [%s]\n", origin_header.c_str());
15063
15064 std::string headers;
15065 headers += "HTTP/1.1 200 OK\n";
15066 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15067 if (origin_header.length() > 0)
15068 headers += "Access-Control-Allow-Origin: " + origin_header + "\n";
15069 else
15070 headers += "Access-Control-Allow-Origin: *\n";
15071 headers += "Access-Control-Allow-Headers: Content-Type\n";
15072 headers += "Access-Control-Allow-Credentials: true\n";
15073 headers += "Access-Control-Max-Age: 120\n";
15074 headers += "Content-Length: 0\n";
15075 headers += "Content-Type: text/plain\n";
15076 //printf("sending headers: %s\n", headers.c_str());
15077 //printf("sending reply: %s\n", reply.c_str());
15078
15079 std::string send = headers + "\n";
15080
15082
15083 mg_send(nc, send.c_str(), send.length());
15084
15085 t->fTimeSent = GetTimeSec();
15086}
15087
15088// HTTP event handler
15089
15090static bool mongoose_passwords_enabled(const struct mg_connection *nc);
15091
15092#ifdef HAVE_MONGOOSE616
15093static MVOdb* gProxyOdb = NULL;
15094#endif
15095
15097{
15098 std::string method = mgstr(&msg->method);
15099 std::string query_string = mgstr(&msg->query_string);
15100 std::string uri_encoded = mgstr(&msg->uri);
15101 std::string uri = UrlDecode(uri_encoded.c_str());
15102
15103 if (trace_mg)
15104 printf("handle_http_message: method [%s] uri [%s] proto [%s]\n", method.c_str(), uri.c_str(), mgstr(&msg->proto).c_str());
15105
15106 RequestTrace* t = new RequestTrace;
15108 t->fMethod = method;
15109 t->fUri = uri;
15110 t->fQuery = query_string;
15111
15112 // process OPTIONS for Cross-origin (CORS) preflight request
15113 // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
15114 if (method == "OPTIONS" && query_string == "mjsonrpc" && mg_get_http_header(msg, "Access-Control-Request-Method") != NULL) {
15115 handle_http_options_cors(nc, msg, t);
15116 t->fCompleted = true;
15118 return;
15119 }
15120
15122 std::string username = check_digest_auth(msg, gAuthMg);
15123
15124 // Cannot re-read the password file - it is not thread safe to do so
15125 // unless I lock gAuthMg for each call check_digest_auth() and if I do so,
15126 // I will serialize (single-thread) all the http requests and defeat
15127 // the whole point of multithreading the web server. K.O.
15128 //
15130 //if (username.length() < 1) {
15131 // bool ok = read_passwords(&gAuthMg);
15132 // if (ok)
15133 // username = check_digest_auth(msg, &gAuthMg);
15134 //}
15135
15136 if (trace_mg)
15137 printf("handle_http_message: auth user: \"%s\"\n", username.c_str());
15138
15139 if (username.length() == 0) {
15140 if (trace_mg||verbose_mg)
15141 printf("handle_http_message: method [%s] uri [%s] query [%s] proto [%s], sending auth request for realm \"%s\"\n", method.c_str(), uri.c_str(), query_string.c_str(), mgstr(&msg->proto).c_str(), gAuthMg->realm.c_str());
15142
15144 t->fCompleted = true;
15146 return;
15147 }
15148 t->fAuthOk = true;
15149 } else {
15150 t->fAuthOk = true;
15151 }
15152
15153#ifdef HAVE_MONGOOSE616
15154 if (gProxyOdb && starts_with(uri, "/proxy/")) {
15155 std::string::size_type p1 = uri.find("/", 1);
15156 if (p1 == uri.length()-1) {
15157 std::string response = "404 Not Found (Proxy name is missing)";
15158 mg_send_head(nc, 404, response.length(), NULL);
15159 mg_send(nc, response.c_str(), response.length());
15160 delete t;
15161 return;
15162 }
15163 std::string::size_type p2 = uri.find("/", p1+1);
15164 if (p2 == std::string::npos) {
15165 std::string response = "404 Not Found (Proxy URL should end with a slash)";
15166 mg_send_head(nc, 404, response.length(), NULL);
15167 mg_send(nc, response.c_str(), response.length());
15168 delete t;
15169 return;
15170 }
15171 std::string p = uri.substr(p1+1, p2-p1-1);
15172 //printf("uri [%s], p1: %d, p2: %d, substr: [%s]\n", uri.c_str(), (int)p1, (int)p2, p.c_str());
15173 if (p.length() < 1) {
15174 std::string response = "404 Not Found (Double-slash or Proxy name is too short)";
15175 mg_send_head(nc, 404, response.length(), NULL);
15176 mg_send(nc, response.c_str(), response.length());
15177 delete t;
15178 return;
15179 }
15180 std::string destination;
15181 gProxyOdb->RS(p.c_str(), &destination);
15182 if (destination.length() < 1) {
15183 std::string response = "404 Not Found (Proxy not found in ODB)";
15184 mg_send_head(nc, 404, response.length(), NULL);
15185 mg_send(nc, response.c_str(), response.length());
15186 delete t;
15187 return;
15188 } else if (destination[0] == '#') {
15189 std::string response = "404 Not Found (Proxy commented-out in ODB)";
15190 mg_send_head(nc, 404, response.length(), NULL);
15191 mg_send(nc, response.c_str(), response.length());
15192 delete t;
15193 return;
15194 } else if (ends_with_char(destination, '/')) {
15195 std::string response = "404 Not Found (Proxy address should not end with a slash)";
15196 mg_send_head(nc, 404, response.length(), NULL);
15197 mg_send(nc, response.c_str(), response.length());
15198 delete t;
15199 return;
15200 } else if (!starts_with(destination, "http")) {
15201 std::string response = "404 Not Found (Proxy address does not start with http";
15202 mg_send_head(nc, 404, response.length(), NULL);
15203 mg_send(nc, response.c_str(), response.length());
15204 delete t;
15205 return;
15206 } else {
15207 std::string m;
15208 m += "/proxy";
15209 m += "/";
15210 m += p;
15211 mg_str mount = mg_mk_str(m.c_str());
15213 if (verbose_mg||trace_mg) {
15214 printf("proxy: uri [%s] mount [%s] upstream [%s]\n", uri.c_str(), mgstr(&mount).c_str(), mgstr(&upstream).c_str());
15215 }
15217 delete t;
15218 return;
15219 }
15220 }
15221#endif
15222
15223 int response = RESPONSE_501;
15224
15225 if (method == "GET")
15226 response = handle_http_get(nc, msg, uri.c_str(), t);
15227 else if (method == "POST")
15228 response = handle_http_post(nc, msg, uri.c_str(), t);
15229
15230 if (response == RESPONSE_501) {
15231 if (trace_mg||verbose_mg)
15232 printf("handle_http_message: sending 501 Not Implemented error\n");
15233
15234 std::string response = "501 Not Implemented";
15235 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15236 mg_send(nc, response.c_str(), response.length());
15237 }
15238
15239 if (response != RESPONSE_QUEUED) {
15240 t->fCompleted = true;
15242 }
15243}
15244
15245#ifdef HAVE_MONGOOSE6
15246
15247static void handle_http_event_mg(struct mg_connection *nc, int ev, void *ev_data)
15248{
15249 switch (ev) {
15250 case MG_EV_HTTP_REQUEST:
15251 if (trace_mg)
15252 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15254 break;
15255 default:
15256 if (trace_mg)
15257 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15258 break;
15259 }
15260}
15261
15262static void handle_http_redirect(struct mg_connection *nc, int ev, void *ev_data)
15263{
15264 switch (ev) {
15265 case MG_EV_HTTP_REQUEST:
15266 {
15268 if (trace_mg)
15269 printf("handle_http_redirect: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15270
15271 mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: https://%s%s\r\n\r\n",
15272 ((std::string*)(nc->user_data))->c_str(),
15273 mgstr(&msg->uri).c_str());
15275 }
15276 break;
15277 default:
15278 if (trace_mg)
15279 printf("handle_http_redirect: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15280 }
15281}
15282
15283#endif
15284
15285#ifdef HAVE_MONGOOSE616
15286
15287// from mongoose examples/multithreaded/multithreaded.c
15288
15289//static sock_t s_sock[2];
15290static std::atomic_bool s_shutdown{false};
15291static struct mg_mgr s_mgr;
15292static std::atomic_int s_rseqno{1};
15293static std::mutex s_mg_broadcast_mutex;
15294
15295#if 0
15296// This info is passed to the worker thread
15297struct work_request {
15298 void* nc;
15300};
15301#endif
15302
15303// This info is passed by the worker thread to mg_broadcast
15304struct work_result {
15305 mg_connection* nc = NULL;
15306 uint32_t check = 0x12345678;
15307 int rseqno = 0;
15309 const char* p1 = NULL;
15310 size_t s1 = 0;
15311 const char* p2 = NULL;
15312 size_t s2 = 0;
15313 bool close_flag = false;
15314 bool send_501 = false;
15315};
15316
15317#if 0
15318static void mongoose_queue(void *nc, MongooseWorkObject *w)
15319{
15320 struct work_request req = {nc, w};
15321
15322 //printf("nc: %p: wseqno: %d, queue work object!\n", nc, w->wseqno);
15323
15324 if (write(s_sock[0], &req, sizeof(req)) < 0) {
15325 fprintf(stderr, "mongoose_queue: Error: write(s_sock(0)) error %d (%s)\n", errno, strerror(errno));
15326 abort();
15327 }
15328}
15329#endif
15330
15331static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data)
15332{
15333 (void) ev;
15334 struct work_result *res = (struct work_result *)ev_data;
15335
15336 assert(res != NULL);
15337 assert(res->w != NULL);
15338
15339 //printf("nc: %p, ncseqno: %d, wseqno: %d, rseqno: %d, check 0x%08x, offered nc %p ncseqno %d, flags 0x%08x\n", res->nc, GetNcSeqno(res->nc), res->w->wseqno, res->rseqno, res->check, nc, GetNcSeqno(nc), (int)nc->flags);
15340
15341 // check for correct connection, note that nc objects are reused and after a socket is closed
15342 // and a new one is opened, the same nc address and the same nc->sock can now refer to a completely
15343 // different tcp connection. So we check ncseqno instead of nc. K.O.
15344
15345 //if (res->nc != nc)
15346 //return;
15347
15348 if (GetNcSeqno(nc) != res->w->wncseqno)
15349 return;
15350
15351 //printf("nc: %p, ncseqno: %d, wseqno: %d, wncseqno %d, on_work_complete: rseqno: %d, send_501: %d, s1 %d, s2: %d, close_flag: %d\n", res->nc, GetNcSeqno(nc), res->w->wseqno, res->w->wncseqno, res->rseqno, res->send_501, (int)res->s1, (int)res->s2, res->close_flag);
15352
15353 if (res->send_501) {
15354 std::string response = "501 Not Implemented";
15355 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15356 mg_send(nc, response.c_str(), response.length());
15357 }
15358
15359 if (res->s1 > 0)
15360 mg_send(nc, res->p1, res->s1);
15361
15362 if (res->s2 > 0)
15363 mg_send(nc, res->p2, res->s2);
15364
15365 if (res->close_flag) {
15366 // cannot do pipelined http if response generated by mhttpd
15367 // decode_get() has no Content-Length header.
15368 // must close the connection.
15370 }
15371
15372 res->w->send_done = true;
15373}
15374
15375static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag)
15376{
15377 //printf("nc: %p: send %d and %d\n", nc, (int)s1, (int)s2);
15378 struct work_result res;
15379 res.nc = nc;
15380 res.w = w;
15381 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15382 res.p1 = p1;
15383 res.s1 = s1;
15384 res.p2 = p2;
15385 res.s2 = s2;
15386 res.close_flag = close_flag;
15387 res.send_501 = false;
15388 //printf("nc: %p: call mg_broadcast()\n", nc);
15389
15390 // NB: mg_broadcast() is advertised as thread-safe, but it is not.
15391 //
15392 // in mongoose 6.16, mg_brodacast() and mg_mgr_handle_ctl_sock() have several problems:
15393 //
15394 // a) "wrong thread" read from mgr->ctl[0], defeating the handshake
15395 //
15396 // b) "lost messages". if more than one message is written to mgr->ctl[0], the second message
15397 // will be "eaten" by mg_mgr_handle_ctl_sock() because of mistatch between number of bytes read and written
15398 // in the two functions. mg_mgr_handle_ctl_sock() always reads about 8000 bytes while mg_broadcast()
15399 // writes 8 bytes per message, (per examples/multithreaded/multithreaded.c. mhttpd messages are a bit longer).
15400 // So if multiple messages are present in the msg->ctl[0] pipe, the read call (of about 8000 bytes)
15401 // in mg_mgr_handle_ctl_sock() will return several messages (last message may be truncated)
15402 // but only the first message will be processed by the code. any additional messages are ignored.
15403 //
15404 // Problems (a) and (b) are easy to fix by using a mutex to serialize mg_broadcast().
15405 //
15406 // c) if the mg_broadcast() message contains pointers to the data buffer to be sent out,
15407 // the caller of mg_broadcast() should not free these data buffers until mg_send() is called
15408 // in "on_work_complete()". In theory, the caller of mg_broadcast() could wait until on_work_complete()
15409 // sets a "done" flag. In practice, if the corresponding network connection is closed before
15410 // mg_mgr_handle_ctl_sock() has looped over it, on_work_complete() will never run
15411 // and the "done" flag will never be set. (Of course, network connections are permitted to close
15412 // at any time without warning, but) the firefox browser closes the network connections "a lot"
15413 // especially when user pressed the "page reload" button at the moment when HTTP transations
15414 // are "in flight". (google-chrome tends to permit these "lame duck" transactions to complete and mongoose
15415 // does not see unexpected socket closures, at least not as many).
15416 //
15417 // To fix problem (c) I need to know when mg_mgr_handle_ctl_sock()'s loop over network connections
15418 // has completed (two cases: (a) my on_work_complete() was hopefully called and finished,
15419 // and (b) the "right" network connection was already closed (for whatever reason) and my on_work_complete()
15420 // was never called).
15421 //
15422 // My solution is to change the handshake between mg_broadcast() and mg_mgr_handle_ctl_sock() by sending
15423 // the handshake reply after looping over the network connections instead of after reading the message
15424 // from msg->ctl[1].
15425 //
15426 // This requires a modification to the code in mongoose.c. If this change is lost/undone, nothing will work.
15427 //
15428
15429 s_mg_broadcast_mutex.lock();
15430 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15431 s_mg_broadcast_mutex.unlock();
15432}
15433
15435{
15436 struct work_result res;
15437 res.nc = nc;
15438 res.w = w;
15439 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15440 res.p1 = 0;
15441 res.s1 = 0;
15442 res.p2 = 0;
15443 res.s2 = 0;
15444 res.close_flag = false;
15445 res.send_501 = true;
15446 //printf("nc: %p, call mg_broadcast()\n", nc);
15447
15448 s_mg_broadcast_mutex.lock();
15449 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15450 s_mg_broadcast_mutex.unlock();
15451}
15452
15453#if 0
15454void *worker_thread_proc(void *param)
15455{
15456 //struct mg_mgr *mgr = (struct mg_mgr *) param;
15457 struct work_request req = {0};
15458
15459 while ((! _abort) && (! s_shutdown)) {
15460 int rd = read(s_sock[1], &req, sizeof(req));
15461 if (rd == 0) {
15462 // socket closed, shutdown the thread
15463 break;
15464 }
15465 if (rd < 0) {
15466 if (_abort || s_shutdown) {
15467 return NULL;
15468 }
15469 fprintf(stderr, "worker_thread_proc: Error: read(s_sock(1)) returned %d, error %d (%s)\n", rd, errno, strerror(errno));
15470 abort();
15471 return NULL;
15472 }
15473
15474 //printf("nc: %p: received request!\n", req.nc);
15475
15476 int response = thread_work_function(req.nc, req.w);
15477
15478 if (response == RESPONSE_501) {
15479 if (trace_mg||verbose_mg)
15480 printf("handle_http_message: sending 501 Not Implemented error\n");
15481 mongoose_send_501(req.nc, req.w);
15482 }
15483
15484 req.w->t->fCompleted = true;
15485 gTraceBuf->AddTraceMTS(req.w->t);
15486
15487 //printf("nc: %p: wseqno: %d, delete work object!\n", req.nc, req.w->wseqno);
15488
15489 delete req.w;
15490 req.w = NULL;
15491 }
15492 return NULL;
15493}
15494#endif
15495
15497{
15498 //printf("to %p, nc %p: thread %p started!\n", to, to->fNc, to->fThread);
15499
15500 std::unique_lock<std::mutex> ulm(to->fMutex, std::defer_lock);
15501
15502 to->fIsRunning = true;
15503
15504 while ((! _abort) && (! s_shutdown)) {
15506
15507 ulm.lock();
15508 while (to->fQueue.empty()) {
15509 //printf("to %p, nc %p, thread %p: waiting!\n", to, to->fNc, to->fThread);
15510 to->fNotify.wait(ulm);
15511 if (_abort || s_shutdown) {
15512 break;
15513 }
15514 }
15515
15516 if (_abort || s_shutdown) {
15517 break;
15518 }
15519
15520 w = to->fQueue.front();
15521 to->fQueue.pop_front();
15522 ulm.unlock();
15523
15524 //printf("to %p, nc %p: wseqno: %d, received request!\n", to, w->nc, w->wseqno);
15525
15526 int response = thread_work_function(w->nc, w);
15527
15528 if (response == RESPONSE_501) {
15529 if (trace_mg||verbose_mg)
15530 printf("handle_http_message: sending 501 Not Implemented error\n");
15531 mongoose_send_501(w->nc, w);
15532 }
15533
15534 // mg_broadcast() called on_work_complete() on the main thread and waited until it finished
15535
15536 if (!w->send_done) {
15537 // NB: careful here, if connection nc was closed, pointer nc points to nowhere! do not dereference it!
15538 // NB: stay quiet about it, nothing special about network connctions closing and opening as they wish.
15539 //printf("to %p, nc %p: wseqno: %d, wncseqno: %d, request was not sent, maybe nc was closed while we were thinking\n", to, w->nc, w->wseqno, w->wncseqno);
15540 }
15541
15542 w->t->fCompleted = true;
15543 gTraceBuf->AddTraceMTS(w->t);
15544
15545 //printf("nc: %p: wseqno: %d, delete work object!\n", w->nc, w->wseqno);
15546
15547 delete w;
15548 }
15549
15550 to->fIsRunning = false;
15551
15552 //printf("to %p, nc %p: thread %p finished!\n", to, to->fNc, to->fThread);
15553}
15554
15555static bool mongoose_hostlist_enabled(const struct mg_connection *nc);
15556
15557static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
15558{
15559 (void) nc;
15560 (void) ev_data;
15561
15562 //if (trace_mg && ev != 0) {
15563 // printf("ev_handler: connection %p, event %d\n", nc, ev);
15564 //}
15565
15566 switch (ev) {
15567 case 0:
15568 break;
15569 default: {
15570 if (trace_mg) {
15571 printf("ev_handler: connection %p, event %d\n", nc, ev);
15572 }
15573 break;
15574 }
15575 case MG_EV_ACCEPT:
15576 assert(nc->user_data == NULL);
15577 nc->user_data = new MongooseNcUserData();
15578
15579 if (trace_mg) {
15580 printf("ev_handler: connection %p, MG_EV_ACCEPT, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15581 }
15582 if (s_shutdown) {
15583 //printf("XXX nc %p!\n", nc);
15585 } else if (mongoose_hostlist_enabled(nc)) {
15586 if (!mongoose_check_hostlist(&nc->sa)) {
15588 }
15589 }
15590 break;
15591 case MG_EV_RECV:
15592 if (trace_mg_recv) {
15593 printf("ev_handler: connection %p, MG_EV_RECV, %d bytes\n", nc, *(int*)ev_data);
15594 }
15595 if (s_shutdown) {
15596 //printf("RRR nc %p!\n", nc);
15598 }
15599 break;
15600 case MG_EV_SEND:
15601 if (trace_mg_send) {
15602 printf("ev_handler: connection %p, MG_EV_SEND, %d bytes\n", nc, *(int*)ev_data);
15603 }
15604 break;
15605 case MG_EV_HTTP_CHUNK: {
15606 if (trace_mg) {
15607 printf("ev_handler: connection %p, MG_EV_HTTP_CHUNK\n", nc);
15608 }
15609 if (s_shutdown) {
15610 //printf("RRR1 nc %p!\n", nc);
15612 }
15613 break;
15614 }
15615 case MG_EV_HTTP_REQUEST: {
15616 struct http_message* msg = (struct http_message*)ev_data;
15617 if (trace_mg) {
15618 printf("ev_handler: connection %p, MG_EV_HTTP_REQUEST \"%s\" \"%s\"\n", nc, mgstr(&msg->method).c_str(), mgstr(&msg->uri).c_str());
15619 }
15620 if (s_shutdown) {
15621 //printf("RRR2 nc %p!\n", nc);
15623 } else {
15624 handle_http_message(nc, msg);
15625 }
15626 break;
15627 }
15628 case MG_EV_CLOSE: {
15629 if (trace_mg) {
15630 printf("ev_handler: connection %p, MG_EV_CLOSE, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15631 }
15632 //printf("CCC nc %p!\n", nc);
15633 FreeThread(nc);
15634 if (nc->user_data) {
15636 nc->user_data = NULL;
15637 delete ncud;
15638 ncud = NULL;
15639 }
15640 }
15641 }
15642}
15643
15644#define FLAG_HTTPS MG_F_USER_1
15645#define FLAG_PASSWORDS MG_F_USER_2
15646#define FLAG_HOSTLIST MG_F_USER_3
15647
15648static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15649{
15650 int flags = 0;
15651 if (nc && nc->listener) {
15652 flags = nc->listener->flags;
15653 }
15654 //printf("mongoose_passwords_enabled: nc %p, listener %p, flags 0x%lx, user_data %p, flags 0x%x\n", nc, nc->listener, nc->listener->flags, nc->listener->user_data, flags);
15655 return flags & FLAG_PASSWORDS;
15656}
15657
15658static bool mongoose_hostlist_enabled(const struct mg_connection *nc)
15659{
15660 int flags = 0;
15661 if (nc && nc->listener) {
15662 flags = nc->listener->flags;
15663 }
15664 //printf("mongoose_hostlist_enabled: nc %p, listener %p, flags 0x%lx, user_data %p, flags 0x%x\n", nc, nc->listener, nc->listener->flags, nc->listener->user_data, flags);
15665 return flags & FLAG_HOSTLIST;
15666}
15667
15668static int mongoose_listen(const char* address, int flags)
15669{
15670#if MG_ENABLE_SSL
15671#else
15672 if (flags & FLAG_HTTPS) {
15673 cm_msg(MERROR, "mongoose_listen", "https port \"%s\" requested, but mhttpd compiled without MG_ENABLE_SSL", address);
15674 return SS_SOCKET_ERROR;
15675 }
15676#endif
15677
15678 struct mg_connection *nc = mg_bind(&s_mgr, address, ev_handler);
15679 if (nc == NULL) {
15680 cm_msg(MERROR, "mongoose_listen", "Cannot mg_bind address \"%s\"", address);
15681 return SS_SOCKET_ERROR;
15682 }
15683
15684 if (flags & FLAG_HTTPS) {
15685#if MG_ENABLE_SSL
15686 std::string cert_file;
15687
15688 int status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
15689
15690 if (status != SUCCESS) {
15691 cm_msg(MERROR, "mongoose_listen", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
15692 cm_msg(MERROR, "mongoose_listen", "please create SSL certificate file using openssl: cd $MIDASSYS; openssl req -new -nodes -newkey rsa:2048 -sha256 -out ssl_cert.csr -keyout ssl_cert.key -subj \"/C=/ST=/L=/O=midas/OU=mhttpd/CN=localhost\"; openssl x509 -req -days 365 -sha256 -in ssl_cert.csr -signkey ssl_cert.key -out ssl_cert.pem; cat ssl_cert.key >> ssl_cert.pem");
15693 cm_msg(MERROR, "mongoose_listen", "or using certbot (recommened): setup certbot per Let's Encrypt instructions, certificates are typically saved in /etc/letsencrypt/live/$HOSTNAME/, copy fullchain.pem and privkey.pem to $MIDASSYS; cd $MIDASSYS; cat fullchain.pem privkey.pem > ssl_cert.pem");
15694 return SS_FILE_ERROR;
15695 }
15696
15697 printf("Mongoose web server will use https certificate file \"%s\"\n", cert_file.c_str());
15698
15699 const char* errmsg = mg_set_ssl(nc, cert_file.c_str(), NULL);
15700 if (errmsg) {
15701 cm_msg(MERROR, "mongoose_listen", "Cannot enable https with certificate file \"%s\", error: %s", cert_file.c_str(), errmsg);
15702 return SS_SOCKET_ERROR;
15703 }
15704
15705 // NB: where is the warning that the SSL certificate has expired?!? K.O.
15706#else
15707 abort(); // cannot happen!
15708#endif
15709 }
15710
15712
15713 nc->flags |= flags;
15714
15715 printf("Listening on \"%s://%s\", passwords %s, hostlist %s\n", (flags&FLAG_HTTPS)?"https":"http", address, (flags&FLAG_PASSWORDS)?"enabled":"OFF", (flags&FLAG_HOSTLIST)?"enabled":"OFF");
15716
15717 return SUCCESS;
15718}
15719
15720static int mongoose_init(MVOdb* odb, bool no_passwords, bool no_hostlist, const std::vector<std::string>& user_hostlist)
15721{
15722 bool enable_localhost_port = true;
15723 int localhost_port = 8080;
15724 bool localhost_port_passwords = false;
15725
15726 bool enable_insecure_port = false;
15727 int insecure_port = 8081;
15728 bool insecure_port_passwords = true;
15729 bool insecure_port_hostlist = true;
15730
15731 bool enable_https_port = false;
15732 int https_port = 8443;
15733 bool https_port_passwords = true;
15734 bool https_port_hostlist = false;
15735
15736 std::vector<std::string> hostlist;
15737 hostlist.push_back("localhost");
15738
15739 bool enable_ipv6 = true;
15740
15741 odb->RB("Enable localhost port", &enable_localhost_port, true);
15742 odb->RI("localhost port", &localhost_port, true);
15743 odb->RB("localhost port passwords", &localhost_port_passwords, true);
15744 odb->RB("Enable insecure port", &enable_insecure_port, true);
15745 odb->RI("insecure port", &insecure_port, true);
15746 odb->RB("insecure port passwords", &insecure_port_passwords, true);
15747 odb->RB("insecure port host list", &insecure_port_hostlist, true);
15748 odb->RB("Enable https port", &enable_https_port, true);
15749 odb->RI("https port", &https_port, true);
15750 odb->RB("https port passwords", &https_port_passwords, true);
15751 odb->RB("https port host list", &https_port_hostlist, true);
15752 odb->RSA("Host list", &hostlist, true, 10, 256);
15753 odb->RB("Enable IPv6", &enable_ipv6, true);
15754
15755 // populate the MIME.types table
15756 gProxyOdb = odb->Chdir("Proxy", true);
15757 std::string proxy_example = "#http://localhost:8080";
15758 gProxyOdb->RS("example", &proxy_example, true);
15759
15760 // populate the MIME.types table
15761 SaveMimetypes(odb->Chdir("mime.types", true));
15762
15763 if (!no_passwords
15767 gAuthMg = new Auth();
15768 int status = gAuthMg->Init();
15769 if (status != SUCCESS) {
15770 printf("mongoose_init: Error: Cannot initialize authorization object!\n");
15771 return status;
15772 }
15773 printf("HTTP Digest authentication with realm \"%s\" and password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
15774 } else {
15775 printf("Password protection is off\n");
15776 }
15777
15778 if (!no_hostlist
15781 gAllowedHosts.clear();
15782
15783 // copy the user allowed hosts
15784 for (unsigned int i=0; i<user_hostlist.size(); i++)
15785 gAllowedHosts.push_back(user_hostlist[i]);
15786
15787 for (unsigned i=0; i<hostlist.size(); i++) {
15788 std::string s = hostlist[i];
15789 if (s.length() < 1) // skip emties
15790 continue;
15791
15792 if (s[0] == '#') // skip commented-out entries
15793 continue;
15794
15795 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
15796 gAllowedHosts.push_back(s);
15797 }
15798
15799 printf("Hostlist active, connections will be accepted only from: ");
15800 for (unsigned i=0; i<gAllowedHosts.size(); i++) {
15801 if (i>0)
15802 printf(", ");
15803 printf("%s", gAllowedHosts[i].c_str());
15804 }
15805 printf("\n");
15806 } else {
15807 printf("Hostlist off, connections from anywhere will be accepted\n");
15808 }
15809
15811
15812 bool listen_failed = false;
15813
15815 char str[256];
15816 sprintf(str, "localhost:%d", localhost_port);
15817 int status = mongoose_listen(str, 0);
15818 if (status != SUCCESS)
15819 listen_failed = true;
15820 if (enable_ipv6) {
15821 sprintf(str, "[::1]:%d", localhost_port);
15823 if (status != SUCCESS)
15824 listen_failed = true;
15825 }
15826 }
15827
15829 char str[256];
15830 int flags = 0;
15835 if (enable_ipv6) {
15836 sprintf(str, "[::]:%d", insecure_port);
15838 if (status != SUCCESS)
15839 listen_failed = true;
15840 } else {
15841 sprintf(str, "%d", insecure_port);
15843 if (status != SUCCESS)
15844 listen_failed = true;
15845 }
15846 }
15847
15848 if (enable_https_port) {
15849 char str[256];
15850 int flags = 0;
15855 flags |= FLAG_HTTPS;
15856 if (enable_ipv6) {
15857 sprintf(str, "[::]:%d", https_port);
15859 if (status != SUCCESS)
15860 listen_failed = true;
15861 } else {
15862 sprintf(str, "%d", https_port);
15864 if (status != SUCCESS)
15865 listen_failed = true;
15866 }
15867 }
15868
15869 if (listen_failed) {
15870 cm_msg(MERROR, "mongoose_init", "Failed to listen on a TCP port enabled in ODB /WebServer");
15871 return SS_SOCKET_ERROR;
15872 }
15873
15874 return SUCCESS;
15875}
15876
15877static void mongoose_poll(int msec = 200)
15878{
15880}
15881
15882static void mongoose_cleanup()
15883{
15884 printf("Mongoose web server shutting down\n");
15885
15886 s_shutdown = true;
15887
15888 // close listener sockets
15889 if (s_mgr.active_connections) {
15890 struct mg_connection* nc = s_mgr.active_connections;
15891 while (nc) {
15892 //printf("nc %p, next %p, user_data %p, listener %p, flags %lu\n", nc, nc->next, nc->user_data, nc->listener, nc->flags);
15893 if (nc->flags & MG_F_LISTENING) {
15895 }
15896 nc = nc->next;
15897 }
15898 }
15899
15900 // tell threads to shut down
15901 for (auto it : gMongooseThreads) {
15903 to->fNotify.notify_one();
15904 }
15905
15906 // wait until all threads stop
15907 for (int i=0; i<10; i++) {
15908 int count_running = 0;
15909 for (auto it : gMongooseThreads) {
15911 //printf("AAA6C %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15912 if (to->fIsRunning) {
15913 count_running++;
15914 }
15915 }
15916 printf("Mongoose web server shutting down, %d threads still running\n", count_running);
15917 if (count_running == 0)
15918 break;
15919 mongoose_poll(1000);
15920 }
15921
15922 // delete thread objects
15923 for (auto it : gMongooseThreads) {
15925 //printf("AAA7B %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15926 if (to->fIsRunning) {
15927 cm_msg(MERROR, "mongoose", "thread failed to shut down");
15928 continue;
15929 }
15930 to->fThread->join();
15931 delete to->fThread;
15932 delete to;
15933 }
15934 gMongooseThreads.clear();
15935
15937
15938 //closesocket(s_sock[0]);
15939 //closesocket(s_sock[1]);
15940
15941 // make leak sanitizer happy!
15942 for (auto e : gHostlistCache) {
15943 delete e;
15944 }
15945 gHostlistCache.clear();
15946 if (gProxyOdb) {
15947 delete gProxyOdb;
15948 gProxyOdb = NULL;
15949 }
15950 if (gMimeTypesOdb) {
15951 delete gMimeTypesOdb;
15953 }
15954
15955 printf("Mongoose web server shut down\n");
15956}
15957
15958#endif
15959
15960#ifdef HAVE_MONGOOSE6
15961
15962static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15963{
15964 return true;
15965}
15966
15968{
15969 HNDLE hDB;
15970 int size;
15971 int status;
15972
15973 //if (verbose)
15974 // trace_mg = true;
15975
15976 if (verbose)
15977 verbose_mg = true;
15978
15980 assert(status == CM_SUCCESS);
15981
15982 int http_port = 8080;
15983 int https_port = 8443;
15984 int http_redirect_to_https = 1;
15985
15986 size = sizeof(http_port);
15987 db_get_value(hDB, 0, "/Experiment/midas http port", &http_port, &size, TID_INT, TRUE);
15988
15989 size = sizeof(https_port);
15990 db_get_value(hDB, 0, "/Experiment/midas https port", &https_port, &size, TID_INT, TRUE);
15991
15992 size = sizeof(http_redirect_to_https);
15993 db_get_value(hDB, 0, "/Experiment/http redirect to https", &http_redirect_to_https, &size, TID_BOOL, TRUE);
15994
15995 bool need_cert_file = false;
15996 bool need_password_file = false;
15997
15998 if (user_http_port)
16000
16001 if (user_https_port)
16003
16004 if (https_port) {
16005 need_cert_file = true;
16006 need_password_file = true;
16007 }
16008
16009 if (!https_port)
16011
16013 // no passwords serving over http unless
16014 // http is just a redict to https
16015 need_password_file = false;
16016 }
16017
16018 if (socket_priviledged_port >= 0) {
16019 // no passwords if serving unencrypted http on port 80
16020 need_password_file = false;
16021 printf("Mongoose web server password portection is disabled: serving unencrypted http on port 80\n");
16022 }
16023
16024 bool have_at_least_one_port = false;
16025
16026 std::string cert_file;
16027
16028 if (need_cert_file) {
16029 status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
16030
16031 if (status != SUCCESS) {
16032 cm_msg(MERROR, "mongoose", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
16033 cm_msg(MERROR, "mongoose", "please create SSL certificate file: cd $MIDASSYS; openssl req -new -nodes -newkey rsa:2048 -sha256 -out ssl_cert.csr -keyout ssl_cert.key -subj \"/C=/ST=/L=/O=midas/OU=mhttpd/CN=localhost\"; openssl x509 -req -days 365 -sha256 -in ssl_cert.csr -signkey ssl_cert.key -out ssl_cert.pem; cat ssl_cert.key >> ssl_cert.pem");
16034 return SS_FILE_ERROR;
16035 }
16036
16037 printf("Mongoose web server will use SSL certificate file \"%s\"\n", cert_file.c_str());
16038 }
16039
16040 if (need_password_file) {
16041 gAuthMg = new Auth();
16042 status = gAuthMg->Init();
16043 if (status != SUCCESS) {
16044 printf("Error: Cannot initialize authorization object!\n");
16045 return status;
16046 }
16047 printf("Mongoose web server will use authentication realm \"%s\", password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
16048 } else {
16049 printf("Mongoose web server will not use password protection\n");
16050 }
16051
16052 if (trace_mg)
16053 printf("start_mg!\n");
16054
16055#ifndef OS_WINNT
16057#endif
16058
16059 if (!gTraceBuf) {
16061 }
16062
16063 if (!request_mutex) {
16065 assert(status==SS_SUCCESS || status==SS_CREATED);
16066 }
16067
16069
16070 // use socket bound to priviledged port (setuid-mode)
16071 if (socket_priviledged_port >= 0) {
16073 if (nc == NULL) {
16074 cm_msg(MERROR, "mongoose", "Cannot create mg_connection for set-uid-root privileged port");
16075 return SS_SOCKET_ERROR;
16076 }
16077
16078 nc->flags |= MG_F_LISTENING;
16079#ifdef MG_ENABLE_THREADS
16081#endif
16084
16086 printf("mongoose web server is listening on the set-uid-root privileged port\n");
16087 }
16088
16089 if (http_port != 80) { // port 80 is already handled by socket_priviledged_port
16090 char str[256];
16091 sprintf(str, "%d", http_port);
16093 if (nc == NULL) {
16094 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", http_port);
16095 return SS_SOCKET_ERROR;
16096 }
16097
16098#ifdef MG_ENABLE_THREADS
16100#endif
16102
16104 std::string hostname = ss_gethostname();
16105 char str[256];
16106 sprintf(str, "%d", https_port);
16107 std::string s = hostname + ":" + std::string(str);
16108 nc->user_data = new std::string(s);
16110 printf("mongoose web server is redirecting HTTP port %d to https://%s\n", http_port, s.c_str());
16111 } else {
16113 }
16114
16116 printf("mongoose web server is listening on the HTTP port %d\n", http_port);
16117 }
16118
16119 if (https_port) {
16120#ifdef MG_ENABLE_SSL
16121 char str[256];
16122 sprintf(str, "%d", https_port);
16124 if (nc == NULL) {
16125 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", https_port);
16126 return SS_SOCKET_ERROR;
16127 }
16128
16129 mg_set_ssl(nc, cert_file.c_str(), NULL);
16130#ifdef MG_ENABLE_THREADS
16132#endif
16135
16137 printf("mongoose web server is listening on the HTTPS port %d\n", https_port);
16138#else
16139 cm_msg(MERROR, "mongoose", "https port %d requested, but mhttpd compiled without MG_ENABLE_SSL", https_port);
16140 return SS_SOCKET_ERROR;
16141#endif
16142 }
16143
16145 cm_msg(MERROR, "mongoose", "cannot start: no ports defined");
16146 return SS_FILE_ERROR;
16147 }
16148
16149 return SUCCESS;
16150}
16151
16152int stop_mg()
16153{
16154 if (trace_mg)
16155 printf("stop_mg!\n");
16156
16157 // Stop the server.
16159
16160 if (trace_mg)
16161 printf("stop_mg done!\n");
16162 return SUCCESS;
16163}
16164
16165int loop_mg()
16166{
16167 int status = SUCCESS;
16168
16169 /* establish Ctrl-C handler - will set _abort to TRUE */
16171
16172 while (!_abort) {
16173
16174 /* cm_yield() is not thread safe, need to take a lock */
16175
16176#ifdef HAVE_MONGOOSE6
16178#endif
16179 gMutex.lock();
16180
16181 /* check for shutdown message */
16182 status = cm_yield(0);
16183 if (status == RPC_SHUTDOWN)
16184 break;
16185
16186 gMutex.unlock();
16187#ifdef HAVE_MONGOOSE6
16189#endif
16190
16191 //ss_sleep(10);
16192
16193 mg_mgr_poll(&mgr_mg, 10);
16194 }
16195
16196 return status;
16197}
16198#endif
16199
16200static MJsonNode* get_http_trace(const MJsonNode* params)
16201{
16202 if (!params) {
16203 MJSO *doc = MJSO::I();
16204 doc->D("get current value of mhttpd http_trace");
16205 doc->P(NULL, 0, "there are no input parameters");
16206 doc->R(NULL, MJSON_INT, "current value of http_trace");
16207 return doc;
16208 }
16209
16210 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16211}
16212
16213static MJsonNode* set_http_trace(const MJsonNode* params)
16214{
16215 if (!params) {
16216 MJSO* doc = MJSO::I();
16217 doc->D("set new value of mhttpd http_trace");
16218 doc->P(NULL, MJSON_INT, "new value of http_trace");
16219 doc->R(NULL, MJSON_INT, "new value of http_trace");
16220 return doc;
16221 }
16222
16223 http_trace = params->GetInt();
16224 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16225}
16226
16228{
16229 mjsonrpc_add_handler("set_http_trace", set_http_trace);
16230 mjsonrpc_add_handler("get_http_trace", get_http_trace);
16231}
16232
16233/*------------------------------------------------------------------*/
16234
16235int main(int argc, const char *argv[])
16236{
16237 int status;
16238 int daemon = FALSE;
16239#ifdef HAVE_MONGOOSE6
16240 int user_http_port = 0;
16241 int user_https_port = 0;
16242#endif
16243#ifdef HAVE_MONGOOSE616
16244 bool no_passwords = false;
16245 bool no_hostlist = false;
16246#endif
16247 const char *myname = "mhttpd";
16248
16249 setbuf(stdout, NULL);
16250 setbuf(stderr, NULL);
16251#ifdef SIGPIPE
16252 /* avoid getting killed by "Broken pipe" signals */
16254#endif
16255
16256#ifdef HAVE_MONGOOSE6
16257 //
16258 // if running setuid-root, unconditionally bind to port 80.
16259 //
16260
16261 int socket_priviledged_port = -1;
16262
16263#ifdef OS_UNIX
16264 // in setuid-root mode bind to priviledged port
16265 if (getuid() != geteuid()) {
16266 int port80 = 80;
16267
16268 printf("mhttpd is running in setuid-root mode.\n");
16269
16271 if (socket_priviledged_port < 0) {
16272 printf("Cannot open listening socket on TCP port %d, aborting.\n", port80);
16273 exit(1);
16274 }
16275
16276 // give up root privilege
16277 status = setuid(getuid());
16278 if (status != 0) {
16279 printf("Cannot give up root privelege, aborting.\n");
16280 exit(1);
16281 }
16282 status = setuid(getuid());
16283 if (status != 0) {
16284 printf("Cannot give up root privelege, aborting.\n");
16285 exit(1);
16286 }
16287 }
16288#endif
16289#endif
16290
16291 char midas_hostname[256];
16292 char midas_expt[256];
16293
16294 /* get default from environment */
16296
16297 /* parse command line parameters */
16298#ifdef HAVE_MONGOOSE6
16299 gUserAllowedHosts.clear();
16300#else
16301 std::vector<std::string> user_hostlist;
16302#endif
16303 for (int i = 1; i < argc; i++) {
16304 if (argv[i][0] == '-' && argv[i][1] == 'D')
16305 daemon = TRUE;
16306 else if (argv[i][0] == '-' && argv[i][1] == 'v')
16307 verbose = TRUE;
16308 else if (argv[i][0] == '-' && argv[i][1] == 'E')
16309 elog_mode = TRUE;
16310 else if (argv[i][0] == '-' && argv[i][1] == 'H') {
16312#ifdef HAVE_MONGOOSE6
16313 } else if (strcmp(argv[i], "--http") == 0) {
16314 if (argv[i+1]) {
16315 user_http_port = atoi(argv[i+1]);
16316 }
16317 } else if (strcmp(argv[i], "--https") == 0) {
16318 if (argv[i+1]) {
16319 user_https_port = atoi(argv[i+1]);
16320 }
16321#endif
16322 } else if (strcmp(argv[i], "--trace-mg") == 0) {
16323 trace_mg = true;
16324 trace_mg_recv = true;
16325 trace_mg_send = true;
16326 } else if (strcmp(argv[i], "--trace-mg-verbose") == 0) {
16327 trace_mg_verbose = true;
16328 } else if (strcmp(argv[i], "--no-trace-mg-recv") == 0) {
16329 trace_mg_recv = false;
16330 } else if (strcmp(argv[i], "--no-trace-mg-send") == 0) {
16331 trace_mg_send = false;
16332 } else if (strcmp(argv[i], "--verbose-mg") == 0) {
16333 verbose_mg = true;
16334#ifdef HAVE_MONGOOSE616
16335 } else if (strcmp(argv[i], "--no-multithread") == 0) {
16336 multithread_mg = false;
16337 } else if (strcmp(argv[i], "--no-passwords") == 0) {
16338 no_passwords = true;
16339 } else if (strcmp(argv[i], "--no-hostlist") == 0) {
16340 no_hostlist = true;
16341#endif
16342 } else if (argv[i][0] == '-') {
16343 if (i + 1 >= argc || argv[i + 1][0] == '-')
16344 goto usage;
16345 if (argv[i][1] == 'h')
16347 else if (argv[i][1] == 'e')
16348 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
16349 else if (argv[i][1] == 'a') {
16350#ifdef HAVE_MONGOOSE6
16351 gUserAllowedHosts.push_back(argv[++i]);
16352#else
16353 user_hostlist.push_back(argv[++i]);
16354#endif
16355 } else if (argv[i][1] == 'p') {
16356 printf("Option \"-p port_number\" for the old web server is obsolete.\n");
16357 printf("mongoose web server is the new default, port number is set in ODB or with \"--http port_number\".\n");
16358 printf("To run the obsolete old web server, please use \"--oldserver\" switch.\n");
16359 return 1;
16360 } else {
16361 usage:
16362 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-v] [-D] [-a Hostname]\n\n", argv[0]);
16363 printf(" -a add hostname to the hostlist of hosts allowed to connect to mhttpd\n");
16364 printf(" -e experiment to connect to\n");
16365 printf(" -h connect to midas server (mserver) on given host\n");
16366 printf(" -v display verbose HTTP communication\n");
16367 printf(" -D become a daemon\n");
16368 printf(" -E only display ELog system\n");
16369 printf(" -H only display history plots\n");
16370#ifdef HAVE_MONGOOSE6
16371 printf(" --http port - bind to specified HTTP port (default is ODB \"/Experiment/midas http port\")\n");
16372 printf(" --https port - bind to specified HTTP port (default is ODB \"/Experiment/midas https port\")\n");
16373#endif
16374 printf(" --verbose-mg - trace mongoose web requests\n");
16375 printf(" --trace-mg - trace mongoose events\n");
16376 printf(" --no-trace-mg-recv - do not trace mongoose recv events\n");
16377 printf(" --no-trace-mg-send - dop not trace mongoose send events\n");
16378#ifdef HAVE_MONGOOSE616
16379 printf(" --no-multithread - disable mongoose multithreading\n");
16380 printf(" --no-passwords - disable password protection\n");
16381 printf(" --no-hostlist - disable access control host list\n");
16382#endif
16383 return 0;
16384 }
16385 }
16386 }
16387
16388 if (daemon) {
16389 printf("Becoming a daemon...\n");
16391 }
16392
16393#ifdef OS_LINUX
16394 /* write PID file */
16395 FILE *f = fopen("/var/run/mhttpd.pid", "w");
16396 if (f != NULL) {
16397 fprintf(f, "%d", ss_getpid());
16398 fclose(f);
16399 }
16400#endif
16401
16402 if (history_mode)
16403 myname = "mhttpd_history";
16404
16405 /*---- connect to experiment ----*/
16409 return 1;
16410 else if (status == DB_INVALID_HANDLE) {
16411 std::string s = cm_get_error(status);
16412 puts(s.c_str());
16413 } else if (status != CM_SUCCESS) {
16414 std::string s = cm_get_error(status);
16415 puts(s.c_str());
16416 return 1;
16417 }
16418
16419 /* mhttpd needs the watchdog thread until we are sure
16420 * we do not have any long sleeps anywhere in the mhttpd code.
16421 * this includes reads from the history files or databases,
16422 * that can take arbitrary long time */
16424
16425 /* Get ODB handles */
16426
16427 HNDLE hDB;
16428
16430
16431 MVOdb *odb = MakeMidasOdb(hDB);
16432 gOdb = odb;
16433
16434 /* do ODB record checking */
16435 if (!check_odb_records(odb)) {
16436 // check_odb_records() fails with nothing printed to the terminal
16437 // because mhttpd does not print cm_msg(MERROR, ...) messages to the terminal.
16438 // At least print something!
16439 printf("check_odb_records() failed, see messages and midas.log, bye!\n");
16441 return 1;
16442 }
16443
16444#ifdef HAVE_MONGOOSE6
16445 if (init_allowed_hosts() != SUCCESS) {
16446 printf("init_allowed_hosts() failed, see messages and midas.log, bye!\n");
16448 return 1;
16449 }
16450
16451 if (verbose) {
16452 if (gAllowedHosts.size() > 0) {
16453 printf("mhttpd allowed hosts list: ");
16454 for (unsigned int i=0; i<gAllowedHosts.size(); i++) {
16455 if (i>0)
16456 printf(", ");
16457 printf("%s", gAllowedHosts[i].c_str());
16458 }
16459 printf("\n");
16460 } else {
16461 printf("mhttpd allowed hosts list is empty\n");
16462 }
16463 }
16464
16465 // populate the MIME.types table
16466 SaveMimetypes(odb->Chdir("WebServer/mime.types", true));
16467#endif
16468
16469 /* initialize odb entries needed for mhttpd and midas web pages */
16470 init_mhttpd_odb(odb);
16471
16472 /* initialize menu buttons */
16473 init_menu_buttons(odb);
16474
16475 /* initialize elog odb entries */
16476 init_elog_odb();
16477
16478 /* initialize the JSON RPC handlers */
16479 mjsonrpc_init();
16481
16483
16484#ifdef HAVE_MONGOOSE6
16486 if (status != SUCCESS) {
16487 // At least print something!
16488 printf("could not start the mongoose web server, see messages and midas.log, bye!\n");
16490 return 1;
16491 }
16492#endif
16493
16494#ifdef HAVE_MONGOOSE616
16495
16496#ifdef SIGPIPE
16497#ifdef SIG_IGN
16499#endif
16500#endif
16501
16502 if (!gTraceBuf) {
16504 }
16505
16506 //if (!request_mutex) {
16507 // status = ss_mutex_create(&request_mutex, FALSE);
16508 // assert(status==SS_SUCCESS || status==SS_CREATED);
16509 //}
16510
16511 /* establish Ctrl-C handler - will set _abort to TRUE */
16513
16514 MVOdb* o = odb->Chdir("WebServer", true);
16516 if (status != SUCCESS) {
16517 // At least print something!
16518 printf("Error: Could not start the mongoose web server, see messages and midas.log, bye!\n");
16520 return 1;
16521 }
16522
16523 delete o;
16524#endif
16525
16526#ifdef HAVE_MONGOOSE6
16527 loop_mg();
16528 stop_mg();
16529#endif
16530
16531#ifdef HAVE_MONGOOSE616
16532 while (!_abort) {
16533
16534 /* cm_yield() is not thread safe, need to take a lock */
16535
16536 //status = ss_mutex_wait_for(request_mutex, 0);
16537 gMutex.lock();
16538
16539 /* check for shutdown message */
16540 status = cm_yield(0);
16541 if (status == RPC_SHUTDOWN)
16542 break;
16543
16544 gMutex.unlock();
16545 //status = ss_mutex_release(request_mutex);
16546
16547 //ss_sleep(10);
16548
16549 mongoose_poll(10);
16550 }
16551
16553#endif
16554
16555 if (gMh) {
16556 delete gMh;
16557 gMh = NULL;
16558 gMhkey = 0;
16559 }
16560
16561 mjsonrpc_exit();
16563 return 0;
16564}
16565
16566/* emacs
16567 * Local Variables:
16568 * tab-width: 8
16569 * c-basic-offset: 3
16570 * indent-tabs-mode: nil
16571 * End:
16572 */
#define FALSE
Definition cfortran.h:309
char * attachment_buffer[3]
Definition mhttpd.cxx:69
size_t attachment_size[3]
Definition mhttpd.cxx:70
~Attachment()
Definition mhttpd.cxx:79
void clear(int i)
Definition mhttpd.cxx:85
std::vector< AuthEntry > passwords
Definition mhttpd.cxx:13743
std::string passwd_filename
Definition mhttpd.cxx:13742
std::string realm
Definition mhttpd.cxx:13741
int Init()
Definition mhttpd.cxx:13750
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:719
void unsetparam(const char *param)
Definition mhttpd.cxx:819
const char * getparam(const char *param)
Definition mhttpd.cxx:776
char _param[MAX_PARAM][PARAM_LENGTH]
Definition mhttpd.cxx:704
void setparam(const char *param, const char *value)
Definition mhttpd.cxx:726
~Param()
Definition mhttpd.cxx:714
char * _value[MAX_PARAM]
Definition mhttpd.cxx:705
BOOL isparam(const char *param)
Definition mhttpd.cxx:805
void printparam()
Definition mhttpd.cxx:767
std::string xgetparam(const char *param)
Definition mhttpd.cxx:796
Param()
Definition mhttpd.cxx:709
void freeparam()
Definition mhttpd.cxx:756
char _text[TEXT_SIZE]
Definition mhttpd.cxx:706
MUTEX_T * fMutex
Definition mhttpd.cxx:440
void AddTrace(RequestTrace *t)
Definition mhttpd.cxx:458
void AddTraceMTS(RequestTrace *t)
Definition mhttpd.cxx:463
std::vector< RequestTrace * > fBuf
Definition mhttpd.cxx:441
std::string fQuery
Definition mhttpd.cxx:396
std::string fMethod
Definition mhttpd.cxx:394
void PrintTrace0() const
Definition mhttpd.cxx:413
std::string fUri
Definition mhttpd.cxx:395
double fTimeSent
Definition mhttpd.cxx:392
std::string fResource
Definition mhttpd.cxx:398
bool fCompleted
Definition mhttpd.cxx:393
double fTimeReceived
Definition mhttpd.cxx:388
std::string fRPC
Definition mhttpd.cxx:397
double fTimeUnlocked
Definition mhttpd.cxx:390
double fTimeLocked
Definition mhttpd.cxx:389
double fTimeProcessed
Definition mhttpd.cxx:391
Return()
Definition mhttpd.cxx:524
va_end(argptr)
~Return()
Definition mhttpd.cxx:534
else strcpy(return_buffer+strlen_retbuf, str)
int return_grow(size_t len)
Definition mhttpd.cxx:556
return_grow(strlen(str))
vsprintf(str,(char *) format, argptr)
void rread(const char *filename, int fh, int len)
Definition mhttpd.cxx:588
int strlen_retbuf
Definition mhttpd.cxx:520
size_t return_size
Definition mhttpd.cxx:517
void zero()
Definition mhttpd.cxx:549
void char str[10000]
Definition mhttpd.cxx:672
void rsprintf(const char *format,...) MATTRPRINTF(2
void rmemcpy(const void *buf, int len)
Definition mhttpd.cxx:578
va_start(argptr, format)
int return_length
Definition mhttpd.cxx:521
void rsputs2(const char *str)
Definition mhttpd.cxx:621
void rsputs(const char *str)
Definition mhttpd.cxx:602
void reset()
Definition mhttpd.cxx:544
char * return_buffer
Definition mhttpd.cxx:518
assert(strlen(str)< sizeof(str))
static bool exists(const std::string &name)
Definition odbxx.cxx:75
static void usage()
int done
TRIGGER_SETTINGS ts
INT al_get_alarms(std::string *presult)
Definition alarm.cxx:853
INT cm_yield(INT millisec)
Definition midas.cxx:5664
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3025
INT cm_connect_client(const char *client_name, HNDLE *hConn)
Definition midas.cxx:2780
INT cm_start_watchdog_thread()
Definition midas.cxx:7377
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:2311
std::string cm_expand_env(const char *str)
Definition midas.cxx:7732
int cm_exec_script(const char *odb_path_to_script)
Definition midas.cxx:5483
INT cm_disconnect_experiment(void)
Definition midas.cxx:2860
std::string cm_get_exptab_filename()
Definition midas.cxx:1802
std::string cm_get_path()
Definition midas.cxx:1551
std::string cm_get_history_path(const char *history_channel)
Definition midas.cxx:5865
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2148
const char * cm_get_version()
Definition midas.cxx:1490
std::string cm_get_experiment_name()
Definition midas.cxx:1594
const char * cm_get_revision()
Definition midas.cxx:1498
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7542
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:226
std::string ss_gethostname()
Definition system.cxx:5784
INT ss_mutex_release(MUTEX_T *mutex)
Definition system.cxx:3229
int ss_isnan(double x)
Definition system.cxx:8039
time_t ss_mktime(struct tm *tms)
Definition system.cxx:3437
DWORD ss_millitime()
Definition system.cxx:3465
int ss_file_exist(const char *path)
Definition system.cxx:7196
int ss_isfin(double x)
Definition system.cxx:8044
std::string ss_getcwd()
Definition system.cxx:5848
INT ss_getpid(void)
Definition system.cxx:1379
INT ss_mutex_create(MUTEX_T **mutex, BOOL recursive)
Definition system.cxx:3013
void ss_tzset()
Definition system.cxx:3427
INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
Definition system.cxx:5471
std::string ss_replace_env_variables(const std::string &inputPath)
Definition system.cxx:2284
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2073
DWORD ss_time()
Definition system.cxx:3534
INT ss_sleep(INT millisec)
Definition system.cxx:3700
char * ss_crypt(const char *buf, const char *salt)
Definition system.cxx:7969
void * ss_ctrlc_handler(void(*func)(int))
Definition system.cxx:3971
INT ss_timezone()
Definition system.cxx:3652
INT ss_mutex_wait_for(MUTEX_T *mutex, INT timeout)
Definition system.cxx:3109
INT cm_msg1(INT message_type, const char *filename, INT line, const char *facility, const char *routine, const char *format,...)
Definition midas.cxx:987
INT EXPRT cm_msg_facilities(STRING_LIST *list)
Definition midas.cxx:516
std::string cm_get_error(INT code)
Definition midas.cxx:467
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:929
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition midas.cxx:1278
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition midas.cxx:551
#define TELL(fh)
Definition msystem.h:250
#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:3206
INT db_sprintfh(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10989
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6898
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3861
INT db_find_link(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4279
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5420
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6366
std::string strcomb1(const char **list)
Definition odb.cxx:600
INT db_set_link_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7430
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4995
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11812
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8222
INT db_set_link_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7759
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6544
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3313
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12981
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9042
INT db_scan_tree(HNDLE hDB, HNDLE hKey, INT level, INT(*callback)(HNDLE, HNDLE, KEY *, INT, void *), void *info)
Definition odb.cxx:4772
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6024
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6077
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:13945
INT db_sprintff(char *string, const char *format, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10925
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7653
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13823
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7220
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5730
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10849
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:10513
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:5266
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4084
INT db_get_link_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6661
INT db_rename_key(HNDLE hDB, HNDLE hKey, const char *name)
Definition odb.cxx:6266
INT db_get_key_time(HNDLE hDB, HNDLE hKey, DWORD *delta)
Definition odb.cxx:6137
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:5370
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5591
INT EXPRT db_resize_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int num_values, int max_string_length)
Definition odb.cxx:14036
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12808
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition odb.cxx:11320
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7507
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3606
#define RPC_CNAF16
Definition mrpc.h:125
INT rpc_client_call(HNDLE hConn, DWORD routine_id,...)
Definition midas.cxx:13494
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11849
#define RPC_JRPC
Definition mrpc.h:130
static std::vector< RPC_LIST > rpc_list
Definition midas.cxx:11595
const char * rpc_tid_name(INT id)
Definition midas.cxx:11786
#define RPC_CNAF24
Definition mrpc.h:126
#define RPC_MANUAL_TRIG
Definition mrpc.h:128
INT rpc_tid_size(INT id)
Definition midas.cxx:11779
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:14189
static bool trace_mg
Definition mhttpd.cxx:13721
static void SaveHistPlotToOdb(MVOdb *odb, const HistPlot &hp, const char *group, const char *panel)
Definition mhttpd.cxx:10415
static bool trace_mg_send
Definition mhttpd.cxx:13723
#define LOG2
Definition mhttpd.cxx:7639
BOOL is_editable(char *eq_name, char *var_name)
Definition mhttpd.cxx:2534
#define LN10
Definition mhttpd.cxx:7638
const unsigned char favicon_png[]
Definition mhttpd.cxx:217
#define WEB_BUFFER_SIZE
Definition mhttpd.cxx:511
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:7642
static bool cmp_vars(const HistVar &a, const HistVar &b)
Definition mhttpd.cxx:10111
void output_key(Param *p, Return *r, HNDLE hkey, int index, const char *format)
Definition mhttpd.cxx:4379
static MVOdb * gOdb
Definition mhttpd.cxx:48
void get_elog_url(char *url, int len)
static void DeleteHistPlotDeleted(HistPlot &hp)
Definition mhttpd.cxx:10491
static BOOL history_mode
Definition mhttpd.cxx:95
static void LoadHistPlotFromParam(HistPlot *hp, Param *p)
Definition mhttpd.cxx:10310
static void add_rpc_functions()
Definition mhttpd.cxx:16227
#define RESPONSE_501
Definition mhttpd.cxx:14272
INT check_odb_records(MVOdb *odb)
Definition mhttpd.cxx:13405
static int handle_http_post(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14900
std::string get_content_type(const char *filename)
Definition mhttpd.cxx:1135
static const std::string find_header_mg(const struct http_message *msg, const char *name)
Definition mhttpd.cxx:14158
static std::mutex gMutex
Definition mhttpd.cxx:47
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:13771
#define HTTP_ENCODING
Definition mhttpd.cxx:213
void strencode(Return *r, const char *text)
Definition mhttpd.cxx:2022
static MVOdb * gMimeTypesOdb
Definition mhttpd.cxx:179
void init_elog_odb()
Definition mhttpd.cxx:1981
static const char default_type_list[20][NAME_LENGTH]
Definition mhttpd.cxx:101
void show_eqtable_page(Param *pp, Return *r, int refresh)
Definition mhttpd.cxx:2562
static void history_watch_callback(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition mhttpd.cxx:8155
void show_custom_file(Return *r, const char *name)
Definition mhttpd.cxx:3614
void show_find_page(Return *r, const char *value)
Definition mhttpd.cxx:7577
#define MAX_GROUPS
Definition mhttpd.cxx:52
BOOL check_web_password(Return *r, HNDLE hDB, const char *dec_path, const char *password, const char *redir)
Definition mhttpd.cxx:6746
bool send_fp(Return *r, const std::string &path, FILE *fp)
Definition mhttpd.cxx:1166
std::vector< std::string > get_resource_paths()
Definition mhttpd.cxx:991
static void SplitEventAndTagNames(std::string var_name, std::string &event_name, std::string &tag_name)
Definition mhttpd.cxx:10161
void decode_cookies(Cookies *c, const http_message *msg)
Definition mhttpd.cxx:14223
char * stristr(const char *str, const char *pattern)
Definition mhttpd.cxx:341
void submit_elog(MVOdb *odb, Param *pp, Return *r, Attachment *a)
Definition mhttpd.cxx:2251
void show_query_page(Param *p, Return *r)
Definition mhttpd.cxx:9801
static void urlEncode(char *ps, int ps_size)
Definition mhttpd.cxx:921
static std::string NextHistPlotColour(const HistPlot &hp)
Definition mhttpd.cxx:10126
std::string strencode2(const char *text)
Definition mhttpd.cxx:2050
void decode_get(Return *rr, char *string, const Cookies *c, const char *url, const char *query_string, RequestTrace *t)
Definition mhttpd.cxx:13211
static MJsonNode * get_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16200
void show_error(Return *r, const char *error)
Definition mhttpd.cxx:1841
static HNDLE gMhkey
Definition mhttpd.cxx:8163
static bool read_passwords(Auth *auth)
Definition mhttpd.cxx:13813
void redirect2(Return *r, const char *path)
Definition mhttpd.cxx:1446
static void show_cnaf_page(Param *p, Return *rr)
Definition mhttpd.cxx:5664
static void SaveMimetypes(MVOdb *odb)
Definition mhttpd.cxx:203
#define MAX_PARAM
Definition mhttpd.cxx:697
#define DEFAULT_REFRESH
Definition mhttpd.cxx:39
void show_navigation_bar(Return *r, const char *cur_page)
Definition mhttpd.cxx:1869
#define LOG5
Definition mhttpd.cxx:7640
void ctrlc_handler(int sig)
Definition mhttpd.cxx:13469
static void PrintHistPlot(const HistPlot &hp)
Definition mhttpd.cxx:10116
void javascript_commands(Param *p, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:4454
#define MAX_VARS
Definition mhttpd.cxx:53
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:14744
std::string time_to_string(time_t t)
Definition mhttpd.cxx:8143
static std::string mgstr(const mg_str *s)
Definition mhttpd.cxx:14153
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:7916
static bool mongoose_passwords_enabled(const struct mg_connection *nc)
static bool verbose_mg
Definition mhttpd.cxx:13720
static int cmp_names(const void *a, const void *b)
Definition mhttpd.cxx:9985
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:1255
int find_file_mg(const char *filename, std::string &path, FILE **fpp, bool trace)
Definition mhttpd.cxx:13688
void decode_query(Param *pp, const char *query_string)
Definition mhttpd.cxx:13186
static bool gDoReloadHistory
Definition mhttpd.cxx:8153
static std::string check_digest_auth(struct http_message *hm, Auth *auth)
Definition mhttpd.cxx:13909
static MidasHistoryInterface * gMh
Definition mhttpd.cxx:8162
static bool trace_mg_verbose
Definition mhttpd.cxx:13724
static bool gDoSetupHistoryWatch
Definition mhttpd.cxx:8152
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:8531
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:7795
void show_password_page(Return *r, const char *dec_path, const char *password)
Definition mhttpd.cxx:6712
time_t string_to_time(const char *str)
Definition mhttpd.cxx:8127
void show_header(Return *r, const char *title, const char *method, const char *path, int refresh)
Definition mhttpd.cxx:1781
bool send_resource(Return *r, const std::string &name, bool generate_404=true)
Definition mhttpd.cxx:1231
void strencode3(Return *r, const char *text)
Definition mhttpd.cxx:2081
static std::vector< std::string > gAllowedHosts
Definition mhttpd.cxx:13479
bool send_file(Return *r, const std::string &path, bool generate_404=true)
Definition mhttpd.cxx:1212
static int xmg_check_nonce(const char *nonce)
Definition mhttpd.cxx:13792
void show_text_header(Return *r)
Definition mhttpd.cxx:1829
char * find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
Definition mhttpd.cxx:3096
static std::string UrlDecode(const char *p)
Definition mhttpd.cxx:843
void strencode4(Return *r, const char *text)
Definition mhttpd.cxx:2106
void show_elog_attachment(Param *p, Return *r, const char *path)
Definition mhttpd.cxx:2486
void Unlock(RequestTrace *t)
Definition mhttpd.cxx:12259
int evaluate_src(char *key, char *src, double *fvalue)
Definition mhttpd.cxx:3502
void redirect(Return *r, const char *path)
Definition mhttpd.cxx:1409
static void urlDecode(char *p)
Definition mhttpd.cxx:882
static std::string add_param_to_url(const char *name, const char *value)
Definition mhttpd.cxx:9790
#define READ_HISTORY_DATA
Definition mhttpd.cxx:8330
bool starts_with(const std::string &s1, const char *s2)
Definition mhttpd.cxx:4438
static const char * cgif_bar_str[]
Definition mhttpd.cxx:3473
#define PARAM_LENGTH
Definition mhttpd.cxx:698
#define RESPONSE_QUEUED
Definition mhttpd.cxx:14271
static MidasHistoryInterface * get_history(bool reset=false)
Definition mhttpd.cxx:8167
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:3280
static int handle_http_get(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14817
#define READ_HISTORY_RUNMARKER
Definition mhttpd.cxx:8331
std::string add_custom_path(const std::string &filename)
Definition mhttpd.cxx:3575
void sec_to_label(char *result, int sec, int base, int force_date)
Definition mhttpd.cxx:7760
void show_odb_page(Param *pp, Return *r, const char *dec_path, int write_access)
Definition mhttpd.cxx:6803
void send_icon(Return *r, const char *icon)
Definition mhttpd.cxx:12201
static BOOL elog_mode
Definition mhttpd.cxx:94
void Lock(RequestTrace *t)
Definition mhttpd.cxx:12253
void show_set_page(Param *pp, Return *r, const char *group, int index, const char *value)
Definition mhttpd.cxx:7443
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:13249
#define DELETE(x)
Definition mhttpd.cxx:8245
void show_hist_config_page(MVOdb *odb, Param *p, Return *r, const char *hgroup, const char *hpanel)
Definition mhttpd.cxx:10529
static const std::string find_cookie_mg(const struct http_message *msg, const char *cookie_name)
Definition mhttpd.cxx:14171
void do_jrpc(Param *p, Return *r)
Definition mhttpd.cxx:4325
const unsigned char favicon_ico[]
Definition mhttpd.cxx:282
void init_mhttpd_odb(MVOdb *odb)
Definition mhttpd.cxx:1933
void check_obsolete_odb(HNDLE hDB, const char *odb_path)
Definition mhttpd.cxx:1883
void do_jrpc_rev1(Param *p, Return *r)
Definition mhttpd.cxx:4144
static RequestTraceBuf * gTraceBuf
Definition mhttpd.cxx:506
const char * mhttpd_revision(void)
Definition mhttpd.cxx:836
void show_hist_page(MVOdb *odb, Param *p, Return *r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
Definition mhttpd.cxx:11274
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:14274
void gen_odb_attachment(Return *r, const char *path, std::string &bout)
Definition mhttpd.cxx:2137
#define RESPONSE_SENT
Definition mhttpd.cxx:14270
bool open_resource_file(const char *filename, std::string *ppath, FILE **pfp)
Definition mhttpd.cxx:1031
void redirect_307(Return *r, const char *path)
Definition mhttpd.cxx:1433
static std::string GetMimetype(const std::string &ext)
Definition mhttpd.cxx:181
static double GetTimeSec()
Definition mhttpd.cxx:376
void show_custom_page(Param *pp, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:5430
static MJsonNode * set_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16213
const bool cmp_tags(const TAG &a, const TAG &b)
Definition mhttpd.cxx:10053
const bool cmp_events1(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10048
#define READ_HISTORY_LAST_WRITTEN
Definition mhttpd.cxx:8332
int read_history(const HistPlot &hp, int index, int flags, time_t tstart, time_t tend, time_t scale, HistoryData *data)
Definition mhttpd.cxx:8366
static std::string toString(int i)
Definition mhttpd.cxx:57
const MimetypeTableEntry gMimetypeTable[]
Definition mhttpd.cxx:130
int time_to_sec(const char *str)
Definition mhttpd.cxx:8102
static BOOL verbose
Definition mhttpd.cxx:96
void show_help_page(Return *r, const char *dec_path)
Definition mhttpd.cxx:1542
void do_jrpc_rev0(Param *p, Return *r)
Definition mhttpd.cxx:4019
INT search_callback(HNDLE hDB, HNDLE hKey, KEY *key, INT level, void *info)
Definition mhttpd.cxx:1459
void init_menu_buttons(MVOdb *odb)
Definition mhttpd.cxx:1892
std::atomic_bool _abort
Definition mhttpd.cxx:13467
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:8614
#define ALLOC(t, n)
Definition mhttpd.cxx:8244
static const char * cgif_label_str[]
Definition mhttpd.cxx:3433
time_t mktime_with_dst(const struct tm *ptms)
Definition mhttpd.cxx:9755
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:13655
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:11035
#define STRDUP(x)
Definition mhttpd.cxx:8247
static int http_trace
Definition mhttpd.cxx:435
static void xmg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
Definition mhttpd.cxx:13803
void interprete(Param *p, Return *r, Attachment *a, const Cookies *c, const char *dec_path, RequestTrace *t)
Definition mhttpd.cxx:12267
static const char default_system_list[20][NAME_LENGTH]
Definition mhttpd.cxx:116
static void handle_http_options_cors(struct mg_connection *nc, const http_message *msg, RequestTrace *t)
Definition mhttpd.cxx:15026
#define DELETEA(x, n)
Definition mhttpd.cxx:8246
static Auth * gAuthMg
Definition mhttpd.cxx:13769
static void SortHistPlotVars(HistPlot &hp)
Definition mhttpd.cxx:10508
const bool cmp_events(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10043
int xdb_get_data_index(HNDLE hDB, const char *str, void *value, int size, int index, int tid)
Definition mhttpd.cxx:10072
void show_error_404(Return *r, const char *error)
Definition mhttpd.cxx:1856
static void handle_http_message(struct mg_connection *nc, http_message *msg)
Definition mhttpd.cxx:15096
static int xdb_find_key(HNDLE hDB, HNDLE dir, const char *str, HNDLE *hKey, int tid, int size)
Definition mhttpd.cxx:10088
static void AddHistPlotSelectedParam(HistPlot &hp, Param *p)
Definition mhttpd.cxx:10387
void show_custom_gif(Return *rr, const char *name)
Definition mhttpd.cxx:3677
static void LoadHistPlotFromOdb(MVOdb *odb, HistPlot *hp, const char *group, const char *panel)
Definition mhttpd.cxx:10205
static bool trace_mg_recv
Definition mhttpd.cxx:13722
static int NextHistPlotOrder(const HistPlot &hp)
Definition mhttpd.cxx:10152
#define TEXT_SIZE
Definition mhttpd.cxx:699
bool ends_with_char(const std::string &s, char c)
Definition midas.cxx:412
std::string msprintf(const char *format,...)
Definition midas.cxx:419
#define DIR_SEPARATOR
Definition midas.h:193
INT HNDLE
Definition midas.h:132
#define M_MALLOC(x)
Definition midas.h:1550
#define RPC_OUT
Definition midas.h:1579
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
#define RPC_IN
Definition midas.h:1578
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define RPC_MAX_ID
Definition midas.h:1605
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:1552
#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:1111
#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:1408
#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:13733
std::string password
Definition mhttpd.cxx:13736
std::string username
Definition mhttpd.cxx:13734
std::string realm
Definition mhttpd.cxx:13735
double max
Definition mhttpd.cxx:3494
BOOL logscale
Definition mhttpd.cxx:3493
char format[32]
Definition mhttpd.cxx:3447
char src[256]
Definition mhttpd.cxx:3446
char bgcolor[8]
Definition mhttpd.cxx:3451
char font[32]
Definition mhttpd.cxx:3448
char fgcolor[8]
Definition mhttpd.cxx:3450
std::string cookie_pwd
Definition mhttpd.cxx:12244
int refresh
Definition mhttpd.cxx:12247
std::string cookie_wpwd
Definition mhttpd.cxx:12245
std::string cookie_cpwd
Definition mhttpd.cxx:12246
std::string timescale
Definition mhttpd.cxx:8350
bool enable_factor
Definition mhttpd.cxx:8359
bool show_fill
Definition mhttpd.cxx:8357
double minimum
Definition mhttpd.cxx:8351
double maximum
Definition mhttpd.cxx:8352
bool show_factor
Definition mhttpd.cxx:8358
bool zero_ylow
Definition mhttpd.cxx:8353
bool show_values
Definition mhttpd.cxx:8356
bool log_axis
Definition mhttpd.cxx:8354
std::vector< HistVar > vars
Definition mhttpd.cxx:8361
bool show_run_markers
Definition mhttpd.cxx:8355
double factor
Definition mhttpd.cxx:8343
std::string tag_name
Definition mhttpd.cxx:8337
double offset
Definition mhttpd.cxx:8344
int order
Definition mhttpd.cxx:8342
std::string formula
Definition mhttpd.cxx:8338
std::string label
Definition mhttpd.cxx:8340
double voffset
Definition mhttpd.cxx:8345
std::string colour
Definition mhttpd.cxx:8339
std::string event_name
Definition mhttpd.cxx:8336
bool show_raw_value
Definition mhttpd.cxx:8341
int * odb_index
Definition mhttpd.cxx:8256
time_t tstart
Definition mhttpd.cxx:8265
void Free()
Definition mhttpd.cxx:8287
int alloc_nvars
Definition mhttpd.cxx:8252
void Allocate(int xnvars)
Definition mhttpd.cxx:8269
time_t tend
Definition mhttpd.cxx:8266
double ** v
Definition mhttpd.cxx:8260
void Print() const
Definition mhttpd.cxx:8302
time_t ** t
Definition mhttpd.cxx:8259
char ** var_names
Definition mhttpd.cxx:8254
int * var_index
Definition mhttpd.cxx:8255
char ** event_names
Definition mhttpd.cxx:8253
int * status
Definition mhttpd.cxx:8257
bool have_last_written
Definition mhttpd.cxx:8262
time_t * last_written
Definition mhttpd.cxx:8263
int * num_entries
Definition mhttpd.cxx:8258
time_t scale
Definition mhttpd.cxx:8267
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:125
std::string mimetype
Definition mhttpd.cxx:127
std::string ext
Definition mhttpd.cxx:126
Definition midas.h:1232
char name[NAME_LENGTH]
Definition midas.h:1233
Definition mgd.h:58
Definition mgd.h:120
Return * r
Definition mhttpd.cxx:1455
const char * search_name
Definition mhttpd.cxx:1456
double d
Definition system.cxx:1313
char c
Definition system.cxx:1312
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