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++) {
75 attachment_buffer[i] = NULL;
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]);
90 attachment_buffer[i] = NULL;
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
179static MVOdb* gMimeTypesOdb = NULL;
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, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
222 0x61, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59,
223 0x73, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
224 0xa0, 0x01, 0x5d, 0x7e, 0xbb, 0xa3, 0x00, 0x00,
225 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f,
226 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77,
227 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63,
228 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b,
229 0xee, 0x3c, 0x1a, 0x00, 0x00, 0x01, 0xab, 0x49,
230 0x44, 0x41, 0x54, 0x38, 0x8d, 0x95, 0x92, 0x3d,
231 0x68, 0x14, 0x61, 0x10, 0x86, 0x9f, 0xf9, 0x76,
232 0xef, 0x27, 0x26, 0x5b, 0x28, 0xb1, 0x31, 0x55,
233 0x0a, 0x15, 0xce, 0xbd, 0x58, 0x1c, 0x36, 0x36,
234 0x62, 0xe3, 0x1d, 0x88, 0x4a, 0x2e, 0xb9, 0x2b,
235 0x2c, 0xc4, 0x46, 0x2b, 0x5b, 0x2b, 0xd1, 0x3a,
236 0xbd, 0x85, 0x68, 0x95, 0x80, 0x8d, 0xb7, 0x47,
237 0x40, 0x21, 0xf1, 0x12, 0x41, 0x22, 0x16, 0x42,
238 0x10, 0x8b, 0xf5, 0x12, 0x4d, 0xa7, 0x58, 0xab,
239 0x88, 0x8a, 0x3f, 0x7b, 0x3b, 0x63, 0x11, 0x02,
240 0x2a, 0xb7, 0x97, 0xdc, 0xc0, 0x54, 0xf3, 0xce,
241 0xc3, 0xfb, 0x0e, 0x83, 0x99, 0x91, 0xd5, 0xd3,
242 0xcb, 0xf1, 0xa9, 0xf3, 0x0f, 0xdf, 0x06, 0x83,
243 0x34, 0x8e, 0x8c, 0xaa, 0x77, 0xba, 0x75, 0x4f,
244 0xa4, 0x9d, 0x2b, 0x24, 0xcf, 0x2f, 0x3c, 0xda,
245 0x0a, 0xb2, 0x74, 0x7d, 0x01, 0x33, 0x9d, 0x8d,
246 0x13, 0x4e, 0xb8, 0x67, 0x30, 0x8e, 0x11, 0xe6,
247 0xf2, 0xc9, 0xd3, 0xa1, 0x00, 0xde, 0xd7, 0xcd,
248 0x57, 0x18, 0x2f, 0x11, 0x7e, 0x02, 0x1f, 0x55,
249 0xdd, 0xcd, 0x2c, 0x80, 0x98, 0x59, 0xdf, 0x41,
250 0x33, 0x8a, 0x3c, 0x0d, 0x4a, 0x5d, 0x4d, 0xed,
251 0xc6, 0xe2, 0xd9, 0x70, 0x71, 0x28, 0x07, 0x00,
252 0xad, 0x46, 0x23, 0x15, 0xec, 0x81, 0x25, 0xbd,
253 0x4c, 0xfb, 0x03, 0x01, 0xdb, 0xa5, 0xf9, 0xdc,
254 0x48, 0x7e, 0xa0, 0xa6, 0x6f, 0x84, 0x66, 0xf4,
255 0x62, 0x44, 0x83, 0xe0, 0x9a, 0xc0, 0x11, 0xc5,
256 0x7c, 0x4f, 0xbc, 0x3b, 0xad, 0x6a, 0x69, 0x7d,
257 0xcf, 0x0e, 0x34, 0x08, 0xe6, 0x80, 0x95, 0xa8,
258 0x16, 0x5e, 0x19, 0x3f, 0xf8, 0xfb, 0xaa, 0xa2,
259 0x97, 0x67, 0x9f, 0xbc, 0x39, 0x3c, 0x54, 0x84,
260 0x76, 0x2d, 0x8c, 0x01, 0xee, 0x56, 0x2a, 0x89,
261 0x99, 0x74, 0xb1, 0x9e, 0xb7, 0x27, 0xc0, 0xa5,
262 0xd5, 0x78, 0x14, 0x98, 0xac, 0xaf, 0xc6, 0x21,
263 0xc0, 0xe9, 0xb5, 0x35, 0x5f, 0xc4, 0x2a, 0xa2,
264 0xb9, 0x52, 0x3f, 0xc0, 0x3f, 0x37, 0x98, 0x7d,
265 0xbc, 0x71, 0xce, 0xb0, 0xe9, 0x3c, 0xee, 0x76,
266 0x8f, 0xf4, 0x0c, 0x22, 0x13, 0x86, 0x04, 0x42,
267 0xb2, 0xa0, 0xe6, 0x97, 0x45, 0x6c, 0xd2, 0x15,
268 0xbd, 0x5b, 0xf6, 0x23, 0x39, 0x69, 0xf8, 0x85,
269 0xf2, 0xfa, 0xb1, 0x25, 0x99, 0x59, 0x7e, 0xfd,
270 0x1e, 0xcc, 0x33, 0x71, 0x22, 0xa4, 0xcf, 0xda,
271 0xb5, 0xa9, 0x8b, 0x3b, 0xc0, 0xe6, 0xca, 0xe6,
272 0x81, 0xa8, 0x5a, 0xfa, 0x6c, 0x60, 0x00, 0xcd,
273 0x4e, 0x7c, 0x54, 0x8d, 0x05, 0xc4, 0x95, 0x01,
274 0x87, 0xb0, 0xe4, 0x10, 0x53, 0x44, 0x26, 0x04,
275 0x3b, 0x84, 0xb8, 0x2f, 0x7f, 0xdb, 0x6b, 0x55,
276 0x4b, 0x9f, 0x76, 0x96, 0x01, 0x5a, 0xb5, 0xa9,
277 0x2d, 0x9c, 0x1b, 0x05, 0xf6, 0x01, 0x45, 0x8c,
278 0xe3, 0x4e, 0x4c, 0x76, 0xf9, 0x85, 0xff, 0x32,
279 0xc3, 0x3b, 0x81, 0x14, 0x50, 0x84, 0x0f, 0xbe,
280 0x39, 0x99, 0x17, 0xd3, 0xfd, 0xdb, 0x43, 0xbd,
281 0xbf, 0x1b, 0x60, 0xac, 0x30, 0xd6, 0xf8, 0xf6,
282 0xeb, 0xfb, 0x75, 0x55, 0x2b, 0xf8, 0x45, 0x37,
283 0xf7, 0x07, 0x3b, 0x67, 0xc6, 0x0c, 0xa4, 0x18,
284 0xfd, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
285 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
286};
287
288const unsigned char favicon_ico[] = {
289 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10,
290 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xe4, 0x01,
291 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x89, 0x50,
292 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
293 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
294 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06,
295 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00,
296 0x00, 0x01, 0xab, 0x49, 0x44, 0x41, 0x54, 0x78,
297 0x9c, 0x95, 0x92, 0x3d, 0x68, 0x14, 0x61, 0x10,
298 0x86, 0x9f, 0xf9, 0x76, 0xef, 0x27, 0x26, 0x5b,
299 0x28, 0xb1, 0x31, 0x55, 0x0a, 0x15, 0xce, 0xbd,
300 0x58, 0x1c, 0x36, 0x36, 0x62, 0xe3, 0x1d, 0x88,
301 0x4a, 0x2e, 0xb9, 0x2b, 0x2c, 0xc4, 0x46, 0x2b,
302 0x5b, 0x2b, 0xd1, 0x3a, 0xbd, 0x85, 0x68, 0x95,
303 0x80, 0x8d, 0xb7, 0x47, 0x40, 0x21, 0xf1, 0x12,
304 0x41, 0x22, 0x16, 0x42, 0x10, 0x8b, 0xf5, 0x12,
305 0x4d, 0xa7, 0x58, 0xab, 0x88, 0x8a, 0x3f, 0x7b,
306 0x3b, 0x63, 0x11, 0x02, 0x2a, 0xb7, 0x97, 0xdc,
307 0xc0, 0x54, 0xf3, 0xce, 0xc3, 0xfb, 0x0e, 0x83,
308 0x99, 0x91, 0xd5, 0xd3, 0xcb, 0xf1, 0xa9, 0xf3,
309 0x0f, 0xdf, 0x06, 0x83, 0x34, 0x8e, 0x8c, 0xaa,
310 0x77, 0xba, 0x75, 0x4f, 0xa4, 0x9d, 0x2b, 0x24,
311 0xcf, 0x2f, 0x3c, 0xda, 0x0a, 0xb2, 0x74, 0x7d,
312 0x01, 0x33, 0x9d, 0x8d, 0x13, 0x4e, 0xb8, 0x67,
313 0x30, 0x8e, 0x11, 0xe6, 0xf2, 0xc9, 0xd3, 0xa1,
314 0x00, 0xde, 0xd7, 0xcd, 0x57, 0x18, 0x2f, 0x11,
315 0x7e, 0x02, 0x1f, 0x55, 0xdd, 0xcd, 0x2c, 0x80,
316 0x98, 0x59, 0xdf, 0x41, 0x33, 0x8a, 0x3c, 0x0d,
317 0x4a, 0x5d, 0x4d, 0xed, 0xc6, 0xe2, 0xd9, 0x70,
318 0x71, 0x28, 0x07, 0x00, 0xad, 0x46, 0x23, 0x15,
319 0xec, 0x81, 0x25, 0xbd, 0x4c, 0xfb, 0x03, 0x01,
320 0xdb, 0xa5, 0xf9, 0xdc, 0x48, 0x7e, 0xa0, 0xa6,
321 0x6f, 0x84, 0x66, 0xf4, 0x62, 0x44, 0x83, 0xe0,
322 0x9a, 0xc0, 0x11, 0xc5, 0x7c, 0x4f, 0xbc, 0x3b,
323 0xad, 0x6a, 0x69, 0x7d, 0xcf, 0x0e, 0x34, 0x08,
324 0xe6, 0x80, 0x95, 0xa8, 0x16, 0x5e, 0x19, 0x3f,
325 0xf8, 0xfb, 0xaa, 0xa2, 0x97, 0x67, 0x9f, 0xbc,
326 0x39, 0x3c, 0x54, 0x84, 0x76, 0x2d, 0x8c, 0x01,
327 0xee, 0x56, 0x2a, 0x89, 0x99, 0x74, 0xb1, 0x9e,
328 0xb7, 0x27, 0xc0, 0xa5, 0xd5, 0x78, 0x14, 0x98,
329 0xac, 0xaf, 0xc6, 0x21, 0xc0, 0xe9, 0xb5, 0x35,
330 0x5f, 0xc4, 0x2a, 0xa2, 0xb9, 0x52, 0x3f, 0xc0,
331 0x3f, 0x37, 0x98, 0x7d, 0xbc, 0x71, 0xce, 0xb0,
332 0xe9, 0x3c, 0xee, 0x76, 0x8f, 0xf4, 0x0c, 0x22,
333 0x13, 0x86, 0x04, 0x42, 0xb2, 0xa0, 0xe6, 0x97,
334 0x45, 0x6c, 0xd2, 0x15, 0xbd, 0x5b, 0xf6, 0x23,
335 0x39, 0x69, 0xf8, 0x85, 0xf2, 0xfa, 0xb1, 0x25,
336 0x99, 0x59, 0x7e, 0xfd, 0x1e, 0xcc, 0x33, 0x71,
337 0x22, 0xa4, 0xcf, 0xda, 0xb5, 0xa9, 0x8b, 0x3b,
338 0xc0, 0xe6, 0xca, 0xe6, 0x81, 0xa8, 0x5a, 0xfa,
339 0x6c, 0x60, 0x00, 0xcd, 0x4e, 0x7c, 0x54, 0x8d,
340 0x05, 0xc4, 0x95, 0x01, 0x87, 0xb0, 0xe4, 0x10,
341 0x53, 0x44, 0x26, 0x04, 0x3b, 0x84, 0xb8, 0x2f,
342 0x7f, 0xdb, 0x6b, 0x55, 0x4b, 0x9f, 0x76, 0x96,
343 0x01, 0x5a, 0xb5, 0xa9, 0x2d, 0x9c, 0x1b, 0x05,
344 0xf6, 0x01, 0x45, 0x8c, 0xe3, 0x4e, 0x4c, 0x76,
345 0xf9, 0x85, 0xff, 0x32, 0xc3, 0x3b, 0x81, 0x14,
346 0x50, 0x84, 0x0f, 0xbe, 0x39, 0x99, 0x17, 0xd3,
347 0xfd, 0xdb, 0x43, 0xbd, 0xbf, 0x1b, 0x60, 0xac,
348 0x30, 0xd6, 0xf8, 0xf6, 0xeb, 0xfb, 0x75, 0x55,
349 0x2b, 0xf8, 0x45, 0x37, 0xf7, 0x07, 0x3b, 0x67,
350 0xc6, 0x0c, 0xb9, 0x56, 0xe3, 0x39, 0x00, 0x00,
351 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
352 0x60, 0x82
353};
354
355/*------------------------------------------------------------------*/
356
357class Param;
358class Return;
359void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh);
360int vaxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
361 int minor, int major, int text, int label, int grid, double ymin, double ymax,
362 BOOL logaxis);
363void haxis(gdImagePtr im, gdFont * font, int col, int gcol, int x1, int y1, int width,
364 int minor, int major, int text, int label, int grid, double xmin, double xmax);
365void get_elog_url(char *url, int len);
366void show_header(Return* r, const char *title, const char *method, const char *path, int refresh);
367void show_navigation_bar(Return* r, const char *cur_page);
368
369/*------------------------------------------------------------------*/
370
371char *stristr(const char *str, const char *pattern)
372{
373 char c1, c2, *ps, *pp;
374
375 if (str == NULL || pattern == NULL)
376 return NULL;
377
378 while (*str) {
379 ps = (char *) str;
380 pp = (char *) pattern;
381 c1 = *ps;
382 c2 = *pp;
383 if (toupper(c1) == toupper(c2)) {
384 while (*pp) {
385 c1 = *ps;
386 c2 = *pp;
387
388 if (toupper(c1) != toupper(c2))
389 break;
390
391 ps++;
392 pp++;
393 }
394
395 if (!*pp)
396 return (char *) str;
397 }
398 str++;
399 }
400
401 return NULL;
402}
403
404/*------------------------------------------------------------------*/
405
406static double GetTimeSec()
407{
408 struct timeval tv;
409 gettimeofday(&tv, NULL);
410 return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
411}
412
413/*------------------------------------------------------------------*/
414
416{
417public:
418 double fTimeReceived; // time request received
419 double fTimeLocked; // time lock is taken
420 double fTimeUnlocked; // time lock is released
421 double fTimeProcessed; // time processing of request is done
422 double fTimeSent; // time sending the request is done
423 bool fCompleted; // flag the request completed, it's RequestTrace is safe to delete
424 std::string fMethod; // request HTTP method
425 std::string fUri; // request URL/URI
426 std::string fQuery; // request query string
427 std::string fRPC; // request RPC
428 std::string fResource; // request file resource, with full path
429 bool fAuthOk; // password check passed
430
431public:
432 RequestTrace() // ctor
433 {
434 fTimeReceived = 0;
435 fTimeLocked = 0;
436 fTimeUnlocked = 0;
437 fTimeProcessed = 0;
438 fTimeSent = 0;
439 fCompleted = false;
440 fAuthOk = false;
441 }
442
443 void PrintTrace0() const
444 {
445 printf("%.3f ", fTimeReceived);
446 printf("%.3f ", fTimeLocked-fTimeReceived);
447 printf("%.3f ", fTimeUnlocked-fTimeLocked);
448 printf("%.3f ", fTimeProcessed-fTimeUnlocked);
449 printf("%.3f ", fTimeSent-fTimeProcessed);
450 printf("A ");
451 printf("%d ", fAuthOk);
452 printf("T ");
453 printf("%.3f ", fTimeSent-fTimeReceived);
454 printf("%.3f ", fTimeLocked-fTimeReceived);
455 printf("%.3f ", fTimeProcessed-fTimeLocked);
456 printf("M %s ", fMethod.c_str());
457 printf("URL %s ", fUri.c_str());
458 if (fRPC.length() > 0) {
459 printf("RPC %s ", fRPC.c_str());
460 }
461 printf("\n");
462 };
463};
464
465static int http_trace = 0;
466
468{
469public:
471 std::vector<RequestTrace*> fBuf;
472
473public:
475 {
476 int status;
478 assert(status==SS_SUCCESS || status==SS_CREATED);
479 }
480
481 //RequestTrace* NewTrace() // RequestTrace factory
482 //{
483 // RequestTrace* t = new RequestTrace;
484 // fBuf.push_back(t);
485 // return t;
486 //}
487
489 {
490 fBuf.push_back(t);
491 }
492
494 {
496 if (http_trace) {
497 t->PrintTrace0();
498 }
499 delete t;
500 //AddTrace(t);
502 }
503
504 void Clear() // clear all completed requests
505 {
506 // delete all completed requests
507 for (unsigned i=0; i<fBuf.size(); i++) {
508 if (fBuf[i] && fBuf[i]->fCompleted) {
509 delete fBuf[i];
510 fBuf[i] = NULL;
511 }
512 }
513
514 // compact all non-completed requests
515 unsigned k = 0;
516 for (unsigned i=0; i<fBuf.size(); i++) {
517 if (fBuf[i]) {
518 if (fBuf[k] != NULL) {
519 for (; k<i; k++) {
520 if (fBuf[k] == NULL) {
521 break;
522 }
523 }
524 }
525 // if we found an empty spot between "k" and "i" move "i" there
526 // if there is no empty spot, then "i" does not need to be moved
527 if (fBuf[k] == NULL) {
528 fBuf[k] = fBuf[i];
529 fBuf[i] = NULL;
530 }
531 }
532 }
533 }
534};
535
537
538/*------------------------------------------------------------------*/
539
540/* size of buffer for incoming data, must fit sum of all attachments */
541#define WEB_BUFFER_SIZE (6*1024*1024)
542
544{
545public:
546
549
552
553public:
554 Return() // ctor
555 {
557 return_buffer = (char*)malloc(return_size);
558 assert(return_buffer != NULL);
559
560 strlen_retbuf = 0;
561 return_length = 0;
562 }
563
564 ~Return() // dtor
565 {
566 if (return_buffer)
567 free(return_buffer);
568 return_buffer = NULL;
569 return_size = 0;
570 strlen_retbuf = 0;
571 return_length = 0;
572 }
573
574 void reset()
575 {
576 strlen_retbuf = 0;
577 }
578
579 void zero()
580 {
581 memset(return_buffer, 0, return_size);
582 strlen_retbuf = 0;
583 return_length = 0;
584 }
585
586int return_grow(size_t len)
587{
588 //printf("size %d, grow %d, room %d\n", return_size, len, return_size - strlen_retbuf);
589
590 for (int i=0; i<1000; i++) { // infinite loop with protection against infinite looping
591 if (strlen_retbuf + len < return_size-40)
592 return SUCCESS;
593
594 return_size *= 2;
595 return_buffer = (char*)realloc(return_buffer, return_size);
596
598
599 //printf("new size %d\n", return_size);
600 }
601
602 assert(!"Cannot happen!"); // does not return
603 return 0;
604}
605
606/*------------------------------------------------------------------*/
607
608void rmemcpy(const void *buf, int len)
609{
610 return_grow(len);
611 memcpy(return_buffer + strlen_retbuf, buf, len);
612 strlen_retbuf += len;
614}
615
616/*------------------------------------------------------------------*/
617
618void rread(const char* filename, int fh, int len)
619{
620 return_grow(len);
621 int rd = read(fh, return_buffer + strlen_retbuf, len);
622 if (rd != len) {
623 cm_msg(MERROR, "rread", "Cannot read file \'%s\', read of %d returned %d, errno %d (%s)", filename, len, rd, errno, strerror(errno));
624 memset(return_buffer + strlen_retbuf, 0, len);
625 }
626 strlen_retbuf += len;
628}
629
630/*------------------------------------------------------------------*/
631
632void rsputs(const char *str)
633{
634 size_t len = strlen(str);
635
636 return_grow(len);
637
638 if (strlen_retbuf + len > return_size-40) {
639 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
641 } else {
643 strlen_retbuf += len;
644 }
645
647}
648
649/*------------------------------------------------------------------*/
650
651void rsputs2(const char *str)
652{
653 size_t len = strlen(str);
654
655 return_grow(len);
656
657 if (strlen_retbuf + len > return_size) {
658 mstrlcpy(return_buffer, "<H1>Error: return buffer too small</H1>", return_size);
660 } else {
661 int j = strlen_retbuf;
662 for (size_t i = 0; i < len; i++) {
663 if (strncmp(str + i, "http://", 7) == 0) {
664 int k;
665 char link[256];
666 char* p = (char *) (str + i + 7);
667
668 i += 7;
669 for (k = 0; *p && *p != ' ' && *p != '\n'; k++, i++)
670 link[k] = *p++;
671 link[k] = 0;
672
673 sprintf(return_buffer + j, "<a href=\"http://%s\">http://%s</a>", link, link);
674 j += strlen(return_buffer + j);
675 } else
676 switch (str[i]) {
677 case '<':
678 mstrlcat(return_buffer, "&lt;", return_size);
679 j += 4;
680 break;
681 case '>':
682 mstrlcat(return_buffer, "&gt;", return_size);
683 j += 4;
684 break;
685 default:
686 return_buffer[j++] = str[i];
687 }
688 }
689
690 return_buffer[j] = 0;
692 }
693
695}
696
697/*------------------------------------------------------------------*/
698
699void rsprintf(const char *format, ...) MATTRPRINTF(2,3)
700{
701 va_list argptr;
702 char str[10000];
703
704 va_start(argptr, format);
705 vsprintf(str, (char *) format, argptr);
706 va_end(argptr);
707
708 // catch array overrun. better too late than never...
709 assert(strlen(str) < sizeof(str));
710
711 return_grow(strlen(str));
712
714 strcpy(return_buffer, "<H1>Error: return buffer too small</H1>");
715 else
717
718 strlen_retbuf += strlen(str);
720}
721};
722
723/*------------------------------------------------------------------*/
724
725/* Parameter handling functions similar to setenv/getenv */
726
727#define MAX_PARAM 500
728#define PARAM_LENGTH 256
729#define TEXT_SIZE 50000
730
731class Param
732{
733public:
737
738public:
739 Param() // ctor
740 {
741 initparam();
742 }
743
744 ~Param() // dtor
745 {
746 freeparam();
747 }
748
750 {
751 memset(_param, 0, sizeof(_param));
752 memset(_value, 0, sizeof(_value));
753 _text[0] = 0;
754 }
755
756 void setparam(const char *param, const char *value)
757 {
758 int i;
759
760 if (equal_ustring(param, "text")) {
761 if (strlen(value) >= TEXT_SIZE)
762 printf("Error: parameter value too big\n");
763
764 mstrlcpy(_text, value, TEXT_SIZE);
765 _text[TEXT_SIZE - 1] = 0;
766 return;
767 }
768
769 for (i = 0; i < MAX_PARAM; i++)
770 if (_param[i][0] == 0)
771 break;
772
773 if (i < MAX_PARAM) {
774 mstrlcpy(_param[i], param, PARAM_LENGTH);
775
776 int size = strlen(value)+1;
777 _value[i] = (char*)malloc(size);
778 mstrlcpy(_value[i], value, size);
779 _value[i][strlen(value)] = 0;
780
781 } else {
782 printf("Error: parameter array too small\n");
783 }
784 }
785
787 {
788 int i;
789
790 for (i=0 ; i<MAX_PARAM ; i++)
791 if (_value[i] != NULL) {
792 free(_value[i]);
793 _value[i] = NULL;
794 }
795 }
796
798 {
799 int i;
800
801 for (i = 0; i < MAX_PARAM && _param[i][0]; i++) {
802 printf("param %d name [%s] value [%s]\n", i, _param[i], _value[i]);;
803 }
804 }
805
806 const char *getparam(const char *param)
807 {
808 int i;
809
810 if (equal_ustring(param, "text"))
811 return _text;
812
813 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
815 break;
816
817 if (i == MAX_PARAM)
818 return NULL;
819
820 if (_value[i] == NULL)
821 return "";
822
823 return _value[i];
824 }
825
826 std::string xgetparam(const char *param)
827 {
828 const char* s = getparam(param);
829 if (s)
830 return s;
831 else
832 return "";
833 }
834
835 BOOL isparam(const char *param)
836 {
837 int i;
838
839 for (i = 0; i < MAX_PARAM && _param[i][0]; i++)
841 break;
842
843 if (i < MAX_PARAM && _param[i][0])
844 return TRUE;
845
846 return FALSE;
847 }
848
849 void unsetparam(const char *param)
850 {
851 int i;
852
853 for (i = 0; i < MAX_PARAM; i++)
855 break;
856
857 if (i < MAX_PARAM) {
858 _param[i][0] = 0;
859 _value[i][0] = 0;
860 }
861 }
862};
863
864/*------------------------------------------------------------------*/
865
866const char *mhttpd_revision(void)
867{
868 return cm_get_revision();
869}
870
871/*------------------------------------------------------------------*/
872
873static std::string UrlDecode(const char* p)
874/********************************************************************\
875 Decode the given string in-place by expanding %XX escapes
876\********************************************************************/
877{
878 std::string s;
879
880 //printf("URL decode: [%s] --> ", p);
881
882 while (*p) {
883 if (*p == '%') {
884 /* Escape: next 2 chars are hex representation of the actual character */
885 p++;
886 if (isxdigit(p[0]) && isxdigit(p[1])) {
887 int i = 0;
888 char str[3];
889 str[0] = p[0];
890 str[1] = p[1];
891 str[2] = 0;
892 sscanf(str, "%02X", &i);
893
894 s += (char) i;
895 p += 2;
896 } else
897 s += '%';
898 } else if (*p == '+') {
899 /* convert '+' to ' ' */
900 s += ' ';
901 p++;
902 } else {
903 s += *p++;
904 }
905 }
906
907 //printf("[%s]\n", s.c_str());
908
909 return s;
910}
911
912static void urlDecode(char *p)
913/********************************************************************\
914 Decode the given string in-place by expanding %XX escapes
915\********************************************************************/
916{
917 //char *px = p;
918 char *pD, str[3];
919 int i;
920
921 //printf("URL decode: [%s] --> ", p);
922
923 pD = p;
924 while (*p) {
925 if (*p == '%') {
926 /* Escape: next 2 chars are hex representation of the actual character */
927 p++;
928 if (isxdigit(p[0]) && isxdigit(p[1])) {
929 str[0] = p[0];
930 str[1] = p[1];
931 str[2] = 0;
932 sscanf(str, "%02X", &i);
933
934 *pD++ = (char) i;
935 p += 2;
936 } else
937 *pD++ = '%';
938 } else if (*p == '+') {
939 /* convert '+' to ' ' */
940 *pD++ = ' ';
941 p++;
942 } else {
943 *pD++ = *p++;
944 }
945 }
946 *pD = '\0';
947
948 //printf("[%s]\n", px);
949}
950
951static void urlEncode(char *ps, int ps_size)
952/*
953 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
954 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
955*/
956{
957 char *pd, *p;
958 int len = strlen(ps);
959 char *str = (char*)malloc(len*3 + 10); // at worst, each input character is expanded into 3 output characters
960
961 pd = str;
962 p = ps;
963 while (*p) {
964 if (isalnum(*p)) {
965 *pd++ = *p++;
966 } else {
967 sprintf(pd, "%%%02X", (*p)&0xFF);
968 pd += 3;
969 p++;
970 }
971 }
972 *pd = '\0';
973
974 if (/* DISABLES CODE */ (0)) {
975 printf("urlEncode [");
976 for (p=ps; *p!=0; p++)
977 printf("0x%02x ", (*p)&0xFF);
978 printf("]\n");
979
980 printf("urlEncode [%s] -> [%s]\n", ps, str);
981 }
982
983 mstrlcpy(ps, str, ps_size);
984 free(str);
985}
986
987static std::string urlEncode(const char *text)
988/*
989 Encode mhttpd ODB path for embedding into HTML <a href="?cmd=odb&odb_path=xxx"> elements.
990 Encoding is intended to be compatible with RFC 3986 section 2 (adding of %XX escapes)
991*/
992{
993 std::string encoded;
994
995 const char* p = text;
996 while (*p) {
997 if (isalnum(*p)) {
998 encoded += *p++;
999 } else {
1000 char buf[16];
1001 sprintf(buf, "%%%02X", (*p)&0xFF);
1002 encoded += buf;
1003 p++;
1004 }
1005 }
1006
1007 if (/* DISABLES CODE */ (0)) {
1008 printf("urlEncode [");
1009 for (p=text; *p!=0; p++)
1010 printf("0x%02x ", (*p)&0xFF);
1011 printf("]\n");
1012
1013 printf("urlEncode [%s] -> [%s]\n", text, encoded.c_str());
1014 }
1015
1016 return encoded;
1017}
1018
1019/*------------------------------------------------------------------*/
1020
1021std::vector<std::string> get_resource_paths()
1022{
1023 HNDLE hDB;
1024 int status;
1025
1027
1028 std::vector<std::string> paths;
1029
1030 // add /Experiment/Resources
1031 std::string buf;
1032 status = db_get_value_string(hDB, 0, "/Experiment/Resources", 0, &buf, TRUE);
1033 if (status == DB_SUCCESS && buf.length() > 0)
1034 paths.push_back(buf);
1035
1036 // add "/Logger/History/IMAGE/History dir"
1037 paths.push_back(cm_get_history_path("IMAGE"));
1038
1039 // add /Logger/Data dir
1040 status = db_get_value_string(hDB, 0, "/Logger/Data dir", 0, &buf, TRUE);
1041 if (status == DB_SUCCESS && buf.length() > 0)
1042 paths.push_back(buf);
1043
1044 std::string cwd = ss_getcwd();
1045 if (!cwd.empty()) {
1046 paths.push_back(cwd + "/");
1047 paths.push_back(cwd + "/resources/");
1048 }
1049 paths.push_back(cm_get_path());
1050 paths.push_back(cm_get_path() + "resources/");
1051 char *m = getenv("MIDASSYS");
1052 if (m) {
1053 paths.push_back(std::string(m) + "/resources/");
1054 }
1055
1056 return paths;
1057}
1058
1059/*------------------------------------------------------------------*/
1060
1061bool open_resource_file(const char *filename, std::string* ppath, FILE** pfp)
1062{
1063 // resource file names should not start with a directory separator "/"
1064 // or contain ".." as this will allow them to escape the mhttpd filename "jail"
1065 // by asking file files names like "../../etc/passwd", etc.
1066
1067 if (strlen(filename) < 1) {
1068 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' is too short",
1069 filename);
1070 return false;
1071 }
1072
1073 if (filename[0] == DIR_SEPARATOR) {
1074 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' starting with \'%c\' which is not allowed",
1075 filename, DIR_SEPARATOR);
1076 return false;
1077 }
1078
1079 if (strstr(filename, "..") != NULL) {
1080 cm_msg(MERROR, "open_resource_file", "Invalid resource file name \'%s\' containing \'..\' which is not allowed",
1081 filename);
1082 return false;
1083 }
1084
1085 std::vector<std::string> paths = get_resource_paths();
1086
1087 std::vector<std::string> paths_not_found;
1088
1089 for (unsigned i=0; i<paths.size(); i++) {
1090 std::string path = paths[i];
1091 if (path.length() < 1)
1092 continue;
1093 if (path[0] == '#')
1094 continue;
1095
1096 // expand env.variables before we add the filename.
1097 // the filename comes from the URL and if the URL
1098 // has '$' characters we will try to expand them
1099 // as an env.variable and maybe escape the file jail.
1100
1101 std::string xpath = cm_expand_env(path.c_str());
1102
1103 if (xpath[xpath.length()-1] != DIR_SEPARATOR)
1104 xpath += DIR_SEPARATOR_STR;
1105 xpath += filename;
1106
1107 //printf("path [%s] [%s] [%s]\n", paths[i].c_str(), path.c_str(), xpath.c_str());
1108
1109 FILE* fp = fopen(xpath.c_str(), "r");
1110 if (fp) {
1111 struct stat statbuf;
1112 int status = fstat(fileno(fp), &statbuf);
1113 if (status != 0) {
1114 cm_msg(MERROR, "open_resource_file", "Cannot fstat() file \'%s\', error %d (%s)", xpath.c_str(), errno, strerror(errno));
1115 fclose(fp);
1116 fp = NULL;
1117 }
1118
1119 if (statbuf.st_mode & S_IFREG) {
1120 // good, normal file
1121 //printf("%s: regular!\n", xpath.c_str());
1122 //} else if (statbuf.st_mode & S_IFLNK) {
1123 // symlink
1124 //printf("%s: symlink!\n", xpath.c_str());
1125 } else if (statbuf.st_mode & S_IFDIR) {
1126 cm_msg(MERROR, "open_resource_file", "File \'%s\' for resource \'%s\' is a directory", xpath.c_str(), filename);
1127 fclose(fp);
1128 fp = NULL;
1129 } else {
1130 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);
1131 fclose(fp);
1132 fp = NULL;
1133 }
1134
1135 if (fp) {
1136 if (ppath)
1137 *ppath = xpath;
1138 if (pfp) {
1139 *pfp = fp;
1140 } else {
1141 fclose(fp);
1142 fp = NULL;
1143 }
1144 //cm_msg(MINFO, "open_resource_file", "Resource file \'%s\' is \'%s\'", filename, xpath.c_str());
1145 return true;
1146 }
1147 }
1148
1149 paths_not_found.push_back(xpath);
1150 }
1151
1152 std::string s;
1153 for (unsigned i=0; i<paths_not_found.size(); i++) {
1154 if (i>0)
1155 s += ", ";
1156 s += paths_not_found[i];
1157 }
1158
1159 cm_msg(MERROR, "open_resource_file", "Cannot find resource file \'%s\', tried %s", filename, s.c_str());
1160 return false;
1161}
1162
1163/*------------------------------------------------------------------*/
1164
1165std::string get_content_type(const char* filename)
1166{
1167 std::string ext_upper;
1168 const char* p = filename;
1169 const char* last_dot = NULL;
1170 for (; *p; p++) {
1171 if (*p == '.')
1172 last_dot = p;
1173 if (*p == DIR_SEPARATOR)
1174 last_dot = NULL;
1175 }
1176
1177 if (last_dot) {
1178 p = last_dot;
1179 for (; *p; p++)
1180 ext_upper += toupper(*p);
1181 }
1182
1183 //printf("filename: [%s], ext [%s]\n", filename, ext_upper.c_str());
1184
1185 std::string type = GetMimetype(ext_upper);
1186 if (type.length() > 0)
1187 return type;
1188
1189 cm_msg(MERROR, "get_content_type", "Unknown HTTP Content-Type for resource file \'%s\', file extension \'%s\'", filename, ext_upper.c_str());
1190
1191 return "text/plain";
1192}
1193
1194/*------------------------------------------------------------------*/
1195
1196bool send_fp(Return* r, const std::string& path, FILE* fp)
1197{
1198 assert(fp != NULL);
1199
1200 // send HTTP headers
1201
1202 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1203 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1204 r->rsprintf("Accept-Ranges: bytes\r\n");
1205
1206 // send HTTP cache control headers
1207
1208 time_t now = time(NULL);
1209 now += (int) (3600 * 24);
1210 struct tm gmt_tms;
1211 gmtime_r(&now, &gmt_tms);
1212 const char* format = "%A, %d-%b-%y %H:%M:%S GMT";
1213
1214 char str[256];
1215 strftime(str, sizeof(str), format, &gmt_tms);
1216 r->rsprintf("Expires: %s\r\n", str);
1217
1218 // send Content-Type header
1219
1220 r->rsprintf("Content-Type: %s\r\n", get_content_type(path.c_str()).c_str());
1221
1222 // send Content-Length header
1223
1224 struct stat stat_buf;
1225 fstat(fileno(fp), &stat_buf);
1226 int length = stat_buf.st_size;
1227 r->rsprintf("Content-Length: %d\r\n", length);
1228
1229 // send end of headers
1230
1231 r->rsprintf("\r\n");
1232
1233 // send file data
1234
1235 r->rread(path.c_str(), fileno(fp), length);
1236
1237 fclose(fp);
1238
1239 return true;
1240}
1241
1242bool send_file(Return* r, const std::string& path, bool generate_404 = true)
1243{
1244 FILE *fp = fopen(path.c_str(), "rb");
1245
1246 if (!fp) {
1247 if (generate_404) {
1248 /* header */
1249 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1250 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1251 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1252 r->rsprintf("\r\n");
1253 r->rsprintf("Error: Cannot read \"%s\", fopen() errno %d (%s)\n", path.c_str(), errno, strerror(errno));
1254 }
1255 return false;
1256 }
1257
1258 return send_fp(r, path, fp);
1259}
1260
1261bool send_resource(Return* r, const std::string& name, bool generate_404 = true)
1262{
1263 std::string path;
1264 FILE *fp = NULL;
1265
1266 bool found = open_resource_file(name.c_str(), &path, &fp);
1267
1268 if (!found) {
1269 if (generate_404) {
1270 /* header */
1271 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1272 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1273 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
1274 r->rsprintf("\r\n");
1275 r->rsprintf("Error: resource file \"%s\" not found, see messages\n", name.c_str());
1276 }
1277 return false;
1278 }
1279
1280 return send_fp(r, path, fp);
1281}
1282
1283/*------------------------------------------------------------------*/
1284
1285INT sendmail(const char* from_host, const char *smtp_host, const char *from, const char *to, const char *subject, const char *text)
1286{
1287 struct sockaddr_in bind_addr;
1288 struct hostent *phe;
1289 int i, s, strsize, offset;
1290 char *str, buf[256];
1291
1292 if (verbose)
1293 printf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
1294
1295 /* create a new socket for connecting to remote server */
1296 s = socket(AF_INET, SOCK_STREAM, 0);
1297 if (s == -1)
1298 return -1;
1299
1300 /* connect to remote node port 25 */
1301 memset(&bind_addr, 0, sizeof(bind_addr));
1302 bind_addr.sin_family = AF_INET;
1303 bind_addr.sin_port = htons((short) 25);
1304
1305 phe = gethostbyname(smtp_host);
1306 if (phe == NULL)
1307 return -1;
1308 memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
1309
1310 if (connect(s, (const sockaddr*)&bind_addr, sizeof(bind_addr)) < 0) {
1311 closesocket(s);
1312 return -1;
1313 }
1314
1315 strsize = TEXT_SIZE + 1000;
1316 str = (char*)malloc(strsize);
1317
1318 assert(str != NULL);
1319
1320 recv_string(s, str, strsize, 3000);
1321 if (verbose)
1322 puts(str);
1323
1324 /* drain server messages */
1325 do {
1326 str[0] = 0;
1327 recv_string(s, str, strsize, 300);
1328 if (verbose)
1329 puts(str);
1330 } while (str[0]);
1331
1332 sprintf(str, "HELO %s\r\n", from_host);
1333 send(s, str, strlen(str), 0);
1334 if (verbose)
1335 puts(str);
1336 recv_string(s, str, strsize, 3000);
1337 if (verbose)
1338 puts(str);
1339
1340 if (strchr(from, '<')) {
1341 mstrlcpy(buf, strchr(from, '<') + 1, sizeof(buf));
1342 if (strchr(buf, '>'))
1343 *strchr(buf, '>') = 0;
1344 } else
1345 mstrlcpy(buf, from, sizeof(buf));
1346
1347 sprintf(str, "MAIL FROM: %s\n", buf);
1348 send(s, str, strlen(str), 0);
1349 if (verbose)
1350 puts(str);
1351 recv_string(s, str, strsize, 3000);
1352 if (verbose)
1353 puts(str);
1354
1355 sprintf(str, "RCPT TO: <%s>\r\n", to);
1356 send(s, str, strlen(str), 0);
1357 if (verbose)
1358 puts(str);
1359 recv_string(s, str, strsize, 3000);
1360 if (verbose)
1361 puts(str);
1362
1363 sprintf(str, "DATA\r\n");
1364 send(s, str, strlen(str), 0);
1365 if (verbose)
1366 puts(str);
1367 recv_string(s, str, strsize, 3000);
1368 if (verbose)
1369 puts(str);
1370
1371 sprintf(str, "To: %s\r\nFrom: %s\r\nSubject: %s\r\n", to, from, subject);
1372 send(s, str, strlen(str), 0);
1373 if (verbose)
1374 puts(str);
1375
1376 sprintf(str, "X-Mailer: mhttpd revision %s\r\n", mhttpd_revision());
1377 send(s, str, strlen(str), 0);
1378 if (verbose)
1379 puts(str);
1380
1381 ss_tzset(); // required for localtime_r()
1382 time_t now;
1383 time(&now);
1384 struct tm tms;
1385 localtime_r(&now, &tms);
1386 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", &tms);
1387 offset = (-(int) timezone);
1388 if (tms.tm_isdst)
1389 offset += 3600;
1390 sprintf(str, "Date: %s %+03d%02d\r\n", buf, (int) (offset / 3600),
1391 (int) ((abs((int) offset) / 60) % 60));
1392 send(s, str, strlen(str), 0);
1393 if (verbose)
1394 puts(str);
1395
1396 sprintf(str, "Content-Type: TEXT/PLAIN; charset=US-ASCII\r\n\r\n");
1397 send(s, str, strlen(str), 0);
1398 if (verbose)
1399 puts(str);
1400
1401 /* analyze text for "." at beginning of line */
1402 const char* p = text;
1403 str[0] = 0;
1404 while (strstr(p, "\r\n.\r\n")) {
1405 i = (POINTER_T) strstr(p, "\r\n.\r\n") - (POINTER_T) p + 1;
1406 mstrlcat(str, p, i);
1407 p += i + 4;
1408 mstrlcat(str, "\r\n..\r\n", strsize);
1409 }
1410 mstrlcat(str, p, strsize);
1411 mstrlcat(str, "\r\n", strsize);
1412 send(s, str, strlen(str), 0);
1413 if (verbose)
1414 puts(str);
1415
1416 /* send ".<CR>" to signal end of message */
1417 sprintf(str, ".\r\n");
1418 send(s, str, strlen(str), 0);
1419 if (verbose)
1420 puts(str);
1421 recv_string(s, str, strsize, 3000);
1422 if (verbose)
1423 puts(str);
1424
1425 sprintf(str, "QUIT\n");
1426 send(s, str, strlen(str), 0);
1427 if (verbose)
1428 puts(str);
1429 recv_string(s, str, strsize, 3000);
1430 if (verbose)
1431 puts(str);
1432
1433 closesocket(s);
1434 free(str);
1435
1436 return 1;
1437}
1438
1439/*------------------------------------------------------------------*/
1440
1441void redirect(Return *r, const char *path)
1442{
1443 char str[256];
1444
1445 //printf("redirect to [%s]\n", path);
1446
1447 mstrlcpy(str, path, sizeof(str));
1448 if (str[0] == 0)
1449 strcpy(str, "./");
1450
1451 /* redirect */
1452 r->rsprintf("HTTP/1.1 302 Found\r\n");
1453 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1454 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1455
1456 if (strncmp(path, "http:", 5) == 0)
1457 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1458 else if (strncmp(path, "https:", 6) == 0)
1459 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1460 else {
1461 r->rsprintf("Location: %s\r\n\r\n<html>redir</html>\r\n", str);
1462 }
1463}
1464
1465void redirect_307(Return *r, const char *path)
1466{
1467 //printf("redirect_307 to [%s]\n", path);
1468
1469 /* redirect */
1470 r->rsprintf("HTTP/1.1 307 Temporary Redirect\r\n");
1471 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1472 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
1473 r->rsprintf("Location: %s\r\n", path);
1474 r->rsprintf("\r\n");
1475 r->rsprintf("<html>redirect to %s</html>\r\n", path);
1476}
1477
1478void redirect2(Return* r, const char *path)
1479{
1480 redirect(r, path);
1481}
1482
1483/*------------------------------------------------------------------*/
1484
1486{
1488 const char* search_name;
1489};
1490
1492{
1493 search_data* sinfo = (search_data*)info;
1494 int i;
1495 INT size, status;
1496
1497 Return* r = sinfo->r;
1498 const char* search_name = sinfo->search_name;
1499
1500 /* convert strings to uppercase */
1501
1502 char xstr1[MAX_ODB_PATH];
1503 for (i = 0; key->name[i]; i++)
1504 xstr1[i] = toupper(key->name[i]);
1505 xstr1[i] = 0;
1506
1507 char str2[MAX_ODB_PATH];
1508 for (i = 0; search_name[i] ; i++)
1509 str2[i] = toupper(search_name[i]);
1510 str2[i] = 0;
1511
1512 if (strstr(xstr1, str2) != NULL) {
1513 char data[10000];
1514 std::string path = db_get_path(hDB, hKey).substr(1);
1515 std::string path_encoded = urlEncode(path.c_str());
1516
1517 if (key->type == TID_KEY || key->type == TID_LINK) {
1518 /* for keys, don't display data value */
1519 r->rsprintf("<tr><td class=\"ODBkey\"><a href=\"?cmd=odb&odb_path=/%s\">/%s</a></tr>\n", path_encoded.c_str(), path.c_str());
1520 } else {
1521 /* strip variable name from path */
1522 char* p = const_cast<char *>(path.data() + path.length() - 1);
1523 while (*p && *p != '/')
1524 *p-- = 0;
1525 if (*p == '/')
1526 *p = 0;
1527
1528 /* display single value */
1529 if (key->num_values == 1) {
1530 size = sizeof(data);
1531 status = db_get_data(hDB, hKey, data, &size, key->type);
1532 std::string data_str;
1533 if (status == DB_NO_ACCESS)
1534 data_str = "<no read access>";
1535 else
1536 data_str = db_sprintf(data, key->item_size, 0, key->type);
1537
1538 r->rsprintf("<tr><td class=\"ODBkey\">");
1539 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s</a></td>", path_encoded.c_str(), path.c_str(), key->name);
1540 r->rsprintf("<td class=\"ODBvalue\">%s</td></tr>\n", data_str.c_str());
1541 } else {
1542 /* display first value */
1543 i = key->num_values;
1544 if (i > 10)
1545 i = 11;
1546 r->rsprintf("<tr><td rowspan=%d class=\"ODBkey\">", i);
1547 r->rsprintf("<a href=\"?cmd=odb&odb_path=/%s\">/%s/%s\n", path_encoded.c_str(), path.c_str(), key->name);
1548
1549 for (int i = 0; i < key->num_values; i++) {
1550 size = sizeof(data);
1551 db_get_data_index(hDB, hKey, data, &size, i, key->type);
1552
1553 std::string data_str = db_sprintf(data, key->item_size, 0, key->type);
1554
1555 if (i > 0)
1556 r->rsprintf("<tr>");
1557
1558 r->rsprintf("<td class=\"ODBvalue\">[%d] %s</td></tr>\n", i, data_str.c_str());
1559
1560 if (i > 8) {
1561 r->rsprintf("<tr><td class=\"ODBvalue\">... [%d] values ...</td></tr>\n", key->num_values - i - 1);
1562 break;
1563 }
1564 }
1565 }
1566 }
1567 }
1568
1569 return SUCCESS;
1570}
1571
1572/*------------------------------------------------------------------*/
1573
1574void show_help_page(Return* r, const char* dec_path)
1575{
1576 const char *s;
1577 char str[256];
1578 int status;
1579
1580 show_header(r, "Help", "", "./", 0);
1581 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
1582 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
1583 show_navigation_bar(r, "Help");
1584
1585 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1586 r->rsprintf(" <tr>\n");
1587 r->rsprintf(" <td class=\"mtableheader\">MIDAS Help Page</td>\n");
1588 r->rsprintf(" </tr>\n");
1589 r->rsprintf(" <tr>\n");
1590 r->rsprintf(" <td>\n");
1591 r->rsprintf(" <table>\n");
1592
1593 r->rsprintf(" <tr>\n");
1594 r->rsprintf(" <td style=\"text-align:right;\">Documentation:</td>\n");
1595 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca\">https://midas.triumf.ca</a></td>\n");
1596 r->rsprintf(" </tr>\n");
1597 r->rsprintf(" <tr>\n");
1598 r->rsprintf(" <td style=\"text-align:right;\">Discussion Forum:</td>\n");
1599 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://midas.triumf.ca/forum/\">https://midas.triumf.ca/forum/</a></td>\n");
1600 r->rsprintf(" </tr>\n");
1601 r->rsprintf(" <tr>\n");
1602 r->rsprintf(" <td style=\"text-align:right;\">Code:</td>\n");
1603 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/\">https://bitbucket.org/tmidas/midas/</a></td>\n");
1604 r->rsprintf(" </tr>\n");
1605 r->rsprintf(" <tr>\n");
1606 r->rsprintf(" <td style=\"text-align:right;\">Report a bug:</td>\n");
1607 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"https://bitbucket.org/tmidas/midas/issues/\">https://bitbucket.org/tmidas/midas/issues/</a></td>\n");
1608 r->rsprintf(" </tr>\n");
1609
1610 r->rsprintf(" <tr>\n");
1611 r->rsprintf(" <td style=\"text-align:right;\">Version:</td>\n");
1612 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_version());
1613 r->rsprintf(" </tr>\n");
1614 r->rsprintf(" <tr>\n");
1615 r->rsprintf(" <td style=\"text-align:right;\">Revision:</td>\n");
1616 std::string rev = cm_get_revision();
1617 std::string url = "https://bitbucket.org/tmidas/midas/commits/";
1618 // rev format looks like this:
1619 // Fri Nov 24 10:15:54 2017 -0800 - midas-2017-07-c-171-gb8928d5c-dirty on branch develop
1620 // -gXXX is the commit hash
1621 // -dirty should be removed from the hash url, if present
1622 // " " before "on branch" should be removed from the hash url
1623 std::string::size_type pos = rev.find("-g");
1624 if (pos != std::string::npos) {
1625 std::string hash = rev.substr(pos+2);
1626 pos = hash.find("-dirty");
1627 if (pos != std::string::npos) {
1628 hash = hash.substr(0, pos);
1629 }
1630 pos = hash.find(" ");
1631 if (pos != std::string::npos) {
1632 hash = hash.substr(0, pos);
1633 }
1634 url += hash;
1635 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"%s\">%s</a></td>\n", url.c_str(), rev.c_str());
1636 } else {
1637 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", rev.c_str());
1638 }
1639 r->rsprintf(" </tr>\n");
1640
1641 r->rsprintf(" <tr>\n");
1642 r->rsprintf(" <td style=\"text-align:right;\">MIDASSYS:</td>\n");
1643 s = getenv("MIDASSYS");
1644 if (!s) s = "(unset)";
1645 mstrlcpy(str, s, sizeof(str));
1646 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", str);
1647 r->rsprintf(" </tr>\n");
1648
1649 r->rsprintf(" <tr>\n");
1650 r->rsprintf(" <td style=\"text-align:right;\">mhttpd current directory:</td>\n");
1651 std::string cwd = ss_getcwd();
1652 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cwd.c_str());
1653 r->rsprintf(" </tr>\n");
1654
1655 r->rsprintf(" <tr>\n");
1656 r->rsprintf(" <td style=\"text-align:right;\">Exptab file:</td>\n");
1657 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_exptab_filename().c_str());
1658 r->rsprintf(" </tr>\n");
1659
1660 r->rsprintf(" <tr>\n");
1661 r->rsprintf(" <td style=\"text-align:right;\">Experiment:</td>\n");
1662 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_experiment_name().c_str());
1663 r->rsprintf(" </tr>\n");
1664
1665 r->rsprintf(" <tr>\n");
1666 r->rsprintf(" <td style=\"text-align:right;\">Experiment directory:</td>\n");
1667 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_path().c_str());
1668 r->rsprintf(" </tr>\n");
1669
1672
1673 if (status == CM_SUCCESS) {
1674 if (list.size() == 1) {
1675 r->rsprintf(" <tr>\n");
1676 r->rsprintf(" <td style=\"text-align:right;\">System logfile:</td>\n");
1677 std::string s;
1678 cm_msg_get_logfile("midas", 0, &s, NULL, NULL);
1679 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", s.c_str());
1680 r->rsprintf(" </tr>\n");
1681 } else {
1682 r->rsprintf(" <tr>\n");
1683 r->rsprintf(" <td style=\"text-align:right;\">Logfiles:</td>\n");
1684 r->rsprintf(" <td style=\"text-align:left;\">\n");
1685 for (unsigned i=0 ; i<list.size() ; i++) {
1686 if (i>0)
1687 r->rsputs("<br />\n");
1688 std::string s;
1689 cm_msg_get_logfile(list[i].c_str(), 0, &s, NULL, NULL);
1690 r->rsputs(s.c_str());
1691 }
1692 r->rsprintf("\n </td>\n");
1693 r->rsprintf(" </tr>\n");
1694 }
1695 }
1696
1697 r->rsprintf(" <tr>\n");
1698 r->rsprintf(" <td style=\"text-align:right;\">Image history:</td>\n");
1699 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", cm_get_history_path("IMAGE").c_str());
1700 r->rsprintf(" </tr>\n");
1701
1702 r->rsprintf(" <tr>\n");
1703 r->rsprintf(" <td style=\"text-align:right;\">Resource paths:</td>\n");
1704 r->rsprintf(" <td style=\"text-align:left;\">");
1705 std::vector<std::string> resource_paths = get_resource_paths();
1706 for (unsigned i=0; i<resource_paths.size(); i++) {
1707 if (i>0)
1708 r->rsputs("<br>");
1709 r->rsputs(resource_paths[i].c_str());
1710 std::string exp = cm_expand_env(resource_paths[i].c_str());
1711 //printf("%d %d [%s] [%s]\n", resource_paths[i].length(), exp.length(), resource_paths[i].c_str(), exp.c_str());
1712 if (exp != resource_paths[i]) {
1713 r->rsputs(" (");
1714 r->rsputs(exp.c_str());
1715 r->rsputs(")");
1716 }
1717 }
1718 r->rsprintf(" </td>\n");
1719 r->rsprintf(" </tr>\n");
1720
1721 std::string path;
1722
1723 r->rsprintf(" <tr>\n");
1724 r->rsprintf(" <td style=\"text-align:right;\">midas.css:</td>\n");
1725 if (open_resource_file("midas.css", &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;\">midas.js:</td>\n");
1733 if (open_resource_file("midas.js", &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;\">controls.js:</td>\n");
1741 if (open_resource_file("controls.js", &path, NULL))
1742 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1743 else
1744 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1745 r->rsprintf(" </tr>\n");
1746
1747 r->rsprintf(" <tr>\n");
1748 r->rsprintf(" <td style=\"text-align:right;\">mhttpd.js:</td>\n");
1749 if (open_resource_file("mhttpd.js", &path, NULL))
1750 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1751 else
1752 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1753 r->rsprintf(" </tr>\n");
1754
1755 r->rsprintf(" <tr>\n");
1756 r->rsprintf(" <td style=\"text-align:right;\">obsolete.js:</td>\n");
1757 if (open_resource_file("obsolete.js", &path, NULL))
1758 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1759 else
1760 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1761 r->rsprintf(" </tr>\n");
1762
1763 r->rsprintf(" <tr>\n");
1764 r->rsprintf(" <td style=\"text-align:right;\">Obsolete mhttpd.css:</td>\n");
1765 if (open_resource_file("mhttpd.css", &path, NULL))
1766 r->rsprintf(" <td style=\"text-align:left;\">%s</td>\n", path.c_str());
1767 else
1768 r->rsprintf(" <td style=\"text-align:left;\">NOT FOUND</td>\n");
1769 r->rsprintf(" </tr>\n");
1770
1771 r->rsprintf(" <tr>\n");
1772 r->rsprintf(" <td style=\"text-align:right;\">JSON-RPC schema:</td>\n");
1773 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");
1774 r->rsprintf(" </tr>\n");
1775
1776 r->rsprintf(" <tr>\n");
1777 r->rsprintf(" <td style=\"text-align:right;\">JavaScript examples:</td>\n");
1778 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=example\">example.html</a></td>\n");
1779 r->rsprintf(" </tr>\n");
1780
1781 r->rsprintf(" <tr>\n");
1782 r->rsprintf(" <td style=\"text-align:right;\">Custom page example:</td>\n");
1783 r->rsprintf(" <td style=\"text-align:left;\"><a href=\"?cmd=custom_example\">custom_example.html</a></td>\n");
1784 r->rsprintf(" </tr>\n");
1785
1786 r->rsprintf(" </table>\n");
1787 r->rsprintf(" </td>\n");
1788 r->rsprintf(" </tr>\n");
1789 r->rsprintf("</table>\n");
1790
1791 r->rsprintf("<table class=\"mtable\" style=\"width: 95%%\">\n");
1792 r->rsprintf(" <tr>\n");
1793 r->rsprintf(" <td class=\"mtableheader\">Contributions</td>\n");
1794 r->rsprintf(" </tr>\n");
1795 r->rsprintf(" <tr>\n");
1796 r->rsprintf(" <td>\n");
1797 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");
1798 r->rsprintf(" </td>\n");
1799 r->rsprintf(" </tr>\n");
1800 r->rsprintf("</table>\n");
1801
1802 r->rsprintf("</div></form>\n");
1803 r->rsprintf("</body></html>\r\n");
1804}
1805
1806/*------------------------------------------------------------------*/
1807
1808void show_header(Return* r, const char *title, const char *method, const char *path, int refresh)
1809{
1810 HNDLE hDB;
1811 time_t now;
1812 char str[256];
1813
1815
1816 /* header */
1817 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1818 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1819 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1820 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1821 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1822
1823 r->rsprintf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
1824 r->rsprintf("<html><head>\n");
1825
1826 /* style sheet */
1827 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
1828 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1829 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
1830
1831 /* auto refresh */
1832 if (refresh > 0)
1833 r->rsprintf("<meta http-equiv=\"Refresh\" content=\"%02d\">\n", refresh);
1834
1835 r->rsprintf("<title>%s</title></head>\n", title);
1836
1837 mstrlcpy(str, path, sizeof(str));
1838 urlEncode(str, sizeof(str));
1839
1840 if (equal_ustring(method, "POST"))
1841 r->rsprintf
1842 ("<body><form name=\"form1\" method=\"POST\" action=\"%s\" enctype=\"multipart/form-data\">\n\n",
1843 str);
1844 else if (equal_ustring(method, "GET"))
1845 r->rsprintf("<body><form name=\"form1\" method=\"GET\" action=\"%s\">\n\n", str);
1846
1847 /* title row */
1848
1849 std::string exptname;
1850 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
1851 time(&now);
1852}
1853
1854/*------------------------------------------------------------------*/
1855
1857{
1858 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1859 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1860 r->rsprintf("Access-Control-Allow-Origin: *\r\n");
1861 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
1862 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
1863 r->rsprintf("Content-Type: text/plain; charset=%s\r\n\r\n", HTTP_ENCODING);
1864}
1865
1866/*------------------------------------------------------------------*/
1867
1868void show_error(Return* r, const char *error)
1869{
1870 /* header */
1871 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
1872 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1873 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
1874
1875 r->rsprintf("<html><head>\n");
1876 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
1877 r->rsprintf("<title>MIDAS error</title></head>\n");
1878 r->rsprintf("<body><H1>%s</H1></body></html>\n", error);
1879}
1880
1881/*------------------------------------------------------------------*/
1882
1883void show_error_404(Return* r, const char *error)
1884{
1885 /* header */
1886 r->rsprintf("HTTP/1.1 404 Not Found\r\n");
1887 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
1888 r->rsprintf("Content-Type: text/plain\r\n");
1889 r->rsprintf("\r\n");
1890
1891 r->rsprintf("MIDAS error: %s\n", error);
1892}
1893
1894/*------------------------------------------------------------------*/
1895
1896void show_navigation_bar(Return* r, const char *cur_page)
1897{
1898 r->rsprintf("<script>\n");
1899 r->rsprintf("window.addEventListener(\"load\", function(e) { mhttpd_init('%s', 1000); });\n", cur_page);
1900 r->rsprintf("</script>\n");
1901
1902 r->rsprintf("<!-- header and side navigation will be filled in mhttpd_init -->\n");
1903 r->rsprintf("<div id=\"mheader\"></div>\n");
1904 r->rsprintf("<div id=\"msidenav\"></div>\n");
1905 r->rsprintf("<div id=\"mmain\">\n");
1906}
1907
1908/*------------------------------------------------------------------*/
1909
1910void check_obsolete_odb(HNDLE hDB, const char* odb_path)
1911{
1912 HNDLE hKey;
1913 int status = db_find_key(hDB, 0, odb_path, &hKey);
1914 if (status == DB_SUCCESS) {
1915 cm_msg(MERROR, "check_obsolete_odb", "ODB \"%s\" is obsolete, please delete it.", odb_path);
1916 }
1917}
1918
1919void init_menu_buttons(MVOdb* odb)
1920{
1921 HNDLE hDB;
1922 BOOL true_value = TRUE;
1923 BOOL false_value = FALSE;
1924 int size = sizeof(true_value);
1926 db_get_value(hDB, 0, "/Experiment/Menu/Status", &true_value, &size, TID_BOOL, TRUE);
1927 db_get_value(hDB, 0, "/Experiment/Menu/Start", &false_value, &size, TID_BOOL, TRUE);
1928 db_get_value(hDB, 0, "/Experiment/Menu/Transition", &true_value, &size, TID_BOOL, TRUE);
1929 db_get_value(hDB, 0, "/Experiment/Menu/ODB", &true_value, &size, TID_BOOL, TRUE);
1930 db_get_value(hDB, 0, "/Experiment/Menu/OldODB", &true_value, &size, TID_BOOL, TRUE);
1931 db_get_value(hDB, 0, "/Experiment/Menu/Messages", &true_value, &size, TID_BOOL, TRUE);
1932 db_get_value(hDB, 0, "/Experiment/Menu/Chat", &true_value, &size, TID_BOOL, TRUE);
1933 db_get_value(hDB, 0, "/Experiment/Menu/Elog", &true_value, &size, TID_BOOL, TRUE);
1934 db_get_value(hDB, 0, "/Experiment/Menu/Alarms", &true_value, &size, TID_BOOL, TRUE);
1935 db_get_value(hDB, 0, "/Experiment/Menu/Programs", &true_value, &size, TID_BOOL, TRUE);
1936 db_get_value(hDB, 0, "/Experiment/Menu/Buffers", &true_value, &size, TID_BOOL, TRUE);
1937 db_get_value(hDB, 0, "/Experiment/Menu/History", &true_value, &size, TID_BOOL, TRUE);
1938 db_get_value(hDB, 0, "/Experiment/Menu/OldHistory", &true_value, &size, TID_BOOL, TRUE);
1939 db_get_value(hDB, 0, "/Experiment/Menu/MSCB", &true_value, &size, TID_BOOL, TRUE);
1940 db_get_value(hDB, 0, "/Experiment/Menu/Sequencer", &true_value, &size, TID_BOOL, TRUE);
1941 db_get_value(hDB, 0, "/Experiment/Menu/PySequencer",&true_value, &size, TID_BOOL, TRUE);
1942 db_get_value(hDB, 0, "/Experiment/Menu/Event Dump", &true_value, &size, TID_BOOL, TRUE);
1943 db_get_value(hDB, 0, "/Experiment/Menu/Config", &true_value, &size, TID_BOOL, TRUE);
1944 db_get_value(hDB, 0, "/Experiment/Menu/Example", &true_value, &size, TID_BOOL, TRUE);
1945 db_get_value(hDB, 0, "/Experiment/Menu/Help", &true_value, &size, TID_BOOL, TRUE);
1946
1947 //std::string buf;
1948 //status = db_get_value_string(hDB, 0, "/Experiment/Menu buttons", 0, &buf, FALSE);
1949 //if (status == DB_SUCCESS) {
1950 // cm_msg(MERROR, "init_menu_buttons", "ODB \"/Experiment/Menu buttons\" is obsolete, please delete it.");
1951 //}
1952
1953 check_obsolete_odb(hDB, "/Experiment/Menu buttons");
1954 check_obsolete_odb(hDB, "/Experiment/Menu/OldSequencer");
1955 check_obsolete_odb(hDB, "/Experiment/Menu/NewSequencer");
1956}
1957
1958/*------------------------------------------------------------------*/
1959
1960void init_mhttpd_odb(MVOdb* odb)
1961{
1962 HNDLE hDB;
1963 HNDLE hKey;
1964 int status;
1965 std::string s;
1967
1968 status = db_find_key(hDB, 0, "/Experiment/Base URL", &hKey);
1969 if (status == DB_SUCCESS) {
1970 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Base URL\" is obsolete, please delete it.");
1971 }
1972
1973 status = db_find_key(hDB, 0, "/Experiment/CSS File", &hKey);
1974 if (status == DB_SUCCESS) {
1975 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/CSS File\" is obsolete, please delete it.");
1976 }
1977
1978 status = db_find_key(hDB, 0, "/Experiment/JS File", &hKey);
1979 if (status == DB_SUCCESS) {
1980 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/JS File\" is obsolete, please delete it.");
1981 }
1982
1983 status = db_find_key(hDB, 0, "/Experiment/Start-Stop Buttons", &hKey);
1984 if (status == DB_SUCCESS) {
1985 cm_msg(MERROR, "init_mhttpd_odb", "ODB \"/Experiment/Start-Stop Buttons\" is obsolete, please delete it.");
1986 }
1987
1988 bool xdefault = true;
1989 odb->RB("Experiment/Pause-Resume Buttons", &xdefault, true);
1990
1991#ifdef HAVE_MONGOOSE616
1992 check_obsolete_odb(hDB, "/Experiment/midas http port");
1993 check_obsolete_odb(hDB, "/Experiment/midas https port");
1994 check_obsolete_odb(hDB, "/Experiment/http redirect to https");
1995 check_obsolete_odb(hDB, "/Experiment/Security/mhttpd hosts");
1996#endif
1997
1998 status = db_find_key(hDB, 0, "/Logger/Message file", &hKey);
1999 if (status == DB_SUCCESS) {
2000 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.");
2001 }
2002
2003 check_obsolete_odb(hDB, "/Logger/Watchdog timeout");
2004}
2005
2006/*------------------------------------------------------------------*/
2007
2009{
2010 HNDLE hDB;
2011 int size;
2012 HNDLE hkey;
2014
2015 BOOL external_elog = FALSE;
2016 std::string external_elog_url;
2017
2018 size = sizeof(external_elog);
2019 db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
2020 db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
2021
2022 BOOL allow_delete = FALSE;
2023 BOOL allow_edit = FALSE;
2024 size = sizeof(BOOL);
2025 db_get_value(hDB, 0, "/Elog/Allow delete", &allow_delete, &size, TID_BOOL, TRUE);
2026 db_get_value(hDB, 0, "/Elog/Allow edit", &allow_edit, &size, TID_BOOL, TRUE);
2027 //db_get_value(hDB, 0, "/Elog/Display run number", &display_run_number, &size, TID_BOOL, TRUE);
2028
2029 if (db_find_key(hDB, 0, "/Elog/Buttons", &hkey) != DB_SUCCESS) {
2030 const char def_button[][NAME_LENGTH] = { "8h", "24h", "7d" };
2031 db_set_value(hDB, 0, "/Elog/Buttons", def_button, NAME_LENGTH*3, 3, TID_STRING);
2032 }
2033
2034
2035 /* get type list from ODB */
2036 size = 20 * NAME_LENGTH;
2037 if (db_find_key(hDB, 0, "/Elog/Types", &hkey) != DB_SUCCESS) {
2038 db_set_value(hDB, 0, "/Elog/Types", default_type_list, NAME_LENGTH * 20, 20, TID_STRING);
2039 }
2040
2041 /* get system list from ODB */
2042 size = 20 * NAME_LENGTH;
2043 if (db_find_key(hDB, 0, "/Elog/Systems", &hkey) != DB_SUCCESS)
2044 db_set_value(hDB, 0, "/Elog/Systems", default_system_list, NAME_LENGTH * 20, 20, TID_STRING);
2045}
2046
2047/*------------------------------------------------------------------*/
2048
2049void strencode(Return* r, const char *text)
2050{
2051 size_t len = strlen(text);
2052 for (size_t i = 0; i < len; i++) {
2053 switch (text[i]) {
2054 case '\n':
2055 r->rsprintf("<br>\n");
2056 break;
2057 case '<':
2058 r->rsprintf("&lt;");
2059 break;
2060 case '>':
2061 r->rsprintf("&gt;");
2062 break;
2063 case '&':
2064 r->rsprintf("&amp;");
2065 break;
2066 case '\"':
2067 r->rsprintf("&quot;");
2068 break;
2069 default:
2070 r->rsprintf("%c", text[i]);
2071 }
2072 }
2073}
2074
2075/*------------------------------------------------------------------*/
2076
2077std::string strencode2(const char *text)
2078{
2079 std::string b;
2080 size_t len = strlen(text);
2081 for (size_t i = 0; i < len; i++) {
2082 switch (text[i]) {
2083 case '\n':
2084 b += "<br>\n";
2085 break;
2086 case '<':
2087 b += "&lt;";
2088 break;
2089 case '>':
2090 b += "&gt;";
2091 break;
2092 case '&':
2093 b += "&amp;";
2094 break;
2095 case '\"':
2096 b += "&quot;";
2097 break;
2098 default:
2099 b += text[i];
2100 break;
2101 }
2102 }
2103 return b;
2104}
2105
2106/*------------------------------------------------------------------*/
2107
2108void strencode3(Return* r, const char *text)
2109{
2110 size_t len = strlen(text);
2111 for (size_t i = 0; i < len; i++) {
2112 switch (text[i]) {
2113 case '<':
2114 r->rsprintf("&lt;");
2115 break;
2116 case '>':
2117 r->rsprintf("&gt;");
2118 break;
2119 case '&':
2120 r->rsprintf("&amp;");
2121 break;
2122 case '\"':
2123 r->rsprintf("&quot;");
2124 break;
2125 default:
2126 r->rsprintf("%c", text[i]);
2127 }
2128 }
2129}
2130
2131/*------------------------------------------------------------------*/
2132
2133void strencode4(Return* r, const char *text)
2134{
2135 size_t len = strlen(text);
2136 for (size_t i = 0; i < len; i++) {
2137 switch (text[i]) {
2138 case '\n':
2139 r->rsprintf("<br>\n");
2140 break;
2141 case '<':
2142 r->rsprintf("&lt;");
2143 break;
2144 case '>':
2145 r->rsprintf("&gt;");
2146 break;
2147 case '&':
2148 r->rsprintf("&amp;");
2149 break;
2150 case '\"':
2151 r->rsprintf("&quot;");
2152 break;
2153 case ' ':
2154 r->rsprintf("&nbsp;");
2155 break;
2156 default:
2157 r->rsprintf("%c", text[i]);
2158 }
2159 }
2160}
2161
2162/*------------------------------------------------------------------*/
2163
2164void gen_odb_attachment(Return* r, const char *path, std::string& bout)
2165{
2166 HNDLE hDB, hkeyroot, hkey;
2167 KEY key;
2168 INT i, j, size;
2169 char data[1024];
2170 time_t now;
2171
2173 db_find_key(hDB, 0, path, &hkeyroot);
2174 assert(hkeyroot);
2175
2176 /* title row */
2177 //size = sizeof(str);
2178 //str[0] = 0;
2179 //db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
2180 time(&now);
2181
2182 bout += "<table border=3 cellpadding=1 class=\"dialogTable\">\n";
2183 char ctimebuf[32];
2184 ctime_r(&now, ctimebuf);
2185 bout += msprintf("<tr><th colspan=2>%s</tr>\n", ctimebuf);
2186 bout += msprintf("<tr><th colspan=2>%s</tr>\n", path);
2187
2188 /* enumerate subkeys */
2189 for (i = 0;; i++) {
2190 db_enum_link(hDB, hkeyroot, i, &hkey);
2191 if (!hkey)
2192 break;
2193 db_get_key(hDB, hkey, &key);
2194
2195 /* resolve links */
2196 if (key.type == TID_LINK) {
2197 db_enum_key(hDB, hkeyroot, i, &hkey);
2198 db_get_key(hDB, hkey, &key);
2199 }
2200
2201 if (key.type == TID_KEY) {
2202 /* for keys, don't display data value */
2203 bout += msprintf("<tr><td colspan=2>%s</td></tr>\n", key.name);
2204 } else {
2205 /* display single value */
2206 if (key.num_values == 1) {
2207 size = sizeof(data);
2208 db_get_data(hDB, hkey, data, &size, key.type);
2209 //printf("data size %d [%s]\n", size, data);
2210 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2211 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2212
2213 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2214 data_str = "(empty)";
2215 hex_str = "";
2216 }
2217
2218 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2219 //sprintf(b, "<tr><td>%s</td><td>%s (%s)</td></tr>\n", key.name, data_str, hex_str);
2220 bout += "<tr><td>";
2221 bout += key.name;
2222 bout += "</td><td>";
2223 bout += data_str;
2224 bout += " (";
2225 bout += hex_str;
2226 bout += ")</td></tr>\n";
2227 } else {
2228 bout += msprintf("<tr><td>%s</td><td>", key.name);
2229 bout += strencode2(data_str.c_str());
2230 bout += "</td></tr>\n";
2231 }
2232 } else {
2233 /* display first value */
2234 bout += msprintf("<tr><td rowspan=%d>%s</td>\n", key.num_values, key.name);
2235
2236 for (j = 0; j < key.num_values; j++) {
2237 size = sizeof(data);
2238 db_get_data_index(hDB, hkey, data, &size, j, key.type);
2239 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2240 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2241
2242 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2243 data_str = "(empty)";
2244 hex_str = "";
2245 }
2246
2247 if (j > 0) {
2248 bout += "<tr>";
2249 }
2250
2251 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
2252 //sprintf(b, "<td>[%d] %s (%s)<br></td></tr>\n", j, data_str, hex_str);
2253 bout += "<td>[";
2254 bout += toString(j);
2255 bout += "] ";
2256 bout += data_str;
2257 bout += " (";
2258 bout += hex_str;
2259 bout += ")<br></td></tr>\n";
2260 } else {
2261 //sprintf(b, "<td>[%d] %s<br></td></tr>\n", j, data_str);
2262 bout += "<td>[";
2263 bout += toString(j);
2264 bout += "] ";
2265 bout += data_str;
2266 bout += "<br></td></tr>\n";
2267 }
2268 }
2269 }
2270 }
2271 }
2272
2273 bout += "</table>\n";
2274}
2275
2276/*------------------------------------------------------------------*/
2277
2278void submit_elog(MVOdb* odb, Param* pp, Return* r, Attachment* a)
2279{
2280 char path[256], path1[256];
2281 char mail_to[256], mail_from[256], mail_list[256],
2282 smtp_host[256], tag[80], mail_param[1000];
2283 char *p, *pitem;
2284 HNDLE hDB, hkey;
2285 char att_file[3][256];
2286 int fh, size, n_mail;
2287 char mhttpd_full_url[256];
2288
2290 mstrlcpy(att_file[0], pp->getparam("attachment0"), sizeof(att_file[0]));
2291 mstrlcpy(att_file[1], pp->getparam("attachment1"), sizeof(att_file[1]));
2292 mstrlcpy(att_file[2], pp->getparam("attachment2"), sizeof(att_file[2]));
2293
2294 /* check for valid attachment files */
2295 for (int i = 0; i < 3; i++) {
2296 char str[256];
2297 sprintf(str, "attachment%d", i);
2298 //printf("submit_elog: att %d, [%s] param [%s], size %d\n", i, str, pp->getparam(str), a->_attachment_size[i]);
2299 if (pp->getparam(str) && *pp->getparam(str) && a->attachment_size[i] == 0) {
2300 /* replace '\' by '/' */
2301 mstrlcpy(path, pp->getparam(str), sizeof(path));
2302 mstrlcpy(path1, path, sizeof(path1));
2303 while (strchr(path, '\\'))
2304 *strchr(path, '\\') = '/';
2305
2306 /* check if valid ODB tree */
2307 if (db_find_key(hDB, 0, path, &hkey) == DB_SUCCESS) {
2308 std::string bout;
2309 gen_odb_attachment(r, path, bout);
2310 int bufsize = bout.length()+1;
2311 char* buf = (char*)M_MALLOC(bufsize);
2312 memcpy(buf, bout.c_str(), bufsize);
2313 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2314 mstrlcat(att_file[i], ".html", sizeof(att_file[0]));
2315 a->attachment_buffer[i] = buf;
2316 a->attachment_size[i] = bufsize;
2317 }
2318 /* check if local file */
2319 else if ((fh = open(path1, O_RDONLY | O_BINARY)) >= 0) {
2320 size = lseek(fh, 0, SEEK_END);
2321 char* buf = (char*)M_MALLOC(size);
2322 lseek(fh, 0, SEEK_SET);
2323 int rd = read(fh, buf, size);
2324 if (rd < 0)
2325 rd = 0;
2326 close(fh);
2327 mstrlcpy(att_file[i], path, sizeof(att_file[0]));
2328 a->attachment_buffer[i] = buf;
2329 a->attachment_size[i] = rd;
2330 } else if (strncmp(path, "/HS/", 4) == 0) {
2331 char* buf = (char*)M_MALLOC(100000);
2332 size = 100000;
2333 mstrlcpy(str, path + 4, sizeof(str));
2334 if (strchr(str, '?')) {
2335 p = strchr(str, '?') + 1;
2336 p = strtok(p, "&");
2337 while (p != NULL) {
2338 pitem = p;
2339 p = strchr(p, '=');
2340 if (p != NULL) {
2341 *p++ = 0;
2342 urlDecode(pitem); // parameter name
2343 urlDecode(p); // parameter value
2344
2345 pp->setparam(pitem, p);
2346
2347 p = strtok(NULL, "&");
2348 }
2349 }
2350 *strchr(str, '?') = 0;
2351 }
2352 show_hist_page(odb, pp, r, "image.gif", buf, &size, 0);
2353 mstrlcpy(att_file[i], str, sizeof(att_file[0]));
2354 a->attachment_buffer[i] = buf;
2355 a->attachment_size[i] = size;
2356 pp->unsetparam("scale");
2357 pp->unsetparam("offset");
2358 pp->unsetparam("width");
2359 pp->unsetparam("index");
2360 } else {
2361 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2362 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2363 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
2364
2365 r->rsprintf("<html><head>\n");
2366 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
2367 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
2368 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
2369 r->rsprintf("<title>ELog Error</title></head>\n");
2370 r->rsprintf("<i>Error: Attachment file <i>%s</i> not valid.</i><p>\n", pp->getparam(str));
2371 r->rsprintf("Please go back and enter a proper filename (use the <b>Browse</b> button).\n");
2372 r->rsprintf("<body></body></html>\n");
2373 return;
2374 }
2375 }
2376 }
2377
2378 int edit = atoi(pp->getparam("edit"));
2379 //printf("submit_elog: edit [%s] %d, orig [%s]\n", pp->getparam("edit"), edit, pp->getparam("orig"));
2380
2381 tag[0] = 0;
2382 if (edit) {
2383 mstrlcpy(tag, pp->getparam("orig"), sizeof(tag));
2384 }
2385
2386 int status = el_submit(atoi(pp->getparam("run")),
2387 pp->getparam("author"),
2388 pp->getparam("type"),
2389 pp->getparam("system"),
2390 pp->getparam("subject"),
2391 pp->getparam("text"),
2392 pp->getparam("orig"),
2393 *pp->getparam("html") ? "HTML" : "plain",
2394 att_file[0], a->attachment_buffer[0], a->attachment_size[0],
2395 att_file[1], a->attachment_buffer[1], a->attachment_size[1],
2396 att_file[2], a->attachment_buffer[2], a->attachment_size[2],
2397 tag, sizeof(tag));
2398
2399 //printf("el_submit status %d, tag [%s]\n", status, tag);
2400
2401 if (status != EL_SUCCESS) {
2402 cm_msg(MERROR, "submit_elog", "el_submit() returned status %d", status);
2403 }
2404
2405 /* supersede host name with "/Elog/Host name" */
2406 std::string elog_host_name;
2407 db_get_value_string(hDB, 0, "/Elog/Host name", 0, &elog_host_name, TRUE);
2408
2409 // K.O. FIXME: we cannot guess the Elog URL like this because
2410 // we do not know if access is through a proxy or redirect
2411 // we do not know if it's http: or https:, etc. Better
2412 // to read the whole "mhttpd_full_url" string from ODB.
2413 sprintf(mhttpd_full_url, "http://%s/", elog_host_name.c_str());
2414
2415 /* check for mail submissions */
2416 mail_param[0] = 0;
2417 n_mail = 0;
2418
2419 for (int index = 0; index <= 1; index++) {
2420 std::string str;
2421 str += "/Elog/Email ";
2422 if (index == 0)
2423 str += pp->getparam("type");
2424 else
2425 str += pp->getparam("system");
2426
2427 if (db_find_key(hDB, 0, str.c_str(), &hkey) == DB_SUCCESS) {
2428 size = sizeof(mail_list);
2429 db_get_data(hDB, hkey, mail_list, &size, TID_STRING);
2430
2431 if (db_find_key(hDB, 0, "/Elog/SMTP host", &hkey) != DB_SUCCESS) {
2432 show_error(r, "No SMTP host defined under /Elog/SMTP host");
2433 return;
2434 }
2435 size = sizeof(smtp_host);
2436 db_get_data(hDB, hkey, smtp_host, &size, TID_STRING);
2437
2438 p = strtok(mail_list, ",");
2439 while (1) {
2440 mstrlcpy(mail_to, p, sizeof(mail_to));
2441
2442 std::string exptname;
2443 db_get_value_string(hDB, 0, "/Experiment/Name", 0, &exptname, TRUE);
2444
2445 sprintf(mail_from, "MIDAS %s <MIDAS@%s>", exptname.c_str(), elog_host_name.c_str());
2446
2447 std::string mail_text;
2448 mail_text += "A new entry has been submitted by ";
2449 mail_text += pp->getparam("author");
2450 mail_text += "\n";
2451 mail_text += "\n";
2452
2453 mail_text += "Experiment : ";
2454 mail_text += exptname.c_str();
2455 mail_text += "\n";
2456
2457 mail_text += "Type : ";
2458 mail_text += pp->getparam("type");
2459 mail_text += "\n";
2460
2461 mail_text += "System : ";
2462 mail_text += pp->getparam("system");
2463 mail_text += "\n";
2464
2465 mail_text += "Subject : ";
2466 mail_text += pp->getparam("subject");
2467 mail_text += "\n";
2468
2469 mail_text += "Link : ";
2470 mail_text += mhttpd_full_url;
2471 mail_text += "?cmd=Show+Elog&tag=";
2472 mail_text += tag;
2473 mail_text += "\n";
2474
2475 mail_text += "\n";
2476
2477 mail_text += pp->getparam("text");
2478 mail_text += "\n";
2479
2480 sendmail(elog_host_name.c_str(), smtp_host, mail_from, mail_to, pp->getparam("type"), mail_text.c_str());
2481
2482 if (mail_param[0] == 0)
2483 mstrlcpy(mail_param, "?", sizeof(mail_param));
2484 else
2485 mstrlcat(mail_param, "&", sizeof(mail_param));
2486 sprintf(mail_param + strlen(mail_param), "mail%d=%s", n_mail++, mail_to);
2487
2488 p = strtok(NULL, ",");
2489 if (!p)
2490 break;
2491 while (*p == ' ')
2492 p++;
2493 }
2494 }
2495 }
2496
2497 r->rsprintf("HTTP/1.1 302 Found\r\n");
2498 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2499
2500 //if (mail_param[0])
2501 // r->rsprintf("Location: ../EL/%s?%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2502 //else
2503 // r->rsprintf("Location: ../EL/%s\n\n<html>redir</html>\r\n", tag);
2504
2505 if (mail_param[0])
2506 r->rsprintf("Location: ?cmd=Show+elog&tag=%s&%s\n\n<html>redir</html>\r\n", tag, mail_param + 1);
2507 else
2508 r->rsprintf("Location: ?cmd=Show+elog&tag=%s\n\n<html>redir</html>\r\n", tag);
2509}
2510
2511/*------------------------------------------------------------------*/
2512
2513void show_elog_attachment(Param* p, Return* r, const char* path)
2514{
2515 HNDLE hDB;
2516 int size;
2517 int status;
2518 char file_name[256];
2519
2521 file_name[0] = 0;
2522 if (hDB > 0) {
2523 size = sizeof(file_name);
2524 memset(file_name, 0, size);
2525
2526 status = db_get_value(hDB, 0, "/Logger/Elog dir", file_name, &size, TID_STRING, FALSE);
2527 if (status != DB_SUCCESS)
2528 db_get_value(hDB, 0, "/Logger/Data dir", file_name, &size, TID_STRING, TRUE);
2529
2530 if (file_name[0] != 0)
2531 if (file_name[strlen(file_name) - 1] != DIR_SEPARATOR)
2532 mstrlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
2533 }
2534 mstrlcat(file_name, path, sizeof(file_name));
2535
2536 int fh = open(file_name, O_RDONLY | O_BINARY);
2537 if (fh > 0) {
2538 lseek(fh, 0, SEEK_END);
2539 int length = TELL(fh);
2540 lseek(fh, 0, SEEK_SET);
2541
2542 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
2543 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
2544 r->rsprintf("Accept-Ranges: bytes\r\n");
2545 //r->rsprintf("Content-disposition: attachment; filename=%s\r\n", path);
2546
2547 r->rsprintf("Content-Type: %s\r\n", get_content_type(file_name).c_str());
2548
2549 r->rsprintf("Content-Length: %d\r\n\r\n", length);
2550
2551 r->rread(file_name, fh, length);
2552
2553 close(fh);
2554 }
2555
2556 return;
2557}
2558
2559/*------------------------------------------------------------------*/
2560
2561BOOL is_editable(char *eq_name, char *var_name)
2562{
2563 HNDLE hDB, hkey;
2564 KEY key;
2565 char str[256];
2566 int i, size;
2567
2569 sprintf(str, "/Equipment/%s/Settings/Editable", eq_name);
2570 db_find_key(hDB, 0, str, &hkey);
2571
2572 /* if no editable entry found, use default */
2573 if (!hkey) {
2574 return (equal_ustring(var_name, "Demand") ||
2575 equal_ustring(var_name, "Output") || strncmp(var_name, "D_", 2) == 0);
2576 }
2577
2578 db_get_key(hDB, hkey, &key);
2579 for (i = 0; i < key.num_values; i++) {
2580 size = sizeof(str);
2581 db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
2583 return TRUE;
2584 }
2585 return FALSE;
2586}
2587
2588#ifdef OBSOLETE
2589void show_eqtable_page(Param* pp, Return* r, int refresh)
2590{
2591 int i, j, k, colspan, size, n_var, i_edit, i_set, line;
2592 char eq_name[32], group[32];
2593 char group_name[MAX_GROUPS][32], data[256], style[80];
2594 HNDLE hDB;
2595 char odb_path[256];
2596
2598
2599 /* check if variable to edit */
2600 i_edit = -1;
2601 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2602 i_edit = atoi(pp->getparam("index"));
2603
2604 /* check if variable to set */
2605 i_set = -1;
2606 if (equal_ustring(pp->getparam("cmd"), "Set"))
2607 i_set = atoi(pp->getparam("index"));
2608
2609 /* get equipment and group */
2610 if (pp->getparam("eq"))
2611 mstrlcpy(eq_name, pp->getparam("eq"), sizeof(eq_name));
2612 mstrlcpy(group, "All", sizeof(group));
2613 if (pp->getparam("group") && *pp->getparam("group"))
2614 mstrlcpy(group, pp->getparam("group"), sizeof(group));
2615
2616#if 0
2617 /* check for "names" in settings */
2618 if (eq_name[0]) {
2619 sprintf(str, "/Equipment/%s/Settings", eq_name);
2620 HNDLE hkeyset;
2621 db_find_key(hDB, 0, str, &hkeyset);
2622 HNDLE hkeynames = 0;
2623 if (hkeyset) {
2624 for (i = 0;; i++) {
2625 db_enum_link(hDB, hkeyset, i, &hkeynames);
2626
2627 if (!hkeynames)
2628 break;
2629
2630 KEY key;
2631 db_get_key(hDB, hkeynames, &key);
2632
2633 if (strncmp(key.name, "Names", 5) == 0)
2634 break;
2635 }
2636 }
2637
2638 /* redirect if no names found */
2639 if (!hkeyset || !hkeynames) {
2640 /* redirect */
2641 sprintf(str, "?cmd=odb&odb_path=/Equipment/%s/Variables", eq_name);
2642 redirect(r, str);
2643 return;
2644 }
2645 }
2646#endif
2647
2648 show_header(r, "MIDAS slow control", "", group, i_edit == -1 ? refresh : 0);
2649 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
2650 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
2651 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
2652 show_navigation_bar(r, "SC");
2653
2654 /*---- menu buttons ----*/
2655
2656 r->rsprintf("<tr><td colspan=15>\n");
2657
2658 if (equal_ustring(pp->getparam("cmd"), "Edit"))
2659 r->rsprintf("<input type=submit name=cmd value=Set>\n");
2660
2661 r->rsprintf("</tr>\n\n");
2662 r->rsprintf("</table>"); //end header table
2663
2664 r->rsprintf("<table class=\"ODBtable\" style=\"max-width:700px;\">"); //body table
2665
2666 /*---- enumerate SC equipment ----*/
2667
2668 r->rsprintf("<tr><td class=\"subStatusTitle\" colspan=15><i>Equipment:</i> &nbsp;&nbsp;\n");
2669
2670 HNDLE hkeyeqroot;
2671 db_find_key(hDB, 0, "/Equipment", &hkeyeqroot);
2672 if (hkeyeqroot)
2673 for (i = 0;; i++) {
2674 HNDLE hkeyeq;
2675 db_enum_link(hDB, hkeyeqroot, i, &hkeyeq);
2676
2677 if (!hkeyeq)
2678 break;
2679
2680 KEY eqkey;
2681 db_get_key(hDB, hkeyeq, &eqkey);
2682
2683 HNDLE hkeyset;
2684 db_find_key(hDB, hkeyeq, "Settings", &hkeyset);
2685 if (hkeyset) {
2686 for (j = 0;; j++) {
2687 HNDLE hkeynames;
2688 db_enum_link(hDB, hkeyset, j, &hkeynames);
2689
2690 if (!hkeynames)
2691 break;
2692
2693 KEY key;
2694 db_get_key(hDB, hkeynames, &key);
2695
2696 if (strncmp(key.name, "Names", 5) == 0) {
2697 if (equal_ustring(eq_name, eqkey.name))
2698 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", eqkey.name);
2699 else {
2700 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">%s</a> &nbsp;&nbsp;", urlEncode(eqkey.name).c_str(), eqkey.name);
2701 }
2702 break;
2703 }
2704 }
2705 }
2706 }
2707 r->rsprintf("</tr>\n");
2708
2709 if (!eq_name[0]) {
2710 r->rsprintf("</table>");
2711 return;
2712 }
2713
2714 /*---- display SC ----*/
2715
2716 n_var = 0;
2717 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2718 HNDLE hkeyeqnames;
2719 db_find_key(hDB, 0, names_path.c_str(), &hkeyeqnames);
2720
2721 if (hkeyeqnames) {
2722
2723 /*---- single name array ----*/
2724 r->rsprintf("<tr><td colspan=15><i>Groups:</i> &nbsp;&nbsp;");
2725
2726 /* "all" group */
2727 if (equal_ustring(group, "All"))
2728 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2729 else
2730 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2731
2732 /* collect groups */
2733
2734 memset(group_name, 0, sizeof(group_name));
2735 KEY key;
2736 db_get_key(hDB, hkeyeqnames, &key);
2737
2738 for (int level = 0; ; level++) {
2739 bool next_level = false;
2740 for (i = 0; i < key.num_values; i++) {
2741 char name_str[256];
2742 size = sizeof(name_str);
2743 db_get_data_index(hDB, hkeyeqnames, name_str, &size, i, TID_STRING);
2744
2745 char *s = strchr(name_str, '%');
2746 for (int k=0; s && k<level; k++)
2747 s = strchr(s+1, '%');
2748
2749 if (s) {
2750 *s = 0;
2751 if (strchr(s+1, '%'))
2752 next_level = true;
2753
2754 //printf("try group [%s] name [%s], level %d, %d\n", name_str, s+1, level, next_level);
2755
2756 for (j = 0; j < MAX_GROUPS; j++) {
2757 if (equal_ustring(group_name[j], name_str) || group_name[j][0] == 0)
2758 break;
2759 }
2760 if ((j < MAX_GROUPS) && (group_name[j][0] == 0))
2761 mstrlcpy(group_name[j], name_str, sizeof(group_name[0]));
2762 }
2763 }
2764
2765 if (!next_level)
2766 break;
2767 }
2768
2769 for (i = 0; i < MAX_GROUPS && group_name[i][0]; i++) {
2770 if (equal_ustring(group_name[i], group))
2771 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", group_name[i]);
2772 else {
2773 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]);
2774 }
2775 }
2776
2777 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2778 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2779 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2780 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2781 r->rsprintf("</tr>\n");
2782
2783 /* count variables */
2784 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2785 HNDLE hkeyvar;
2786 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2787 if (!hkeyvar) {
2788 r->rsprintf("</table>");
2789 return;
2790 }
2791 for (i = 0;; i++) {
2792 HNDLE hkey;
2793 db_enum_link(hDB, hkeyvar, i, &hkey);
2794 if (!hkey)
2795 break;
2796 }
2797
2798 if (i == 0 || i > 15) {
2799 r->rsprintf("</table>");
2800 return;
2801 }
2802
2803 /* title row */
2804 colspan = 15 - i;
2805 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=%d>Names", colspan);
2806
2807 /* display entries for this group */
2808 for (int i = 0;; i++) {
2809 HNDLE hkey;
2810 db_enum_link(hDB, hkeyvar, i, &hkey);
2811
2812 if (!hkey)
2813 break;
2814
2815 KEY key;
2816 db_get_key(hDB, hkey, &key);
2817 r->rsprintf("<th>%s", key.name);
2818 }
2819
2820 r->rsprintf("</tr>\n");
2821
2822 /* data for current group */
2823 std::string names_path = msprintf("/Equipment/%s/Settings/Names", eq_name);
2824 int num_values = 0;
2825 HNDLE hnames_key;
2826 db_find_key(hDB, 0, names_path.c_str(), &hnames_key);
2827 if (hnames_key) {
2828 KEY names_key;
2829 db_get_key(hDB, hnames_key, &names_key);
2830 num_values = names_key.num_values;
2831 }
2832 for (int i = 0; i < num_values; i++) {
2833 char names_str[256];
2834 size = sizeof(names_str);
2835 db_get_data_index(hDB, hnames_key, names_str, &size, i, TID_STRING);
2836
2837 char name[NAME_LENGTH+32];
2838 mstrlcpy(name, names_str, sizeof(name));
2839
2840 //printf("group [%s], name [%s], str [%s]\n", group, name, names_str);
2841
2842 if (!equal_ustring(group, "All")) {
2843 // check if name starts with the name of the group we want to display
2844 char *s = strstr(name, group);
2845 if (s != name)
2846 continue;
2847 if (name[strlen(group)] != '%')
2848 continue;
2849 }
2850
2851 if (strlen(name) < 1)
2852 sprintf(name, "[%d]", i);
2853
2854 if (i % 2 == 0)
2855 r->rsprintf("<tr class=\"ODBtableEven\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2856 else
2857 r->rsprintf("<tr class=\"ODBtableOdd\"><td colspan=%d><nobr>%s</nobr>", colspan, name);
2858
2859 for (int j = 0;; j++) {
2860 HNDLE hkey;
2861 db_enum_link(hDB, hkeyvar, j, &hkey);
2862 if (!hkey)
2863 break;
2864
2865 KEY varkey;
2866 db_get_key(hDB, hkey, &varkey);
2867
2868 /* check if "variables" array is shorter than the "names" array */
2869 if (i >= varkey.num_values)
2870 continue;
2871
2872 size = sizeof(data);
2873 db_get_data_index(hDB, hkey, data, &size, i, varkey.type);
2874 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
2875
2876 if (is_editable(eq_name, varkey.name)) {
2877 if (n_var == i_set) {
2878 /* set value */
2879 char str[256];
2880 mstrlcpy(str, pp->getparam("value"), sizeof(str));
2881 db_sscanf(str, data, &size, 0, varkey.type);
2882 db_set_data_index(hDB, hkey, data, size, i, varkey.type);
2883
2884 /* redirect (so that 'reload' does not reset value) */
2885 r->reset();
2886 redirect(r, group);
2887 return;
2888 }
2889 if (n_var == i_edit) {
2890 r->rsprintf("<td align=center>");
2891 r->rsprintf("<input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
2892 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
2893 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
2894 n_var++;
2895 } else {
2896 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, i);
2897 r->rsprintf("<td align=center>");
2898 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
2899 n_var++;
2900 }
2901 } else
2902 r->rsprintf("<td align=center>%s", data_str.c_str());
2903 }
2904
2905 r->rsprintf("</tr>\n");
2906 }
2907 } else {
2908 /*---- multiple name arrays ----*/
2909 r->rsprintf("<tr><td colspan=15><i>Groups:</i> ");
2910
2911 /* "all" group */
2912 if (equal_ustring(group, "All"))
2913 r->rsprintf("<b>All</b> &nbsp;&nbsp;");
2914 else
2915 r->rsprintf("<a href=\"?cmd=eqtable&eq=%s\">All</a> &nbsp;&nbsp;", eq_name);
2916
2917 /* groups from Variables tree */
2918
2919 std::string vars_path = msprintf("/Equipment/%s/Variables", eq_name);
2920 HNDLE hkeyvar;
2921 db_find_key(hDB, 0, vars_path.c_str(), &hkeyvar);
2922
2923 if (hkeyvar) {
2924 for (int i = 0;; i++) {
2925 HNDLE hkey;
2926 db_enum_link(hDB, hkeyvar, i, &hkey);
2927
2928 if (!hkey)
2929 break;
2930
2931 KEY key;
2932 db_get_key(hDB, hkey, &key);
2933
2934 if (equal_ustring(key.name, group)) {
2935 r->rsprintf("<b>%s</b> &nbsp;&nbsp;", key.name);
2936 } else {
2937 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);
2938 }
2939 }
2940 }
2941
2942 r->rsprintf("<i>ODB:</i> &nbsp;&nbsp;");
2943 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Common\">Common</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2944 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Settings\">Settings</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2945 r->rsprintf("<a href=\"?cmd=odb&odb_path=Equipment/%s/Variables\">Variables</a> &nbsp;&nbsp;", urlEncode(eq_name).c_str());
2946 r->rsprintf("</tr>\n");
2947
2948 /* enumerate variable arrays */
2949 line = 0;
2950 for (i = 0;; i++) {
2951 HNDLE hkey;
2952 db_enum_link(hDB, hkeyvar, i, &hkey);
2953
2954 if (line % 2 == 0)
2955 mstrlcpy(style, "ODBtableEven", sizeof(style));
2956 else
2957 mstrlcpy(style, "ODBtableOdd", sizeof(style));
2958
2959 if (!hkey)
2960 break;
2961
2962 KEY varkey;
2963 db_get_key(hDB, hkey, &varkey);
2964
2965 if (!equal_ustring(group, "All") && !equal_ustring(varkey.name, group))
2966 continue;
2967
2968 /* title row */
2969 r->rsprintf("<tr class=\"subStatusTitle\"><th colspan=9>Names<th>%s</tr>\n", varkey.name);
2970
2971 if (varkey.type == TID_KEY) {
2972 HNDLE hkeyroot = hkey;
2973
2974 /* enumerate subkeys */
2975 for (j = 0;; j++) {
2976 db_enum_key(hDB, hkeyroot, j, &hkey);
2977 if (!hkey)
2978 break;
2979
2980 KEY key;
2981 db_get_key(hDB, hkey, &key);
2982
2983 if (key.type == TID_KEY) {
2984 /* for keys, don't display data value */
2985 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<br></tr>\n", style, key.name);
2986 } else {
2987 /* display single value */
2988 if (key.num_values == 1) {
2989 size = sizeof(data);
2990 db_get_data(hDB, hkey, data, &size, key.type);
2991
2992 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
2993 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
2994
2995 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
2996 data_str = "(empty)";
2997 hex_str = "";
2998 }
2999
3000 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
3001 r->rsprintf
3002 ("<tr class=\"%s\" ><td colspan=9>%s<td align=center>%s (%s)<br></tr>\n",
3003 style, key.name, data_str.c_str(), hex_str.c_str());
3004 else
3005 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center>%s<br></tr>\n",
3006 style, key.name, data_str.c_str());
3007 line++;
3008 } else {
3009 /* display first value */
3010 r->rsprintf("<tr class=\"%s\"><td colspan=9 rowspan=%d>%s\n", style, key.num_values,
3011 key.name);
3012
3013 for (k = 0; k < key.num_values; k++) {
3014 size = sizeof(data);
3015 db_get_data_index(hDB, hkey, data, &size, k, key.type);
3016 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
3017 std::string hex_str = db_sprintfh(data, key.item_size, 0, key.type);
3018
3019 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
3020 data_str = "(empty)";
3021 hex_str = "";
3022 }
3023
3024 if (k > 0)
3025 r->rsprintf("<tr>");
3026
3027 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
3028 r->rsprintf("<td>[%d] %s (%s)<br></tr>\n", k, data_str.c_str(), hex_str.c_str());
3029 else
3030 r->rsprintf("<td>[%d] %s<br></tr>\n", k, data_str.c_str());
3031 line++;
3032 }
3033 }
3034 }
3035 }
3036 } else {
3037 /* data for current group */
3038 std::string names_path = msprintf("/Equipment/%s/Settings/Names %s", eq_name, varkey.name);
3039 HNDLE hkeyset;
3040 db_find_key(hDB, 0, names_path.c_str(), &hkeyset);
3041 KEY key;
3042 if (hkeyset)
3043 db_get_key(hDB, hkeyset, &key);
3044
3045 if (varkey.num_values > 1000)
3046 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s<td align=center><i>... %d values ...</i>",
3047 style, varkey.name, varkey.num_values);
3048 else {
3049 for (j = 0; j < varkey.num_values; j++) {
3050
3051 if (line % 2 == 0)
3052 mstrlcpy(style, "ODBtableEven", sizeof(style));
3053 else
3054 mstrlcpy(style, "ODBtableOdd", sizeof(style));
3055
3056 char name[NAME_LENGTH+32];
3057 if (hkeyset && j<key.num_values) {
3058 size = sizeof(name);
3059 db_get_data_index(hDB, hkeyset, name, &size, j, TID_STRING);
3060 } else {
3061 sprintf(name, "%s[%d]", varkey.name, j);
3062 }
3063
3064 if (strlen(name) < 1) {
3065 sprintf(name, "%s[%d]", varkey.name, j);
3066 }
3067
3068 r->rsprintf("<tr class=\"%s\"><td colspan=9>%s", style, name);
3069
3070 size = sizeof(data);
3071 db_get_data_index(hDB, hkey, data, &size, j, varkey.type);
3072 std::string data_str = db_sprintf(data, varkey.item_size, 0, varkey.type);
3073
3074 if (is_editable(eq_name, varkey.name)) {
3075 if (n_var == i_set) {
3076 /* set value */
3077 char str[256];
3078 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3079 db_sscanf(str, data, &size, 0, varkey.type);
3080 db_set_data_index(hDB, hkey, data, size, j, varkey.type);
3081
3082 /* redirect (so that 'reload' does not reset value) */
3083 r->reset();
3084 sprintf(str, "%s", group);
3085 redirect(r, str);
3086 return;
3087 }
3088 if (n_var == i_edit) {
3089 r->rsprintf("<td align=center><input type=text size=10 maxlenth=80 name=value value=\"%s\">\n", data_str.c_str());
3090 r->rsprintf("<input type=submit size=20 name=cmd value=Set></tr>\n");
3091 r->rsprintf("<input type=hidden name=index value=%d>\n", i_edit);
3092 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3093 n_var++;
3094 } else {
3095 sprintf(odb_path, "Equipment/%s/Variables/%s[%d]", eq_name, varkey.name, j);
3096
3097 r->rsprintf("<td align=cernter>");
3098 r->rsprintf("<a href=\"#\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\', 0);return false;\" >%s</a>", odb_path, data_str.c_str());
3099 n_var++;
3100 }
3101
3102 } else
3103 r->rsprintf("<td align=center>%s\n", data_str.c_str());
3104 r->rsprintf("</tr>\n");
3105 line++;
3106 }
3107 }
3108
3109 r->rsprintf("</tr>\n");
3110 }
3111 }
3112 }
3113
3114 r->rsprintf("</table>\n");
3115 r->rsprintf("</div>\n"); // closing for <div id="mmain">
3116 r->rsprintf("</form>\n");
3117 r->rsprintf("</body></html>\r\n");
3118}
3119#endif
3120
3121/*------------------------------------------------------------------*/
3122
3123char *find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
3124{
3125 char str[256], *ps, *pt;
3126 BOOL in_script;
3127
3128 *edit = 0;
3129 *tail = 0;
3130 *format = 0;
3131 pwd[0] = 0;
3132 in_script = FALSE;
3133 strcpy(type, "text");
3134 do {
3135 while (*p && *p != '<')
3136 p++;
3137
3138 /* return if end of string reached */
3139 if (!*p)
3140 return NULL;
3141
3142 p++;
3143 while (*p && ((*p == ' ') || iscntrl(*p)))
3144 p++;
3145
3146 strncpy(str, p, 6);
3147 str[6] = 0;
3148 if (equal_ustring(str, "script"))
3149 in_script = TRUE;
3150
3151 strncpy(str, p, 7);
3152 str[7] = 0;
3153 if (equal_ustring(str, "/script"))
3154 in_script = FALSE;
3155
3156 strncpy(str, p, 4);
3157 str[4] = 0;
3158 if (equal_ustring(str, "odb ")) {
3159 ps = p - 1;
3160 p += 4;
3161 while (*p && ((*p == ' ') || iscntrl(*p)))
3162 p++;
3163
3164 do {
3165 strncpy(str, p, 7);
3166 str[7] = 0;
3167 if (equal_ustring(str, "format=")) {
3168 p += 7;
3169 if (*p == '\"') {
3170 p++;
3171 while (*p && *p != '\"')
3172 *format++ = *p++;
3173 *format = 0;
3174 if (*p == '\"')
3175 p++;
3176 } else {
3177 while (*p && *p != ' ' && *p != '>')
3178 *format++ = *p++;
3179 *format = 0;
3180 }
3181
3182 } else {
3183
3184 strncpy(str, p, 4);
3185 str[4] = 0;
3186 if (equal_ustring(str, "src=")) {
3187 p += 4;
3188 if (*p == '\"') {
3189 p++;
3190 while (*p && *p != '\"')
3191 *path++ = *p++;
3192 *path = 0;
3193 if (*p == '\"')
3194 p++;
3195 } else {
3196 while (*p && *p != ' ' && *p != '>')
3197 *path++ = *p++;
3198 *path = 0;
3199 }
3200 } else {
3201
3202 if (in_script)
3203 break;
3204
3205 strncpy(str, p, 5);
3206 str[5] = 0;
3207 if (equal_ustring(str, "edit=")) {
3208 p += 5;
3209
3210 if (*p == '\"') {
3211 p++;
3212 *edit = atoi(p);
3213 if (*p == '\"')
3214 p++;
3215 } else {
3216 *edit = atoi(p);
3217 while (*p && *p != ' ' && *p != '>')
3218 p++;
3219 }
3220
3221 } else {
3222
3223 strncpy(str, p, 5);
3224 str[5] = 0;
3225 if (equal_ustring(str, "type=")) {
3226 p += 5;
3227 if (*p == '\"') {
3228 p++;
3229 while (*p && *p != '\"')
3230 *type++ = *p++;
3231 *type = 0;
3232 if (*p == '\"')
3233 p++;
3234 } else {
3235 while (*p && *p != ' ' && *p != '>')
3236 *type++ = *p++;
3237 *type = 0;
3238 }
3239 } else {
3240 strncpy(str, p, 4);
3241 str[4] = 0;
3242 if (equal_ustring(str, "pwd=")) {
3243 p += 4;
3244 if (*p == '\"') {
3245 p++;
3246 while (*p && *p != '\"')
3247 *pwd++ = *p++;
3248 *pwd = 0;
3249 if (*p == '\"')
3250 p++;
3251 } else {
3252 while (*p && *p != ' ' && *p != '>')
3253 *pwd++ = *p++;
3254 *pwd = 0;
3255 }
3256 } else {
3257 if (strchr(p, '=')) {
3258 mstrlcpy(str, p, sizeof(str));
3259 pt = strchr(str, '=')+1;
3260 if (*pt == '\"') {
3261 pt++;
3262 while (*pt && *pt != '\"')
3263 pt++;
3264 if (*pt == '\"')
3265 pt++;
3266 *pt = 0;
3267 } else {
3268 while (*pt && *pt != ' ' && *pt != '>')
3269 pt++;
3270 *pt = 0;
3271 }
3272 if (tail[0]) {
3273 mstrlcat(tail, " ", 256);
3274 mstrlcat(tail, str, 256);
3275 } else {
3276 mstrlcat(tail, str, 256);
3277 }
3278 p += strlen(str);
3279 }
3280 }
3281 }
3282 }
3283 }
3284 }
3285
3286 while (*p && ((*p == ' ') || iscntrl(*p)))
3287 p++;
3288
3289 if (*p == '<') {
3290 cm_msg(MERROR, "find_odb_tag", "Invalid odb tag '%s'", ps);
3291 return NULL;
3292 }
3293 } while (*p != '>');
3294
3295 return ps;
3296 }
3297
3298 while (*p && *p != '>')
3299 p++;
3300
3301 } while (1);
3302
3303}
3304
3305/*------------------------------------------------------------------*/
3306
3307void 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)
3308{
3309 int size, index, i_edit, i_set;
3310 char data[TEXT_SIZE], full_keypath[256], keypath[256], *p;
3311 HNDLE hDB, hkey;
3312 KEY key;
3313
3314 /* check if variable to edit */
3315 i_edit = -1;
3316 if (equal_ustring(pp->getparam("cmd"), "Edit"))
3317 i_edit = atoi(pp->getparam("index"));
3318
3319 /* check if variable to set */
3320 i_set = -1;
3321 if (equal_ustring(pp->getparam("cmd"), "Set"))
3322 i_set = atoi(pp->getparam("index"));
3323
3324 /* check if path contains index */
3325 mstrlcpy(full_keypath, keypath1, sizeof(full_keypath));
3326 mstrlcpy(keypath, keypath1, sizeof(keypath));
3327 index = 0;
3328
3329 if (strchr(keypath, '[') && strchr(keypath, ']')) {
3330 for (p = strchr(keypath, '[') + 1; *p && *p != ']'; p++)
3331 if (!isdigit(*p))
3332 break;
3333
3334 if (*p && *p == ']') {
3335 index = atoi(strchr(keypath, '[') + 1);
3336 *strchr(keypath, '[') = 0;
3337 }
3338 }
3339
3341 db_find_key(hDB, 0, keypath, &hkey);
3342 if (!hkey)
3343 r->rsprintf("<b>Key \"%s\" not found in ODB</b>\n", keypath);
3344 else {
3345 db_get_key(hDB, hkey, &key);
3346 size = sizeof(data);
3347 db_get_data_index(hDB, hkey, data, &size, index, key.type);
3348
3349 std::string data_str;
3350 if (format && strlen(format)>0)
3351 data_str = db_sprintff(format, data, key.item_size, 0, key.type);
3352 else
3353 data_str= db_sprintf(data, key.item_size, 0, key.type);
3354
3355 if (equal_ustring(type, "checkbox")) {
3356
3357 if (pp->isparam("cbi"))
3358 i_set = atoi(pp->getparam("cbi"));
3359 if (n_var == i_set) {
3360 /* toggle state */
3361 if (key.type == TID_BOOL) {
3362 if (data_str[0] == 'y')
3363 data_str = "n";
3364 else
3365 data_str = "y";
3366 } else {
3367 if (atoi(data_str.c_str()) > 0)
3368 data_str = "0";
3369 else
3370 data_str = "1";
3371 }
3372
3373 db_sscanf(data_str.c_str(), data, &size, 0, key.type);
3374 db_set_data_index(hDB, hkey, data, size, index, key.type);
3375 }
3376
3377 std::string options;
3378 if (data_str[0] == 'y' || atoi(data_str.c_str()) > 0)
3379 options += "checked ";
3380 if (!edit)
3381 options += "disabled ";
3382 else {
3383 if (edit == 1) {
3384 options += "onClick=\"o=document.createElement('input');o.type='hidden';o.name='cbi';o.value='";
3385 options += msprintf("%d", n_var);
3386 options += "';document.form1.appendChild(o);";
3387 options += "document.form1.submit();\" ";
3388 }
3389 }
3390
3391 if (tail[0])
3392 options += tail;
3393
3394 r->rsprintf("<input type=\"checkbox\" %s>\n", options.c_str());
3395
3396 } else { // checkbox
3397
3398 if (edit == 1) {
3399 if (n_var == i_set) {
3400 /* set value */
3401 char str[256];
3402 mstrlcpy(str, pp->getparam("value"), sizeof(str));
3403 db_sscanf(str, data, &size, 0, key.type);
3404 db_set_data_index(hDB, hkey, data, size, index, key.type);
3405
3406 /* read back value */
3407 size = sizeof(data);
3408 db_get_data_index(hDB, hkey, data, &size, index, key.type);
3409 data_str = db_sprintf(data, key.item_size, 0, key.type);
3410 }
3411
3412 if (n_var == i_edit) {
3413 r->rsprintf("<input type=text size=10 maxlength=80 name=value value=\"%s\">\n", data_str.c_str());
3414 r->rsprintf("<input type=submit size=20 name=cmd value=Set>\n");
3415 r->rsprintf("<input type=hidden name=index value=%d>\n", n_var);
3416 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
3417 } else {
3418 if (edit == 2) {
3419 /* edit handling through user supplied JavaScript */
3420 r->rsprintf("<a href=\"#\" %s>", tail);
3421 } else {
3422 /* edit handling through form submission */
3423 if (pwd[0]) {
3424 r->rsprintf("<a onClick=\"promptpwd('%s?cmd=Edit&index=%d&pnam=%s')\" href=\"#\">", path, n_var, pwd);
3425 } else {
3426 r->rsprintf("<a href=\"%s?cmd=Edit&index=%d\" %s>", path, n_var, tail);
3427 }
3428 }
3429
3430 r->rsputs(data_str.c_str());
3431 r->rsprintf("</a>");
3432 }
3433 } else if (edit == 2) {
3434 r->rsprintf("<a href=\"#\" onclick=\"ODBEdit('%s')\">\n", full_keypath);
3435 r->rsputs(data_str.c_str());
3436 r->rsprintf("</a>");
3437 }
3438 else
3439 r->rsputs(data_str.c_str());
3440 }
3441 }
3442}
3443
3444/*------------------------------------------------------------------*/
3445
3446/* add labels using following syntax under /Custom/Images/<name.gif>/Labels/<name>:
3447
3448 [Name] [Description] [Example]
3449
3450 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3451 Format Formt for float/double %1.2f Deg. C
3452 Font Font to use small | medium | giant
3453 X X-position in pixel 90
3454 Y Y-position from top 67
3455 Align horizontal align left/center/right left
3456 FGColor Foreground color RRGGBB 000000
3457 BGColor Background color RRGGBB FFFFFF
3458*/
3459
3460static const char *cgif_label_str[] = {
3461 "Src = STRING : [256] ",
3462 "Format = STRING : [32] %1.1f",
3463 "Font = STRING : [32] Medium",
3464 "X = INT : 0",
3465 "Y = INT : 0",
3466 "Align = INT : 0",
3467 "FGColor = STRING : [8] 000000",
3468 "BGColor = STRING : [8] FFFFFF",
3469 NULL
3470};
3471
3472typedef struct {
3473 char src[256];
3474 char format[32];
3475 char font[32];
3476 int x, y, align;
3477 char fgcolor[8];
3478 char bgcolor[8];
3479} CGIF_LABEL;
3480
3481/* add labels using following syntax under /Custom/Images/<name.gif>/Bars/<name>:
3482
3483 [Name] [Description] [Example]
3484
3485 Src ODB path for vairable to display /Equipment/Environment/Variables/Input[0]
3486 X X-position in pixel 90
3487 Y Y-position from top 67
3488 Width Width in pixel 20
3489 Height Height in pixel 100
3490 Direction 0(vertical)/1(horiz.) 0
3491 Axis Draw axis 0(none)/1(left)/2(right) 1
3492 Logscale Draw logarithmic axis n
3493 Min Min value for axis 0
3494 Max Max value for axis 10
3495 FGColor Foreground color RRGGBB 000000
3496 BGColor Background color RRGGBB FFFFFF
3497 BDColor Border color RRGGBB 808080
3498*/
3499
3500static const char *cgif_bar_str[] = {
3501 "Src = STRING : [256] ",
3502 "X = INT : 0",
3503 "Y = INT : 0",
3504 "Width = INT : 10",
3505 "Height = INT : 100",
3506 "Direction = INT : 0",
3507 "Axis = INT : 1",
3508 "Logscale = BOOL : n",
3509 "Min = DOUBLE : 0",
3510 "Max = DOUBLE : 10",
3511 "FGColor = STRING : [8] 000000",
3512 "BGColor = STRING : [8] FFFFFF",
3513 "BDColor = STRING : [8] 808080",
3514 NULL
3515};
3516
3517typedef struct {
3518 char src[256];
3519 int x, y, width, height, direction, axis;
3521 double min, max;
3522 char fgcolor[8];
3523 char bgcolor[8];
3524 char bdcolor[8];
3525} CGIF_BAR;
3526
3527/*------------------------------------------------------------------*/
3528
3529int evaluate_src(char *key, char *src, double *fvalue)
3530{
3531 HNDLE hDB, hkeyval;
3532 KEY vkey;
3533 int i, n, size, ivalue;
3534 char str[256], data[256];
3535
3537
3538 /* separate source from operators */
3539 for (i=0 ; i<(int)strlen(src) ; i++)
3540 if (src[i] == '>' || src[i] == '&')
3541 break;
3542 strncpy(str, src, i);
3543 str[i] = 0;
3544
3545 /* strip trailing blanks */
3546 while (strlen(str) > 0 && str[strlen(str)-1] == ' ')
3547 str[strlen(str)-1] = 0;
3548
3549 db_find_key(hDB, 0, str, &hkeyval);
3550 if (!hkeyval) {
3551 cm_msg(MERROR, "evaluate_src", "Invalid Src key \"%s\" for Fill \"%s\"",
3552 src, key);
3553 return 0;
3554 }
3555
3556 db_get_key(hDB, hkeyval, &vkey);
3557 size = sizeof(data);
3558 db_get_value(hDB, 0, src, data, &size, vkey.type, FALSE);
3559 std::string value = db_sprintf(data, size, 0, vkey.type);
3560 if (equal_ustring(value.c_str(), "NAN"))
3561 return 0;
3562
3563 if (vkey.type == TID_BOOL) {
3564 *fvalue = (value[0] == 'y');
3565 } else
3566 *fvalue = atof(value.c_str());
3567
3568 /* evaluate possible operators */
3569 do {
3570 if (src[i] == '>' && src[i+1] == '>') {
3571 i+=2;
3572 n = atoi(src+i);
3573 while (src[i] == ' ' || isdigit(src[i]))
3574 i++;
3575 ivalue = (int)*fvalue;
3576 ivalue >>= n;
3577 *fvalue = ivalue;
3578 }
3579
3580 if (src[i] == '&') {
3581 i+=1;
3582 while (src[i] == ' ')
3583 i++;
3584 if (src[i] == '0' && src[i+1] == 'x')
3585 sscanf(src+2+i, "%x", &n);
3586 else
3587 n = atoi(src+i);
3588 while (src[i] == ' ' || isxdigit(src[i]) || src[i] == 'x')
3589 i++;
3590 ivalue = (int)*fvalue;
3591 ivalue &= n;
3592 *fvalue = ivalue;
3593 }
3594
3595 } while (src[i]);
3596
3597 return 1;
3598}
3599
3600/*------------------------------------------------------------------*/
3601
3602std::string add_custom_path(const std::string& filename)
3603{
3604 // do not append custom path to absolute filenames
3605
3606 if (filename[0] == '/')
3607 return filename;
3608 if (filename[0] == DIR_SEPARATOR)
3609 return filename;
3610
3611 HNDLE hDB;
3613
3614 std::string custom_path = "";
3615
3616 int status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
3617
3618 if (status != DB_SUCCESS)
3619 return filename;
3620
3621 if (custom_path.length() < 1)
3622 return filename;
3623
3624 if ((custom_path == DIR_SEPARATOR_STR) || !strchr(custom_path.c_str(), DIR_SEPARATOR)) {
3625 cm_msg(MERROR, "add_custom_path", "ODB /Custom/Path has a forbidden value \"%s\", please change it", custom_path.c_str());
3626 return filename;
3627 }
3628
3629 custom_path = ss_replace_env_variables(custom_path);
3630
3631 std::string full_filename = custom_path;
3632 if (full_filename[full_filename.length()-1] != DIR_SEPARATOR)
3633 full_filename += DIR_SEPARATOR_STR;
3634 full_filename += filename;
3635
3636 return full_filename;
3637}
3638
3639/*------------------------------------------------------------------*/
3640
3641void show_custom_file(Return* r, const char *name)
3642{
3643 char str[256];
3644 std::string filename;
3645 HNDLE hDB;
3646
3648
3649 HNDLE hkey;
3650 sprintf(str, "/Custom/%s", name);
3651 db_find_key(hDB, 0, str, &hkey);
3652
3653 if (!hkey) {
3654 sprintf(str, "/Custom/%s&", name);
3655 db_find_key(hDB, 0, str, &hkey);
3656 if (!hkey) {
3657 sprintf(str, "/Custom/%s!", name);
3658 db_find_key(hDB, 0, str, &hkey);
3659 }
3660 }
3661
3662 if(!hkey){
3663 sprintf(str,"show_custom_file: Invalid custom page: \"/Custom/%s\" not found in ODB", name);
3664 show_error_404(r, str);
3665 return;
3666 }
3667
3668 int status;
3669 KEY key;
3670
3671 status = db_get_key(hDB, hkey, &key);
3672
3673 if (status != DB_SUCCESS) {
3674 char errtext[512];
3675 sprintf(errtext, "show_custom_file: Error: db_get_key() for \"%s\" status %d", str, status);
3676 show_error_404(r, errtext);
3677 return;
3678 }
3679
3680 int size = key.total_size;
3681 char* ctext = (char*)malloc(size);
3682
3683 status = db_get_data(hDB, hkey, ctext, &size, TID_STRING);
3684
3685 if (status != DB_SUCCESS) {
3686 char errtext[512];
3687 sprintf(errtext, "show_custom_file: Error: db_get_data() for \"%s\" status %d", str, status);
3688 show_error_404(r, errtext);
3689 free(ctext);
3690 return;
3691 }
3692
3693 filename = add_custom_path(ctext);
3694
3695 free(ctext);
3696
3697 send_file(r, filename, true);
3698
3699 return;
3700}
3701
3702/*------------------------------------------------------------------*/
3703
3704void show_custom_gif(Return* rr, const char *name)
3705{
3706 char str[256], data[256], src[256];
3707 int i, index, length, status, size, width, height, bgcol, fgcol, bdcol, r, g, b, x, y;
3708 HNDLE hDB, hkeygif, hkeyroot, hkey, hkeyval;
3709 double fvalue, ratio;
3710 KEY key, vkey;
3711 gdImagePtr im;
3712 gdGifBuffer gb;
3713 gdFontPtr pfont;
3714 FILE *f;
3715 CGIF_LABEL label;
3716 CGIF_BAR bar;
3717
3719
3720 /* find image description in ODB */
3721 sprintf(str, "/Custom/Images/%s", name);
3722 db_find_key(hDB, 0, str, &hkeygif);
3723 if (!hkeygif) {
3724
3725 // If we don't have Images directory,
3726 // then just treat this like any other custom file.
3728 return;
3729 }
3730
3731 /* load background image */
3732 std::string filename;
3733 db_get_value_string(hDB, hkeygif, "Background", 0, &filename, FALSE);
3734
3735 std::string full_filename = add_custom_path(filename);
3736
3737 f = fopen(full_filename.c_str(), "rb");
3738 if (f == NULL) {
3739 sprintf(str, "show_custom_gif: Cannot open file \"%s\"", full_filename.c_str());
3740 show_error_404(rr, str);
3741 return;
3742 }
3743
3744 im = gdImageCreateFromGif(f);
3745 fclose(f);
3746
3747 if (im == NULL) {
3748 sprintf(str, "show_custom_gif: File \"%s\" is not a GIF image", filename.c_str());
3749 show_error_404(rr, str);
3750 return;
3751 }
3752
3754
3755 /*---- draw labels ----------------------------------------------*/
3756
3757 db_find_key(hDB, hkeygif, "Labels", &hkeyroot);
3758 if (hkeyroot) {
3759 for (index = 0;; index++) {
3760 db_enum_key(hDB, hkeyroot, index, &hkey);
3761 if (!hkey)
3762 break;
3763 db_get_key(hDB, hkey, &key);
3764
3765 size = sizeof(label);
3766 status = db_get_record1(hDB, hkey, &label, &size, 0, strcomb1(cgif_label_str).c_str());
3767 if (status != DB_SUCCESS) {
3768 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for label \"%s\"",
3769 key.name);
3770 continue;
3771 }
3772
3773 if (label.src[0] == 0) {
3774 cm_msg(MERROR, "show_custom_gif", "Empty Src key for label \"%s\"", key.name);
3775 continue;
3776 }
3777
3778 db_find_key(hDB, 0, label.src, &hkeyval);
3779 if (!hkeyval) {
3780 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for label \"%s\"",
3781 label.src, key.name);
3782 continue;
3783 }
3784
3785 db_get_key(hDB, hkeyval, &vkey);
3786 size = sizeof(data);
3787 status = db_get_value(hDB, 0, label.src, data, &size, vkey.type, FALSE);
3788
3789 std::string value;
3790
3791 if (label.format[0]) {
3792 if (vkey.type == TID_FLOAT)
3793 value = msprintf(label.format, *(((float *) data)));
3794 else if (vkey.type == TID_DOUBLE)
3795 value = msprintf(label.format, *(((double *) data)));
3796 else if (vkey.type == TID_INT)
3797 value = msprintf(label.format, *(((INT *) data)));
3798 else if (vkey.type == TID_BOOL) {
3799 if (strstr(label.format, "%c"))
3800 value = msprintf(label.format, *(((INT *) data)) ? 'y' : 'n');
3801 else
3802 value = msprintf(label.format, *(((INT *) data)));
3803 } else
3804 value = db_sprintf(data, size, 0, vkey.type);
3805 } else
3806 value = db_sprintf(data, size, 0, vkey.type);
3807
3808 sscanf(label.fgcolor, "%02x%02x%02x", &r, &g, &b);
3809 fgcol = gdImageColorAllocate(im, r, g, b);
3810 if (fgcol == -1)
3811 fgcol = gdImageColorClosest(im, r, g, b);
3812
3813 sscanf(label.bgcolor, "%02x%02x%02x", &r, &g, &b);
3814 bgcol = gdImageColorAllocate(im, r, g, b);
3815 if (bgcol == -1)
3816 bgcol = gdImageColorClosest(im, r, g, b);
3817
3818 /* select font */
3819 if (equal_ustring(label.font, "Small"))
3820 pfont = gdFontSmall;
3821 else if (equal_ustring(label.font, "Medium"))
3822 pfont = gdFontMediumBold;
3823 else if (equal_ustring(label.font, "Giant"))
3824 pfont = gdFontGiant;
3825 else
3826 pfont = gdFontMediumBold;
3827
3828 width = value.length() * pfont->w + 5 + 5;
3829 height = pfont->h + 2 + 2;
3830
3831 if (label.align == 0) {
3832 /* left */
3833 gdImageFilledRectangle(im, label.x, label.y, label.x + width,
3834 label.y + height, bgcol);
3835 gdImageRectangle(im, label.x, label.y, label.x + width, label.y + height,
3836 fgcol);
3837 gdImageString(im, pfont, label.x + 5, label.y + 2, value.c_str(), fgcol);
3838 } else if (label.align == 1) {
3839 /* center */
3840 gdImageFilledRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3841 label.y + height, bgcol);
3842 gdImageRectangle(im, label.x - width / 2, label.y, label.x + width / 2,
3843 label.y + height, fgcol);
3844 gdImageString(im, pfont, label.x + 5 - width / 2, label.y + 2, value.c_str(), fgcol);
3845 } else {
3846 /* right */
3847 gdImageFilledRectangle(im, label.x - width, label.y, label.x,
3848 label.y + height, bgcol);
3849 gdImageRectangle(im, label.x - width, label.y, label.x, label.y + height,
3850 fgcol);
3851 gdImageString(im, pfont, label.x - width + 5, label.y + 2, value.c_str(), fgcol);
3852 }
3853 }
3854 }
3855
3856 /*---- draw bars ------------------------------------------------*/
3857
3858 db_find_key(hDB, hkeygif, "Bars", &hkeyroot);
3859 if (hkeyroot) {
3860 for (index = 0;; index++) {
3861 db_enum_key(hDB, hkeyroot, index, &hkey);
3862 if (!hkey)
3863 break;
3864 db_get_key(hDB, hkey, &key);
3865
3866 size = sizeof(bar);
3867 status = db_get_record1(hDB, hkey, &bar, &size, 0, strcomb1(cgif_bar_str).c_str());
3868 if (status != DB_SUCCESS) {
3869 cm_msg(MERROR, "show_custom_gif", "Cannot open data record for bar \"%s\"",
3870 key.name);
3871 continue;
3872 }
3873
3874 if (bar.src[0] == 0) {
3875 cm_msg(MERROR, "show_custom_gif", "Empty Src key for bar \"%s\"", key.name);
3876 continue;
3877 }
3878
3879 db_find_key(hDB, 0, bar.src, &hkeyval);
3880 if (!hkeyval) {
3881 cm_msg(MERROR, "show_custom_gif", "Invalid Src key \"%s\" for bar \"%s\"",
3882 bar.src, key.name);
3883 continue;
3884 }
3885
3886 db_get_key(hDB, hkeyval, &vkey);
3887 size = sizeof(data);
3888 status = db_get_value(hDB, 0, bar.src, data, &size, vkey.type, FALSE);
3889 std::string value = db_sprintf(data, size, 0, vkey.type);
3890 if (equal_ustring(value.c_str(), "NAN"))
3891 continue;
3892
3893 fvalue = atof(value.c_str());
3894
3895 sscanf(bar.fgcolor, "%02x%02x%02x", &r, &g, &b);
3896 fgcol = gdImageColorAllocate(im, r, g, b);
3897 if (fgcol == -1)
3898 fgcol = gdImageColorClosest(im, r, g, b);
3899
3900 sscanf(bar.bgcolor, "%02x%02x%02x", &r, &g, &b);
3901 bgcol = gdImageColorAllocate(im, r, g, b);
3902 if (bgcol == -1)
3903 bgcol = gdImageColorClosest(im, r, g, b);
3904
3905 sscanf(bar.bdcolor, "%02x%02x%02x", &r, &g, &b);
3906 bdcol = gdImageColorAllocate(im, r, g, b);
3907 if (bdcol == -1)
3908 bdcol = gdImageColorClosest(im, r, g, b);
3909
3910 if (bar.min == bar.max)
3911 bar.max += 1;
3912
3913 if (bar.logscale) {
3914 if (fvalue < 1E-20)
3915 fvalue = 1E-20;
3916 ratio = (log(fvalue) - log(bar.min)) / (log(bar.max) - log(bar.min));
3917 } else
3918 ratio = (fvalue - bar.min) / (bar.max - bar.min);
3919 if (ratio < 0)
3920 ratio = 0;
3921 if (ratio > 1)
3922 ratio = 1;
3923
3924 if (bar.direction == 0) {
3925 /* vertical */
3926 ratio = (bar.height - 2) - ratio * (bar.height - 2);
3927 r = (int) (ratio + 0.5);
3928
3929 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.width,
3930 bar.y + bar.height, bgcol);
3931 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.width, bar.y + bar.height,
3932 bdcol);
3933 gdImageFilledRectangle(im, bar.x + 1, bar.y + r + 1, bar.x + bar.width - 1,
3934 bar.y + bar.height - 1, fgcol);
3935
3936 if (bar.axis == 1)
3937 vaxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.height, bar.height, -3,
3938 -5, -7, -8, 0, bar.min, bar.max, bar.logscale);
3939 else if (bar.axis == 2)
3940 vaxis(im, gdFontSmall, bdcol, 0, bar.x + bar.width, bar.y + bar.height,
3941 bar.height, 3, 5, 7, 10, 0, bar.min, bar.max, bar.logscale);
3942
3943 } else {
3944 /* horizontal */
3945 ratio = ratio * (bar.height - 2);
3946 r = (int) (ratio + 0.5);
3947
3948 gdImageFilledRectangle(im, bar.x, bar.y, bar.x + bar.height,
3949 bar.y + bar.width, bgcol);
3950 gdImageRectangle(im, bar.x, bar.y, bar.x + bar.height, bar.y + bar.width,
3951 bdcol);
3952 gdImageFilledRectangle(im, bar.x + 1, bar.y + 1, bar.x + r,
3953 bar.y + bar.width - 1, fgcol);
3954
3955 if (bar.axis == 1)
3956 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y, bar.height, -3, -5, -7, -18,
3957 0, bar.min, bar.max);
3958 else if (bar.axis == 2)
3959 haxis(im, gdFontSmall, bdcol, 0, bar.x, bar.y + bar.width, bar.height, 3,
3960 5, 7, 8, 0, bar.min, bar.max);
3961 }
3962 }
3963 }
3964
3965 /*---- draw fills -----------------------------------------------*/
3966
3967 db_find_key(hDB, hkeygif, "Fills", &hkeyroot);
3968 if (hkeyroot) {
3969 for (index = 0;; index++) {
3970 db_enum_key(hDB, hkeyroot, index, &hkey);
3971 if (!hkey)
3972 break;
3973 db_get_key(hDB, hkey, &key);
3974
3975 size = sizeof(src);
3976 src[0] = 0;
3977 db_get_value(hDB, hkey, "Src", src, &size, TID_STRING, TRUE);
3978
3979 if (src[0] == 0) {
3980 cm_msg(MERROR, "show_custom_gif", "Empty Src key for Fill \"%s\"", key.name);
3981 continue;
3982 }
3983
3984 if (!evaluate_src(key.name, src, &fvalue))
3985 continue;
3986
3987 x = y = 0;
3988 size = sizeof(x);
3989 db_get_value(hDB, hkey, "X", &x, &size, TID_INT, TRUE);
3990 db_get_value(hDB, hkey, "Y", &y, &size, TID_INT, TRUE);
3991
3992 size = sizeof(data);
3993 status = db_get_value(hDB, hkey, "Limits", data, &size, TID_DOUBLE, FALSE);
3994 if (status != DB_SUCCESS) {
3995 cm_msg(MERROR, "show_custom_gif", "No \"Limits\" entry for Fill \"%s\"",
3996 key.name);
3997 continue;
3998 }
3999 for (i = 0; i < size / (int) sizeof(double); i++)
4000 if (*((double *) data + i) > fvalue)
4001 break;
4002 if (i > 0)
4003 i--;
4004
4005 db_find_key(hDB, hkey, "Fillcolors", &hkeyval);
4006 if (!hkeyval) {
4007 cm_msg(MERROR, "show_custom_gif", "No \"Fillcolors\" entry for Fill \"%s\"",
4008 key.name);
4009 continue;
4010 }
4011
4012 size = sizeof(data);
4013 strcpy(data, "FFFFFF");
4014 status = db_get_data_index(hDB, hkeyval, data, &size, i, TID_STRING);
4015 if (status == DB_SUCCESS) {
4016 sscanf(data, "%02x%02x%02x", &r, &g, &b);
4017 fgcol = gdImageColorAllocate(im, r, g, b);
4018 if (fgcol == -1)
4019 fgcol = gdImageColorClosest(im, r, g, b);
4020 gdImageFill(im, x, y, fgcol);
4021 }
4022 }
4023 }
4024
4025 /* generate GIF */
4026 gdImageInterlace(im, 1);
4027 gdImageGif(im, &gb);
4028 gdImageDestroy(im);
4029 length = gb.size;
4030
4031 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
4032 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
4033
4034 rr->rsprintf("Content-Type: image/gif\r\n");
4035 rr->rsprintf("Content-Length: %d\r\n", length);
4036 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
4037 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
4038
4039 rr->rmemcpy(gb.data, length);
4040}
4041
4042
4043
4044/*------------------------------------------------------------------*/
4045
4047{
4048 static RPC_LIST rpc_list[] = {
4049 { 9999, "mhttpd_jrpc_rev0", {
4050 {TID_STRING, RPC_IN}, // arg0
4051 {TID_STRING, RPC_IN}, // arg1
4052 {TID_STRING, RPC_IN}, // arg2
4053 {TID_STRING, RPC_IN}, // arg3
4054 {TID_STRING, RPC_IN}, // arg4
4055 {TID_STRING, RPC_IN}, // arg5
4056 {TID_STRING, RPC_IN}, // arg6
4057 {TID_STRING, RPC_IN}, // arg7
4058 {TID_STRING, RPC_IN}, // arg8
4059 {TID_STRING, RPC_IN}, // arg9
4060 {0}} },
4061 { 0 }
4062 };
4063
4064 int count = 0, substring = 0, rpc;
4065
4066 const char *xname = p->getparam("name");
4067 const char *srpc = p->getparam("rpc");
4068
4069 if (!srpc || !xname) {
4071 r->rsprintf("<INVALID_ARGUMENTS>");
4072 return;
4073 }
4074
4075 char sname[256];
4076 mstrlcpy(sname, xname, sizeof(sname));
4077
4078 if (sname[strlen(sname)-1]=='*') {
4079 sname[strlen(sname)-1] = 0;
4080 substring = 1;
4081 }
4082
4083 rpc = atoi(srpc);
4084
4085 if (rpc<RPC_MIN_ID || rpc>RPC_MAX_ID) {
4087 r->rsprintf("<INVALID_RPC_ID>");
4088 return;
4089 }
4090
4091 rpc_list[0].id = rpc;
4093
4095 r->rsprintf("calling rpc %d | ", rpc);
4096
4097 if (1) {
4098 int status, i;
4099 char str[256];
4100 HNDLE hDB, hrootkey, hsubkey, hkey;
4101
4103
4104 /* find client which exports FCNA function */
4105 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4106 if (status == DB_SUCCESS) {
4107 for (i=0; ; i++) {
4108 status = db_enum_key(hDB, hrootkey, i, &hsubkey);
4110 break;
4111
4112 sprintf(str, "RPC/%d", rpc);
4113 status = db_find_key(hDB, hsubkey, str, &hkey);
4114 if (status == DB_SUCCESS) {
4115 char client_name[NAME_LENGTH];
4116 HNDLE hconn;
4117 int size;
4118
4119 size = sizeof(client_name);
4120 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4121 if (status != DB_SUCCESS)
4122 continue;
4123
4124 if (strlen(sname) > 0) {
4125 if (substring) {
4126 if (strstr(client_name, sname) != client_name)
4127 continue;
4128 } else {
4129 if (strcmp(sname, client_name) != 0)
4130 continue;
4131 }
4132 }
4133
4134 count++;
4135
4136 r->rsprintf("client %s", client_name);
4137
4138 status = cm_connect_client(client_name, &hconn);
4139 r->rsprintf(" %d", status);
4140
4141 if (status == RPC_SUCCESS) {
4142 status = rpc_client_call(hconn, rpc,
4143 p->getparam("arg0"),
4144 p->getparam("arg1"),
4145 p->getparam("arg2"),
4146 p->getparam("arg3"),
4147 p->getparam("arg4"),
4148 p->getparam("arg5"),
4149 p->getparam("arg6"),
4150 p->getparam("arg7"),
4151 p->getparam("arg8"),
4152 p->getparam("arg9")
4153 );
4154 r->rsprintf(" %d", status);
4155
4156 //status = cm_disconnect_client(hconn, FALSE);
4157 r->rsprintf(" %d", status);
4158 }
4159
4160 r->rsprintf(" | ");
4161 }
4162 }
4163 }
4164 }
4165
4166 r->rsprintf("rpc %d, called %d clients\n", rpc, count);
4167}
4168
4169/*------------------------------------------------------------------*/
4170
4172{
4173 static RPC_LIST rpc_list[] = {
4174 { 9998, "mhttpd_jrpc_rev1", {
4175 {TID_STRING, RPC_OUT}, // return string
4176 {TID_INT, RPC_IN}, // return string max length
4177 {TID_STRING, RPC_IN}, // arg0
4178 {TID_STRING, RPC_IN}, // arg1
4179 {TID_STRING, RPC_IN}, // arg2
4180 {TID_STRING, RPC_IN}, // arg3
4181 {TID_STRING, RPC_IN}, // arg4
4182 {TID_STRING, RPC_IN}, // arg5
4183 {TID_STRING, RPC_IN}, // arg6
4184 {TID_STRING, RPC_IN}, // arg7
4185 {TID_STRING, RPC_IN}, // arg8
4186 {TID_STRING, RPC_IN}, // arg9
4187 {0}} },
4188 { 0 }
4189 };
4190
4191 int status, substring = 0, rpc;
4192
4193 const char *xname = p->getparam("name");
4194 const char *srpc = p->getparam("rpc");
4195
4196 if (!srpc || !xname) {
4198 r->rsprintf("<INVALID_ARGUMENTS>");
4199 return;
4200 }
4201
4202 char sname[256];
4203 mstrlcpy(sname, xname, sizeof(sname));
4204
4205 if (sname[strlen(sname)-1]=='*') {
4206 sname[strlen(sname)-1] = 0;
4207 substring = 1;
4208 }
4209
4210 rpc = atoi(srpc);
4211
4212 if (rpc<RPC_MIN_ID || rpc>RPC_MAX_ID) {
4214 r->rsprintf("<INVALID_RPC_ID>");
4215 return;
4216 }
4217
4218 rpc_list[0].id = rpc;
4220
4221 //printf("cm_register_functions() for format \'%s\' status %d\n", sformat, status);
4222
4224
4225 std::string reply_header;
4226 std::string reply_body;
4227
4228 //r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4229 //r->rsprintf("<!-- created by MHTTPD on (timestamp) -->\n");
4230 //r->rsprintf("<jrpc_rev1>\n");
4231 //r->rsprintf(" <rpc>%d</rpc>\n", rpc);
4232
4233 if (1) {
4234 HNDLE hDB, hrootkey, hsubkey, hkey;
4235
4237
4238 int buf_length = 1024;
4239
4240 int max_reply_length = atoi(p->getparam("max_reply_length"));
4241 if (max_reply_length > buf_length)
4242 buf_length = max_reply_length;
4243
4244 char* buf = (char*)malloc(buf_length);
4245
4246 assert(buf != NULL);
4247
4248 /* find client which exports our RPC function */
4249 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
4250 if (status == DB_SUCCESS) {
4251 for (int i=0; ; i++) {
4252 status = db_enum_key(hDB, hrootkey, i, &hsubkey);
4254 break;
4255
4256 char str[256];
4257 sprintf(str, "RPC/%d", rpc);
4258 status = db_find_key(hDB, hsubkey, str, &hkey);
4259 if (status == DB_SUCCESS) {
4260 char client_name[NAME_LENGTH];
4261 HNDLE hconn;
4262 int size;
4263
4264 size = sizeof(client_name);
4265 status = db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, FALSE);
4266 if (status != DB_SUCCESS)
4267 continue;
4268
4269 if (strlen(sname) > 0) {
4270 if (substring) {
4271 if (strstr(client_name, sname) != client_name)
4272 continue;
4273 } else {
4274 if (strcmp(sname, client_name) != 0)
4275 continue;
4276 }
4277 }
4278
4279 //r->rsprintf(" <client>\n");
4280 //r->rsprintf(" <name>%s</name>\n", client_name);
4281
4282 int connect_status = -1;
4283 int call_status = -1;
4284 int call_length = 0;
4285 int disconnect_status = -1;
4286
4287 connect_status = cm_connect_client(client_name, &hconn);
4288
4289 //r->rsprintf(" <connect_status>%d</connect_status>\n", status);
4290
4291 if (connect_status == RPC_SUCCESS) {
4292 buf[0] = 0;
4293
4294 call_status = rpc_client_call(hconn, rpc,
4295 buf,
4296 buf_length,
4297 p->getparam("arg0"),
4298 p->getparam("arg1"),
4299 p->getparam("arg2"),
4300 p->getparam("arg3"),
4301 p->getparam("arg4"),
4302 p->getparam("arg5"),
4303 p->getparam("arg6"),
4304 p->getparam("arg7"),
4305 p->getparam("arg8"),
4306 p->getparam("arg9")
4307 );
4308
4309 //r->rsprintf(" <rpc_status>%d</rpc_status>\n", status);
4311 //r->rsputs("<data>");
4312 //r->rsputs(buf);
4313 //r->rsputs("</data>\n");
4314
4315 if (call_status == RPC_SUCCESS) {
4316 call_length = strlen(buf);
4317 reply_body += buf;
4318 }
4319
4320 //disconnect_status = cm_disconnect_client(hconn, FALSE);
4321 //r->rsprintf(" <disconnect_status>%d</disconnect_status>\n", status);
4322 }
4323
4324 //r->rsprintf(" </client>\n");
4325
4326 if (reply_header.length() > 0)
4327 reply_header += " | ";
4328
4329 char tmp[256];
4330 sprintf(tmp, "%s %d %d %d %d", client_name, connect_status, call_status, disconnect_status, call_length);
4331 reply_header += tmp;
4332 }
4333 }
4334 }
4335
4336 free(buf);
4337 }
4338
4339 //r->rsprintf(" <called_clients>%d</called_clients>\n", count);
4340 //r->rsprintf("</jrpc_rev1>\n");
4341
4342 if (reply_header.length() > 0) {
4343 r->rsputs(reply_header.c_str());
4344 r->rsputs(" || ");
4345 r->rsputs(reply_body.c_str());
4346 r->rsputs("\n");
4347 }
4348}
4349
4350/*------------------------------------------------------------------*/
4351
4353{
4354 int status;
4355
4356 const char *name = p->getparam("name");
4357 const char *cmd = p->getparam("rcmd");
4358 const char *args = p->getparam("rarg");
4359
4360 if (!name || !cmd || !args) {
4362 r->rsprintf("<INVALID_ARGUMENTS>");
4363 return;
4364 }
4365
4367
4368 int buf_length = 1024;
4369
4370 int max_reply_length = atoi(p->getparam("max_reply_length"));
4371 if (max_reply_length > buf_length)
4372 buf_length = max_reply_length;
4373
4374 char* buf = (char*)malloc(buf_length);
4375 assert(buf != NULL);
4376
4377 buf[0] = 0;
4378
4379 HNDLE hconn;
4380
4381 status = cm_connect_client(name, &hconn);
4382
4383 if (status != RPC_SUCCESS) {
4384 r->rsprintf("<RPC_CONNECT_ERROR>%d</RPC_CONNECT_ERROR>", status);
4385 free(buf);
4386 return;
4387 }
4388
4389 status = rpc_client_call(hconn, RPC_JRPC, cmd, args, buf, buf_length);
4390
4391 if (status != RPC_SUCCESS) {
4392 r->rsprintf("<RPC_CALL_ERROR>%d</RPC_CALL_ERROR>", status);
4393 free(buf);
4394 return;
4395 }
4396
4397 r->rsprintf("%s", buf);
4398
4399 //status = cm_disconnect_client(hconn, FALSE);
4400
4401 free(buf);
4402}
4403
4404/*------------------------------------------------------------------*/
4405
4406void output_key(Param* p, Return* r, HNDLE hkey, int index, const char *format)
4407{
4408 int size, i;
4409 HNDLE hDB, hsubkey;
4410 KEY key;
4411 char data[TEXT_SIZE];
4412
4414
4415 db_get_key(hDB, hkey, &key);
4416 if (key.type == TID_KEY) {
4417 for (i=0 ; ; i++) {
4418 db_enum_key(hDB, hkey, i, &hsubkey);
4419 if (!hsubkey)
4420 break;
4421 output_key(p, r, hsubkey, -1, format);
4422 }
4423 } else {
4424 if (key.item_size <= (int)sizeof(data)) {
4425 size = sizeof(data);
4426 db_get_data(hDB, hkey, data, &size, key.type);
4427 if (index == -1) {
4428 for (i=0 ; i<key.num_values ; i++) {
4429 if (p->isparam("name") && atoi(p->getparam("name")) == 1) {
4430 if (key.num_values == 1)
4431 r->rsprintf("%s:", key.name);
4432 else
4433 r->rsprintf("%s[%d]:", key.name, i);
4434 }
4435 std::string data_str;
4436 if (format && format[0])
4437 data_str = db_sprintff(format, data, key.item_size, i, key.type);
4438 else
4439 data_str = db_sprintf(data, key.item_size, i, key.type);
4440 r->rsputs(data_str.c_str());
4441 if (i<key.num_values-1)
4442 r->rsputs("\n");
4443 }
4444 } else {
4445 if (p->isparam("name") && atoi(p->getparam("name")) == 1)
4446 r->rsprintf("%s[%d]:", key.name, index);
4447 if (index >= key.num_values)
4448 r->rsputs("<DB_OUT_OF_RANGE>");
4449 else {
4450 std::string data_str;
4451 if (p->isparam("format"))
4452 data_str = db_sprintff(p->getparam("format"), data, key.item_size, index, key.type);
4453 else
4454 data_str = db_sprintf(data, key.item_size, index, key.type);
4455 r->rsputs(data_str.c_str());
4456 }
4457 }
4458 r->rsputs("\n");
4459 }
4460 }
4461}
4462
4463/*------------------------------------------------------------------*/
4464
4465bool starts_with(const std::string& s1, const char* s2)
4466{
4467 if (s1.length() < strlen(s2))
4468 return false;
4469 return (strncasecmp(s1.c_str(), s2, strlen(s2)) == 0);
4470}
4471
4472//static bool ends_with_char(const std::string& s, char c)
4473//{
4474// if (s.length() < 1)
4475// return false;
4476// return s[s.length()-1] == c;
4477//}
4478
4479/*------------------------------------------------------------------*/
4480
4481void javascript_commands(Param* p, Return* r, const char *cookie_cpwd)
4482{
4483 int status;
4484 int size, i, n, index, type;
4485 unsigned int t;
4486 char str[TEXT_SIZE], format[256], facility[256], user[256];
4487 HNDLE hDB, hkey;
4488 KEY key;
4489 char data[TEXT_SIZE];
4490
4492
4493 // process common parameters
4494
4495 const int ENCODING_NONE = 0;
4496 const int ENCODING_ODB = 1;
4497 const int ENCODING_XML = 2;
4498 const int ENCODING_JSON = 3;
4499
4500 std::string cmd_parameter;
4501 std::string encoding_parameter;
4502 int encoding = ENCODING_NONE; // default encoding
4503 bool jsonp = false; // default is no JSONP wrapper
4504 std::string jsonp_callback; // default is no JSONP
4505 bool single = false; // single encoding
4506 bool multiple = false; // multiple encoding
4507 std::vector<std::string> odb; // multiple odb parameters
4508 //HNDLE hodb; // ODB handle for single odb parameter
4509 //std::vector<HNDLE> hodbm; // ODB handle for multiple odb parameter
4510
4511 if (p->isparam("cmd")) {
4512 cmd_parameter = p->getparam("cmd");
4513 }
4514
4515 if (p->isparam("encoding")) {
4516 encoding_parameter = p->getparam("encoding");
4517 }
4518
4519 if (encoding_parameter.length() > 0) {
4520 if (starts_with(encoding_parameter, "odb"))
4521 encoding = ENCODING_ODB;
4522 else if (starts_with(encoding_parameter, "xml"))
4523 encoding = ENCODING_XML;
4524 else if (starts_with(encoding_parameter, "json"))
4525 encoding = ENCODING_JSON;
4526 }
4527
4528 if (encoding == ENCODING_JSON) {
4529 if (p->isparam("callback")) {
4530 jsonp = true;
4531 jsonp_callback = p->getparam("callback");
4532 }
4533 }
4534
4535 if (p->isparam("odb")) {
4536 single = true;
4537 odb.push_back(p->getparam("odb"));
4538 }
4539
4540 if (p->isparam("odb0")) {
4541 multiple = true;
4542 for (int i=0 ; ; i++) {
4543 char ppath[256];
4544 sprintf(ppath, "odb%d", i);
4545 if (!p->isparam(ppath))
4546 break;
4547 odb.push_back(p->getparam(ppath));
4548 }
4549 }
4550
4551 if (/* DISABLES CODE */ (0)) {
4552 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());
4553 }
4554
4555 /* process "jset" command */
4556 if (equal_ustring(p->getparam("cmd"), "jset")) {
4557
4558 if (*p->getparam("pnam")) {
4559 std::string ppath;
4560 ppath += "/Custom/Pwd/";
4561 ppath += p->getparam("pnam");
4562 str[0] = 0;
4563 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
4564 if (!equal_ustring(cookie_cpwd, str)) {
4566 r->rsprintf("Invalid password!");
4567 return;
4568 }
4569 }
4570 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4571 if (strchr(str, '[')) {
4572 if (*(strchr(str, '[')+1) == '*')
4573 index = -1;
4574 else
4575 index = atoi(strchr(str, '[')+1);
4576 *strchr(str, '[') = 0;
4577 } else
4578 index = 0;
4579
4580 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS && p->isparam("value")) {
4581 db_get_key(hDB, hkey, &key);
4582 memset(data, 0, sizeof(data));
4583 if (key.item_size <= (int)sizeof(data)) {
4584 if (index == -1) {
4585 const char* ptr = p->getparam("value");
4586 for (i=0 ; ptr != NULL ; i++) {
4587 size = sizeof(data);
4588 db_sscanf(ptr, data, &size, 0, key.type);
4589 if (strchr(data, ','))
4590 *strchr(data, ',') = 0;
4592 ptr = strchr(ptr, ',');
4593 if (ptr != NULL)
4594 ptr++;
4595 }
4596 } else {
4597 size = sizeof(data);
4598 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4599
4600 /* extend data size for single string if necessary */
4601 if ((key.type == TID_STRING || key.type == TID_LINK)
4602 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1) {
4603 key.item_size = strlen(data) + 1;
4604 db_set_data(hDB, hkey, data, key.item_size, 1, key.type);
4605 } else
4607 }
4608 }
4609 } else {
4610 if (p->isparam("value") && p->isparam("type") && p->isparam("len")) {
4611 int type = atoi(p->getparam("type"));
4612 if (type == 0) {
4614 r->rsprintf("Invalid type %d!", type);
4615 return;
4616 }
4617 db_create_key(hDB, 0, str, type);
4618 db_find_key(hDB, 0, str, &hkey);
4619 if (!hkey) {
4621 r->rsprintf("Cannot create \'%s\' type %d", str, type);
4622 return;
4623 }
4624 db_get_key(hDB, hkey, &key);
4625 memset(data, 0, sizeof(data));
4626 size = sizeof(data);
4627 db_sscanf(p->getparam("value"), data, &size, 0, key.type);
4628 if (key.type == TID_STRING)
4629 db_set_data(hDB, hkey, data, atoi(p->getparam("len")), 1, TID_STRING);
4630 else {
4631 for (i=0 ; i<atoi(p->getparam("len")) ; i++)
4633 }
4634 }
4635 }
4636
4638 r->rsprintf("OK");
4639 return;
4640 }
4641
4642 /* process "jget" command */
4643 if (equal_ustring(p->getparam("cmd"), "jget")) {
4644
4645 if (p->isparam("odb")) {
4646 mstrlcpy(str, p->getparam("odb"), 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
4657
4658 status = db_find_key(hDB, 0, str, &hkey);
4659
4660 if (status == DB_SUCCESS)
4661 output_key(p, r, hkey, index, p->getparam("format"));
4662 else
4663 r->rsputs("<DB_NO_KEY>");
4664 }
4665
4666 if (p->isparam("odb0")) {
4668 for (i=0 ; ; i++) {
4669 char ppath[256];
4670 sprintf(ppath, "odb%d", i);
4671 sprintf(format, "format%d", i);
4672 if (p->isparam(ppath)) {
4673 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4674 if (strchr(str, '[')) {
4675 if (*(strchr(str, '[')+1) == '*')
4676 index = -1;
4677 else
4678 index = atoi(strchr(str, '[')+1);
4679 *strchr(str, '[') = 0;
4680 } else
4681 index = 0;
4682 if (i > 0)
4683 r->rsputs("$#----#$\n");
4684 if (db_find_key(hDB, 0, str, &hkey) == DB_SUCCESS)
4685 output_key(p, r, hkey, index, p->getparam(format));
4686 else
4687 r->rsputs("<DB_NO_KEY>");
4688
4689 } else
4690 break;
4691 }
4692 }
4693
4694 return;
4695 }
4696
4697 /* process "jcopy" command */
4698 if (equal_ustring(p->getparam("cmd"), "jcopy")) {
4699
4700 bool fmt_odb = false;
4701 bool fmt_xml = false;
4702 bool fmt_json = true;
4703 bool fmt_jsonp = false;
4704 int follow_links = 1;
4705 int save_keys = 1;
4706 int recurse = 1;
4707 const char* fmt = NULL;
4708 const char* jsonp_callback = "callback";
4709
4710 if (p->isparam("encoding")) {
4711 fmt = p->getparam("encoding");
4712 } else if (p->isparam("format")) {
4713 fmt = p->getparam("format");
4714 }
4715
4716 if (fmt) {
4717 fmt_odb = (equal_ustring(fmt, "odb") > 0);
4718 fmt_xml = (equal_ustring(fmt, "xml") > 0);
4719 fmt_json = (strstr(fmt, "json") != NULL);
4720
4721 if (fmt_odb)
4722 fmt_xml = fmt_json = false;
4723 if (fmt_xml)
4724 fmt_odb = fmt_json = false;
4725 if (fmt_json)
4726 fmt_odb = fmt_xml = false;
4727
4728 if (fmt_json)
4729 fmt_jsonp = (strstr(fmt, "-p") != NULL);
4730 if (fmt_jsonp && p->isparam("callback"))
4731 jsonp_callback = p->getparam("callback");
4732 if (fmt_json && strstr(fmt, "-nofollowlinks"))
4733 follow_links = 0;
4734 if (fmt_json && strstr(fmt, "-nokeys"))
4735 save_keys = 2;
4736 if (fmt_json && strstr(fmt, "-nolastwritten"))
4737 save_keys = 0;
4738 if (fmt_json && strstr(fmt, "-norecurse"))
4739 recurse = 0;
4740 }
4741
4742 if (p->isparam("odb")) {
4743 mstrlcpy(str, p->getparam("odb"), sizeof(str));
4744
4746
4747 if (fmt_json)
4748 status = db_find_link(hDB, 0, str, &hkey);
4749 else
4750 status = db_find_key(hDB, 0, str, &hkey);
4751 if (status == DB_SUCCESS) {
4752
4753 if (fmt_jsonp) {
4754 r->rsputs(jsonp_callback);
4755 r->rsputs("(");
4756 }
4757
4758 int end = 0;
4759 int bufsize = WEB_BUFFER_SIZE;
4760 char* buf = (char *)malloc(bufsize);
4761
4762 if (fmt_xml)
4763 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4764 else if (fmt_json)
4765 db_copy_json_obsolete(hDB, hkey, &buf, &bufsize, &end, save_keys, follow_links, recurse);
4766 else
4767 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4768
4769 r->rsputs(buf);
4770 free(buf);
4771
4772 if (fmt_jsonp) {
4773 r->rsputs(");\n");
4774 }
4775 } else
4776 r->rsputs("<DB_NO_KEY>");
4777 }
4778
4779 if (p->isparam("odb0")) {
4781 if (fmt_jsonp) {
4782 r->rsputs(jsonp_callback);
4783 r->rsputs("(");
4784 }
4785 if (fmt_xml) {
4786 r->rsprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", HTTP_ENCODING);
4787 r->rsputs("<jcopy>\n");
4788 r->rsputs("<data>\n");
4789 } else if (fmt_json)
4790 r->rsputs("[\n");
4791 else
4792 r->rsputs("");
4793 for (int i=0 ; ; i++) {
4794 char ppath[256];
4795 sprintf(ppath, "odb%d", i);
4796 if (!p->isparam(ppath))
4797 break;
4798 mstrlcpy(str, p->getparam(ppath), sizeof(str));
4799
4800 if (i > 0) {
4801 if (fmt_xml)
4802 r->rsputs("</data>\n<data>\n");
4803 else if (fmt_json)
4804 r->rsputs(",\n");
4805 else
4806 r->rsputs("$#----#$\n");
4807 }
4808
4809 if (fmt_json)
4810 status = db_find_link(hDB, 0, str, &hkey);
4811 else
4812 status = db_find_key(hDB, 0, str, &hkey);
4813 if (status != DB_SUCCESS) {
4814 if (fmt_xml)
4815 r->rsputs("<DB_NO_KEY/>\n");
4816 else if (fmt_json) {
4817 char tmp[256];
4818 sprintf(tmp, "{ \"/error\" : %d }\n", status);
4819 r->rsputs(tmp);
4820 } else
4821 r->rsputs("<DB_NO_KEY>\n");
4822 continue;
4823 }
4824
4825 int end = 0;
4826 int bufsize = WEB_BUFFER_SIZE;
4827 char* buf = (char *)malloc(bufsize);
4828
4829 if (fmt_xml) {
4830 db_copy_xml(hDB, hkey, buf, &bufsize, true);
4831 const char* s = strstr(buf, "-->");
4832 if (s)
4833 s+=4;
4834 else
4835 s = buf;
4836 r->rsputs(s);
4837 } else if (fmt_json) {
4838 db_copy_json_obsolete(hDB, hkey, &buf, &bufsize, &end, save_keys, follow_links, recurse);
4839 r->rsputs(buf);
4840 } else {
4841 db_copy(hDB, hkey, buf, &bufsize, (char *)"");
4842 r->rsputs(buf);
4843 }
4844
4845 free(buf);
4846 }
4847
4848 if (fmt_xml)
4849 r->rsputs("</data>\n</jcopy>\n");
4850 else if (fmt_json)
4851 r->rsputs("]\n");
4852 else
4853 r->rsputs("");
4854
4855 if (fmt_jsonp) {
4856 r->rsputs(");\n");
4857 }
4858 }
4859 return;
4860 }
4861
4862 /* process "jkey" command */
4863 if (equal_ustring(p->getparam("cmd"), "jkey")) {
4864
4865 // test:
4866 // curl "http://localhost:8080?cmd=jkey&odb0=/runinfo/run+number&odb1=/nonexistant&odb2=/&encoding=json&callback=aaa"
4867
4869
4870 if (jsonp) {
4871 r->rsputs(jsonp_callback.c_str());
4872 r->rsputs("(");
4873 }
4874
4875 if (multiple) {
4876 switch (encoding) {
4877 default:
4878 break;
4879 case ENCODING_JSON:
4880 r->rsprintf("[ ");
4881 break;
4882 }
4883 }
4884
4885 for (unsigned i=0; i<odb.size(); i++) {
4886 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
4887 if (status == DB_SUCCESS)
4888 status = db_get_key(hDB, hkey, &key);
4889 switch (encoding) {
4890 default:
4891 if (multiple && i>0)
4892 r->rsputs("$#----#$\n");
4893 if (status == DB_SUCCESS) {
4894 r->rsprintf("%s\n", key.name);
4895 r->rsprintf("TID_%s\n", rpc_tid_name(key.type));
4896 r->rsprintf("%d\n", key.num_values);
4897 r->rsprintf("%d\n", key.item_size);
4898 r->rsprintf("%d\n", key.last_written);
4899 } else {
4900 r->rsputs("<DB_NO_KEY>\n");
4901 }
4902 break;
4903 case ENCODING_JSON:
4904 if (multiple && i>0)
4905 r->rsprintf(", ");
4906 if (status == DB_SUCCESS) {
4907 r->rsprintf("{ ");
4908 r->rsprintf("\"name\":\"%s\",", key.name);
4909 r->rsprintf("\"type\":%d,", key.type);
4910 r->rsprintf("\"type_name\":\"TID_%s\",", rpc_tid_name(key.type));
4911 r->rsprintf("\"num_values\":%d,", key.num_values);
4912 r->rsprintf("\"item_size\":%d,", key.item_size);
4913 r->rsprintf("\"last_written\":%d", key.last_written);
4914 r->rsprintf(" }");
4915 } else {
4916 r->rsprintf("{ \"/error\":%d }", status);
4917 }
4918 break;
4919 }
4920 }
4921
4922 if (multiple) {
4923 switch (encoding) {
4924 default:
4925 break;
4926 case ENCODING_JSON:
4927 r->rsprintf(" ]");
4928 break;
4929 }
4930 }
4931
4932 if (jsonp) {
4933 r->rsputs(");\n");
4934 }
4935
4936 return;
4937 }
4938
4939 /* process "jcreate" command */
4940 if (equal_ustring(p->getparam("cmd"), "jcreate")) {
4941
4942 // test:
4943 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
4944 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo&type=7"
4945 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo70&type=7&arraylen=10"
4946 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s&type=12&strlen=32"
4947 // curl "http://localhost:8080?cmd=jcreate&odb=/test/foo12s5&type=12&strlen=32&arraylen=5"
4948 // curl "http://localhost:8080?cmd=jcreate&odb0=/test/foo12s5x&type0=12&strlen0=32&arraylen0=5"
4949
4950
4952
4953 if (jsonp) {
4954 r->rsputs(jsonp_callback.c_str());
4955 r->rsputs("(");
4956 }
4957
4958 if (multiple) {
4959 switch (encoding) {
4960 default:
4961 case ENCODING_JSON:
4962 r->rsprintf("[ ");
4963 break;
4964 }
4965 }
4966
4967 for (unsigned i=0; i<odb.size(); i++) {
4968 HNDLE hkey = 0;
4969 int type = 0;
4970 int arraylength = 0;
4971 int strlength = 0;
4972
4973 if (single) {
4974 type = atoi(p->getparam("type"));
4975 arraylength = atoi(p->getparam("arraylen"));
4976 strlength = atoi(p->getparam("strlen"));
4977 }
4978 else if (multiple) {
4979 char buf[256];
4980 sprintf(buf, "type%d", i);
4981 type = atoi(p->getparam(buf));
4982 sprintf(buf, "arraylen%d", i);
4983 arraylength = atoi(p->getparam(buf));
4984 sprintf(buf, "strlen%d", i);
4985 strlength = atoi(p->getparam(buf));
4986 }
4987
4988 status = db_create_key(hDB, 0, odb[i].c_str(), type);
4989
4990 if (status == DB_SUCCESS) {
4991 status = db_find_link(hDB, 0, odb[i].c_str(), &hkey);
4992 }
4993
4994 if (status == DB_SUCCESS && hkey && type == TID_STRING && strlength > 0) {
4995 char* s = (char*)calloc(strlength, 1); // initialized to zero
4996 status = db_set_data(hDB, hkey, s, strlength, 1, TID_STRING);
4997 free(s);
4998 }
4999
5000 if (status == DB_SUCCESS && hkey && arraylength > 1) {
5001 status = db_set_num_values(hDB, hkey, arraylength);
5002 }
5003
5004 switch (encoding) {
5005 default:
5006 case ENCODING_JSON:
5007 if (multiple && i>0)
5008 r->rsprintf(", ");
5009 r->rsprintf("%d", status);
5010 break;
5011 }
5012 }
5013
5014 if (multiple) {
5015 switch (encoding) {
5016 default:
5017 case ENCODING_JSON:
5018 r->rsprintf(" ]");
5019 break;
5020 }
5021 }
5022
5023 if (jsonp) {
5024 r->rsputs(");\n");
5025 }
5026
5027 return;
5028 }
5029
5030 /* process "jresize" command */
5031 if (equal_ustring(p->getparam("cmd"), "jresize")) {
5032
5033 // test:
5034
5035 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo70&arraylen=5"
5036 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&arraylen=5"
5037 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=16"
5038 // curl "http://localhost:8080?cmd=jresize&odb=/test/foo12s5&strlen=30&arraylen=10"
5039
5041
5042 if (jsonp) {
5043 r->rsputs(jsonp_callback.c_str());
5044 r->rsputs("(");
5045 }
5046
5047 if (multiple) {
5048 switch (encoding) {
5049 default:
5050 case ENCODING_JSON:
5051 r->rsprintf("[ ");
5052 break;
5053 }
5054 }
5055
5056 for (unsigned i=0; i<odb.size(); i++) {
5057 HNDLE hkey;
5058 KEY key;
5059 int arraylength = 0;
5060 int strlength = 0;
5061
5062 if (single) {
5063 arraylength = atoi(p->getparam("arraylen"));
5064 strlength = atoi(p->getparam("strlen"));
5065 }
5066 else if (multiple) {
5067 char buf[256];
5068 sprintf(buf, "arraylen%d", i);
5069 arraylength = atoi(p->getparam(buf));
5070 sprintf(buf, "strlen%d", i);
5071 strlength = atoi(p->getparam(buf));
5072 }
5073
5074 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5075
5076 if (status == DB_SUCCESS && hkey) {
5077 status = db_get_key(hDB, hkey, &key);
5078 }
5079
5080 if (status == DB_SUCCESS && hkey && key.type == TID_STRING && strlength > 0) {
5081 int oldsize = key.item_size * key.num_values;
5082 char* olddata = (char*)malloc(oldsize);
5083 int size = oldsize;
5084 status = db_get_data(hDB, hkey, olddata, &size, TID_STRING);
5085
5086 if (status == DB_SUCCESS) {
5087 int newsize = strlength * key.num_values;
5088 char* s = (char*)calloc(newsize, 1); // initialized to zero
5089 for (int k=0; k<key.num_values; k++) {
5090 mstrlcpy(s + strlength*k, olddata + key.item_size*k, strlength);
5091 }
5092
5093 status = db_set_data(hDB, hkey, s, newsize, key.num_values, TID_STRING);
5094 free(s);
5095 }
5096
5097 free(olddata);
5098 }
5099
5100 if (status == DB_SUCCESS && hkey && arraylength > 0) {
5101 status = db_set_num_values(hDB, hkey, arraylength);
5102 }
5103
5104 switch (encoding) {
5105 default:
5106 case ENCODING_JSON:
5107 if (multiple && i>0)
5108 r->rsprintf(", ");
5109 r->rsprintf("%d", status);
5110 break;
5111 }
5112 }
5113
5114 if (multiple) {
5115 switch (encoding) {
5116 default:
5117 case ENCODING_JSON:
5118 r->rsprintf(" ]");
5119 break;
5120 }
5121 }
5122
5123 if (jsonp) {
5124 r->rsputs(");\n");
5125 }
5126
5127 return;
5128 }
5129
5130 /* process "jrename" command */
5131 if (equal_ustring(p->getparam("cmd"), "jrename")) {
5132
5133 // test:
5134 // curl "http://localhost:8080?cmd=jrename&odb0=/test/foo&type0=7&odb1=/nonexistant&type1=100&odb2=/test/bar&type2=12&encoding=json&callback=aaa"
5135 // curl "http://localhost:8080?cmd=jrename&odb=/test/foo&name=foofoo"
5136
5138
5139 if (jsonp) {
5140 r->rsputs(jsonp_callback.c_str());
5141 r->rsputs("(");
5142 }
5143
5144 if (multiple) {
5145 switch (encoding) {
5146 default:
5147 case ENCODING_JSON:
5148 r->rsprintf("[ ");
5149 break;
5150 }
5151 }
5152
5153 for (unsigned i=0; i<odb.size(); i++) {
5154 const char* name = NULL;
5155 if (single)
5156 name = p->getparam("name");
5157 else if (multiple) {
5158 char buf[256];
5159 sprintf(buf, "name%d", i);
5160 name = p->getparam(buf);
5161 }
5162 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5163 if (status == DB_SUCCESS) {
5164 status = db_rename_key(hDB, hkey, name);
5165 }
5166 switch (encoding) {
5167 default:
5168 case ENCODING_JSON:
5169 if (multiple && i>0)
5170 r->rsprintf(", ");
5171 r->rsprintf("%d", status);
5172 break;
5173 }
5174 }
5175
5176 if (multiple) {
5177 switch (encoding) {
5178 default:
5179 case ENCODING_JSON:
5180 r->rsprintf(" ]");
5181 break;
5182 }
5183 }
5184
5185 if (jsonp) {
5186 r->rsputs(");\n");
5187 }
5188
5189 return;
5190 }
5191
5192 /* process "jlink" command */
5193 if (equal_ustring(p->getparam("cmd"), "jlink")) {
5194
5195 // test:
5196 // curl "http://localhost:8080?cmd=jlink&odb=/test/link&dest=/test/foo"
5197 // curl "http://localhost:8080?cmd=jlink&odb0=/test/link0&dest0=/test/foo&odb1=/test/link1&dest1=/test/foo"
5198
5200
5201 if (jsonp) {
5202 r->rsputs(jsonp_callback.c_str());
5203 r->rsputs("(");
5204 }
5205
5206 if (multiple) {
5207 switch (encoding) {
5208 default:
5209 case ENCODING_JSON:
5210 r->rsprintf("[ ");
5211 break;
5212 }
5213 }
5214
5215 for (unsigned i=0; i<odb.size(); i++) {
5216 const char* dest = NULL;
5217 if (single)
5218 dest = p->getparam("dest");
5219 else if (multiple) {
5220 char buf[256];
5221 sprintf(buf, "dest%d", i);
5222 dest = p->getparam(buf);
5223 }
5224
5225 status = db_create_link(hDB, 0, odb[i].c_str(), dest);
5226
5227 switch (encoding) {
5228 default:
5229 case ENCODING_JSON:
5230 if (multiple && i>0)
5231 r->rsprintf(", ");
5232 r->rsprintf("%d", status);
5233 break;
5234 }
5235 }
5236
5237 if (multiple) {
5238 switch (encoding) {
5239 default:
5240 case ENCODING_JSON:
5241 r->rsprintf(" ]");
5242 break;
5243 }
5244 }
5245
5246 if (jsonp) {
5247 r->rsputs(");\n");
5248 }
5249
5250 return;
5251 }
5252
5253 /* process "jreorder" command */
5254 if (equal_ustring(p->getparam("cmd"), "jreorder")) {
5255
5256 // test:
5257 // curl "http://localhost:8080?cmd=jreorder&odb0=/test/foo&index0=0&odb1=/test/bar&index1=1"
5258 // curl "http://localhost:8080?cmd=jreorder&odb=/test/bar&index=0"
5259
5261
5262 if (jsonp) {
5263 r->rsputs(jsonp_callback.c_str());
5264 r->rsputs("(");
5265 }
5266
5267 if (multiple) {
5268 switch (encoding) {
5269 default:
5270 case ENCODING_JSON:
5271 r->rsprintf("[ ");
5272 break;
5273 }
5274 }
5275
5276 for (unsigned i=0; i<odb.size(); i++) {
5277 int index = 0;
5278 if (single)
5279 index = atoi(p->getparam("index"));
5280 else if (multiple) {
5281 char buf[256];
5282 sprintf(buf, "index%d", i);
5283 index = atoi(p->getparam(buf));
5284 }
5285
5286 status = db_find_key(hDB, 0, odb[i].c_str(), &hkey);
5287 if (status == DB_SUCCESS) {
5288 status = db_reorder_key(hDB, hkey, index);
5289 }
5290
5291 switch (encoding) {
5292 default:
5293 case ENCODING_JSON:
5294 if (multiple && i>0)
5295 r->rsprintf(", ");
5296 r->rsprintf("%d", status);
5297 break;
5298 }
5299 }
5300
5301 if (multiple) {
5302 switch (encoding) {
5303 default:
5304 case ENCODING_JSON:
5305 r->rsprintf(" ]");
5306 break;
5307 }
5308 }
5309
5310 if (jsonp) {
5311 r->rsputs(");\n");
5312 }
5313
5314 return;
5315 }
5316
5317 /* process "jdelete" command */
5318 if (equal_ustring(p->getparam("cmd"), "jdelete")) {
5319
5320 // test:
5321 // curl "http://localhost:8080?cmd=jdelete&odb0=/test/foo&odb1=/nonexistant&odb2=/test/bar&encoding=json&callback=aaa"
5322 // curl "http://localhost:8080?cmd=jdelete&odb=/test/foo"
5323
5325
5326 if (jsonp) {
5327 r->rsputs(jsonp_callback.c_str());
5328 r->rsputs("(");
5329 }
5330
5331 if (multiple) {
5332 switch (encoding) {
5333 default:
5334 case ENCODING_JSON:
5335 r->rsprintf("[ ");
5336 break;
5337 }
5338 }
5339
5340 for (unsigned i=0; i<odb.size(); i++) {
5341 status = db_delete(hDB, 0, odb[i].c_str());
5342 switch (encoding) {
5343 default:
5344 case ENCODING_JSON:
5345 if (multiple && i>0)
5346 r->rsprintf(", ");
5347 r->rsprintf("%d", status);
5348 break;
5349 }
5350 }
5351
5352 if (multiple) {
5353 switch (encoding) {
5354 default:
5355 case ENCODING_JSON:
5356 r->rsprintf(" ]");
5357 break;
5358 }
5359 }
5360
5361 if (jsonp) {
5362 r->rsputs(");\n");
5363 }
5364
5365 return;
5366 }
5367
5368 /* process "jmsg" command */
5369 if (equal_ustring(p->getparam("cmd"), "jmsg")) {
5370
5371 if (p->getparam("f") && *p->getparam("f"))
5372 mstrlcpy(facility, p->getparam("f"), sizeof(facility));
5373 else
5374 mstrlcpy(facility, "midas", sizeof(facility));
5375
5376 n = 1;
5377 if (p->getparam("n") && *p->getparam("n"))
5378 n = atoi(p->getparam("n"));
5379
5380 t = 0;
5381 if (p->getparam("t") && p->getparam("t"))
5382 t = atoi(p->getparam("t"));
5383
5385 char* messages = NULL;
5386 int num_messages = 0;
5387 cm_msg_retrieve2(facility, t, n, &messages, &num_messages);
5388 if (messages) {
5389 r->rsputs(messages);
5390 free(messages);
5391 }
5392 return;
5393 }
5394
5395 /* process "jgenmsg" command */
5396 if (equal_ustring(p->getparam("cmd"), "jgenmsg")) {
5397
5398 if (p->getparam("facility") && *p->getparam("facility"))
5399 mstrlcpy(facility, p->getparam("facility"), sizeof(facility));
5400 else
5401 mstrlcpy(facility, "midas", sizeof(facility));
5402
5403 if (p->getparam("user") && *p->getparam("user"))
5404 mstrlcpy(user, p->getparam("user"), sizeof(user));
5405 else
5406 mstrlcpy(user, "javascript_commands", sizeof(user));
5407
5408 if (p->getparam("type") && *p->getparam("type"))
5409 type = atoi(p->getparam("type"));
5410 else
5411 type = MT_INFO;
5412
5413 if (p->getparam("msg") && *p->getparam("msg")) {
5414 cm_msg1(type, __FILE__, __LINE__, facility, user, "%s", p->getparam("msg"));
5415 }
5416
5418 r->rsputs("Message successfully created\n");
5419 return;
5420 }
5421
5422 /* process "jalm" command */
5423 if (equal_ustring(p->getparam("cmd"), "jalm")) {
5424
5426 std::string alarms;
5427 al_get_alarms(&alarms);
5428 r->rsputs(alarms.c_str());
5429 return;
5430 }
5431
5432 /* process "jrpc" command */
5433 if (equal_ustring(p->getparam("cmd"), "jrpc_rev0")) {
5434 do_jrpc_rev0(p, r);
5435 return;
5436 }
5437
5438 /* process "jrpc" command */
5439 if (equal_ustring(p->getparam("cmd"), "jrpc_rev1")) {
5440 do_jrpc_rev1(p, r);
5441 return;
5442 }
5443
5444 /* process "jrpc" command */
5445 if (equal_ustring(p->getparam("cmd"), "jrpc")) {
5446 do_jrpc(p, r);
5447 return;
5448 }
5449}
5450
5451/*------------------------------------------------------------------*/
5452
5453void show_custom_page(Param* pp, Return* r, const char *cookie_cpwd)
5454{
5455 int size, n_var, index, edit;
5456 char keypath[256], type[32], *p, *ps;
5457 char pwd[256], tail[256];
5458 HNDLE hDB, hkey;
5459 KEY key;
5460 char data[TEXT_SIZE];
5461
5462 std::string path = pp->getparam("page");
5463
5464 if (path[0] == 0) {
5465 show_error_404(r, "show_custom_page: Invalid custom page: \"page\" parameter is empty");
5466 return;
5467 }
5468
5469 if (strstr(path.c_str(), "..")) {
5470 std::string str;
5471 str += "Invalid custom page name \'";
5472 str += path;
5473 str += "\' contains \'..\'";
5474 show_error_404(r, str.c_str());
5475 return;
5476 }
5477
5478 if (strstr(path.c_str(), ".gif")) {
5479 show_custom_gif(r, path.c_str());
5480 return;
5481 }
5482
5483 if (strchr(path.c_str(), '.')) {
5484 show_custom_file(r, path.c_str());
5485 return;
5486 }
5487
5489
5490 std::string xpath = std::string("/Custom/") + path;
5491 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5492 if (!hkey) {
5493 xpath = std::string("/Custom/") + path + "&";
5494 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5495 if (!hkey) {
5496 xpath = std::string("/Custom/") + path + "!";
5497 db_find_key(hDB, 0, xpath.c_str(), &hkey);
5498 }
5499 }
5500
5501 if (hkey) {
5502 char* ctext;
5503 int status;
5504
5505 status = db_get_key(hDB, hkey, &key);
5506 assert(status == DB_SUCCESS);
5507 size = key.total_size;
5508 ctext = (char*)malloc(size);
5509 status = db_get_data(hDB, hkey, ctext, &size, TID_STRING);
5510 if (status != DB_SUCCESS) {
5511 std::string errtext = msprintf("show_custom_page: Error: db_get_data() for \"%s\" status %d", xpath.c_str(), status);
5512 show_error_404(r, errtext.c_str());
5513 free(ctext);
5514 return;
5515 }
5516
5517 std::string content_type = "text/html";
5518
5519 /* check for link */
5520 if (std::string(ctext).substr(0, 5) == "?cmd=") {
5521 redirect(r, ctext);
5522 free(ctext);
5523 return;
5524 }
5525
5526 /* check if filename */
5527 if (strchr(ctext, '\n') == 0) {
5528 std::string full_filename = add_custom_path(ctext);
5529 int fh = open(full_filename.c_str(), O_RDONLY | O_BINARY);
5530 if (fh < 0) {
5531 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", open() errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5532 show_error_404(r, str.c_str());
5533 free(ctext);
5534 return;
5535 }
5536 free(ctext);
5537 ctext = NULL;
5538 off_t off = lseek(fh, 0, SEEK_END);
5539 if (off < 0) {
5540 std::string str = msprintf("show_custom_page: Cannot open file \"%s\", lseek(SEEK_END) errno %d (%s)", full_filename.c_str(), errno, strerror(errno));
5541 show_error_404(r, str.c_str());
5542 free(ctext);
5543 close(fh);
5544 return;
5545 }
5546 size_t size = off;
5547 lseek(fh, 0, SEEK_SET);
5548 ctext = (char*)malloc(size+1);
5549 ssize_t rd = read(fh, ctext, size);
5550 if (rd > 0) {
5551 ctext[rd] = 0; // make sure string is zero-terminated
5552 size = rd;
5553 } else {
5554 ctext[0] = 0;
5555 size = 0;
5556 }
5557 close(fh);
5558
5559 content_type = get_content_type(full_filename.c_str());
5560 }
5561
5562 /* check for valid password */
5563 if (equal_ustring(pp->getparam("cmd"), "Edit")) {
5564 p = ps = ctext;
5565 n_var = 0;
5566 do {
5567 char format[256];
5568
5569 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5570 if (p == NULL)
5571 break;
5572 ps = strchr(p, '>') + 1;
5573
5574 if (pwd[0] && n_var == atoi(pp->getparam("index"))) {
5575 char str[256];
5576 size = NAME_LENGTH;
5577 mstrlcpy(str, path.c_str(), sizeof(str)); // FIXME: overflows "str"
5578 if (strlen(str)>0 && str[strlen(str)-1] == '&')
5579 str[strlen(str)-1] = 0;
5580 std::string ppath;
5581 ppath += "/Custom/Pwd/";
5582 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5583 ppath += pp->getparam("pnam");
5584 } else {
5585 ppath += str;
5586 }
5587 str[0] = 0;
5588 db_get_value(hDB, 0, ppath.c_str(), str, &size, TID_STRING, TRUE);
5589 if (!equal_ustring(cookie_cpwd, str)) {
5590 show_error_404(r, "show_custom_page: Invalid password!");
5591 free(ctext);
5592 return;
5593 } else
5594 break;
5595 }
5596
5597 n_var++;
5598 } while (p != NULL);
5599 }
5600
5601 /* process toggle command */
5602 if (equal_ustring(pp->getparam("cmd"), "Toggle")) {
5603
5604 if (pp->getparam("pnam") && *pp->getparam("pnam")) {
5605 std::string ppath;
5606 ppath += "/Custom/Pwd/";
5607 ppath += pp->getparam("pnam");
5608 std::string str;
5609 db_get_value_string(hDB, 0, ppath.c_str(), 0, &str, TRUE, 256);
5610 if (!equal_ustring(cookie_cpwd, str.c_str())) {
5611 show_error_404(r, "show_custom_page: Invalid password!");
5612 free(ctext);
5613 return;
5614 }
5615 }
5616 std::string podb = pp->getparam("odb");
5617 std::string::size_type pos = podb.find('[');
5618 if (pos != std::string::npos) {
5619 index = atoi(podb.substr(pos+1).c_str());
5620 podb.resize(pos);
5621 //printf("found index %d in [%s] [%s]\n", index, pp->getparam("odb"), podb.c_str());
5622 } else
5623 index = 0;
5624
5625 if (db_find_key(hDB, 0, podb.c_str(), &hkey)) {
5626 db_get_key(hDB, hkey, &key);
5627 memset(data, 0, sizeof(data));
5628 if (key.item_size <= (int)sizeof(data)) {
5629 size = sizeof(data);
5630 db_get_data_index(hDB, hkey, data, &size, index, key.type);
5631 std::string data_str = db_sprintf(data, size, 0, key.type);
5632 if (atoi(data_str.c_str()) == 0)
5633 db_sscanf("1", data, &size, 0, key.type);
5634 else
5635 db_sscanf("0", data, &size, 0, key.type);
5637 }
5638 }
5639
5640 /* redirect (so that 'reload' does not toggle again) */
5641 redirect(r, path.c_str());
5642 free(ctext);
5643 return;
5644 }
5645
5646 /* HTTP header */
5647 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
5648 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5649 r->rsprintf("Content-Type: %s; charset=%s\r\n\r\n", content_type.c_str(), HTTP_ENCODING);
5650
5651 /* interprete text, replace <odb> tags with ODB values */
5652 p = ps = ctext;
5653 n_var = 0;
5654 do {
5655 char format[256];
5656 p = find_odb_tag(ps, keypath, format, &edit, type, pwd, tail);
5657 if (p != NULL)
5658 *p = 0;
5659 r->rsputs(ps);
5660
5661 if (p == NULL)
5662 break;
5663 ps = strchr(p + 1, '>') + 1;
5664
5665 show_odb_tag(pp, r, path.c_str(), keypath, format, n_var, edit, type, pwd, tail);
5666 n_var++;
5667
5668 } while (p != NULL);
5669
5670 if (equal_ustring(pp->getparam("cmd"), "Set") || pp->isparam("cbi")) {
5671 /* redirect (so that 'reload' does not change value) */
5672 r->reset();
5673 redirect(r, path.c_str());
5674 }
5675
5676 free(ctext);
5677 ctext = NULL;
5678 } else {
5679 std::string str = msprintf("Invalid custom page: Page \"%s\" not found in ODB", path.c_str());
5680 show_error_404(r, str.c_str());
5681 return;
5682 }
5683}
5684
5685/*------------------------------------------------------------------*/
5686
5687static void show_cnaf_page(Param* p, Return* rr)
5688{
5689 char str[256];
5690 int c, n, a, f, d, q, x, r, ia, id, w;
5691 int i, size, status;
5692 HNDLE hDB, hrootkey, hsubkey, hkey;
5693
5694 static char client_name[NAME_LENGTH];
5695 static HNDLE hconn = 0;
5696
5698
5699 /* find FCNA server if not specified */
5700 if (hconn == 0) {
5701 /* find client which exports FCNA function */
5702 status = db_find_key(hDB, 0, "System/Clients", &hrootkey);
5703 if (status == DB_SUCCESS) {
5704 for (i = 0;; i++) {
5705 status = db_enum_key(hDB, hrootkey, i, &hsubkey);
5707 break;
5708
5709 sprintf(str, "RPC/%d", RPC_CNAF16);
5710 status = db_find_key(hDB, hsubkey, str, &hkey);
5711 if (status == DB_SUCCESS) {
5712 size = sizeof(client_name);
5713 db_get_value(hDB, hsubkey, "Name", client_name, &size, TID_STRING, TRUE);
5714 break;
5715 }
5716 }
5717 }
5718
5719 if (client_name[0]) {
5720 status = cm_connect_client(client_name, &hconn);
5721 if (status != RPC_SUCCESS)
5722 hconn = 0;
5723 }
5724 }
5725
5726 /* header */
5727 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
5728 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
5729 rr->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
5730
5731 rr->rsprintf("<html><head>\n");
5732 rr->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
5733 rr->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
5734 rr->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
5735 rr->rsprintf("<title>MIDAS CAMAC interface</title></head>\n");
5736 rr->rsprintf("<body><form method=\"GET\" action=\"CNAF\">\n\n");
5737
5738 /* title row */
5739
5740 size = sizeof(str);
5741 str[0] = 0;
5742 db_get_value(hDB, 0, "/Experiment/Name", str, &size, TID_STRING, TRUE);
5743
5744 rr->rsprintf("<table border=3 cellpadding=1>\n");
5745 rr->rsprintf("<tr><th colspan=3>MIDAS experiment \"%s\"", str);
5746
5747 if (client_name[0] == 0)
5748 rr->rsprintf("<th colspan=3 class=\"redLight\">No CAMAC server running</tr>\n");
5749 else if (hconn == 0)
5750 rr->rsprintf("<th colspan=3 class=\"redLight\">Cannot connect to %s</tr>\n", client_name);
5751 else
5752 rr->rsprintf("<th colspan=3>CAMAC server: %s</tr>\n", client_name);
5753
5754 /* default values */
5755 c = n = 1;
5756 a = f = d = q = x = 0;
5757 r = 1;
5758 ia = id = w = 0;
5759
5760 /*---- menu buttons ----*/
5761
5762 rr->rsprintf("<tr><td colspan=3>\n");
5763 rr->rsprintf("<input type=submit name=cmd value=Execute>\n");
5764
5765 rr->rsprintf("<td colspan=3>\n");
5766 rr->rsprintf("<input type=submit name=cmd value=ODB>\n");
5767 rr->rsprintf("<input type=submit name=cmd value=Status>\n");
5768 rr->rsprintf("<input type=submit name=cmd value=Help>\n");
5769 rr->rsprintf("</tr>\n\n");
5770
5771 /* header */
5772 rr->rsprintf("<tr><th>N");
5773 rr->rsprintf("<th>A");
5774 rr->rsprintf("<th>F");
5775 rr->rsprintf("<th colspan=3>Data");
5776
5777 /* execute commands */
5778 size = sizeof(d);
5779
5780 const char* cmd = p->getparam("cmd");
5781 if (equal_ustring(cmd, "C cycle")) {
5782 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5783 &q);
5784
5785 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">C cycle executed sucessfully</tr>\n");
5786 } else if (equal_ustring(cmd, "Z cycle")) {
5787 rpc_client_call(hconn, RPC_CNAF16, CNAF_CRATE_ZINIT, 0, 0, 0, 0, 0, &d, &size, &x,
5788 &q);
5789
5790 rr->rsprintf("<tr><td colspan=6 class=\"greenLight\">Z cycle executed sucessfully</tr>\n");
5791 } else if (equal_ustring(cmd, "Clear inhibit")) {
5792 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_CLEAR, 0, 0, 0, 0, 0, &d, &size, &x,
5793 &q);
5794
5795 rr->rsprintf
5796 ("<tr><td colspan=6 class=\"greenLight\">Clear inhibit executed sucessfully</tr>\n");
5797 } else if (equal_ustring(cmd, "Set inhibit")) {
5798 rpc_client_call(hconn, RPC_CNAF16, CNAF_INHIBIT_SET, 0, 0, 0, 0, 0, &d, &size, &x,
5799 &q);
5800
5801 rr->rsprintf
5802 ("<tr><td colspan=6 class=\"greenLight\">Set inhibit executed sucessfully</tr>\n");
5803 } else if (equal_ustring(cmd, "Execute")) {
5804 c = atoi(p->getparam("C"));
5805 n = atoi(p->getparam("N"));
5806 a = atoi(p->getparam("A"));
5807 f = atoi(p->getparam("F"));
5808 r = atoi(p->getparam("R"));
5809 w = atoi(p->getparam("W"));
5810 id = atoi(p->getparam("ID"));
5811 ia = atoi(p->getparam("IA"));
5812
5813 const char* pd = p->getparam("D");
5814 if (strncmp(pd, "0x", 2) == 0)
5815 sscanf(pd + 2, "%x", &d);
5816 else
5817 d = atoi(p->getparam("D"));
5818
5819 /* limit repeat range */
5820 if (r == 0)
5821 r = 1;
5822 if (r > 100)
5823 r = 100;
5824 if (w > 1000)
5825 w = 1000;
5826
5827 for (i = 0; i < r; i++) {
5828 status = SUCCESS;
5829
5830 if (hconn) {
5831 size = sizeof(d);
5832 status =
5833 rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x,
5834 &q);
5835
5836 if (status == RPC_NET_ERROR) {
5837 /* try to reconnect */
5838 //cm_disconnect_client(hconn, FALSE);
5839 status = cm_connect_client(client_name, &hconn);
5840 if (status != RPC_SUCCESS) {
5841 hconn = 0;
5842 client_name[0] = 0;
5843 }
5844
5845 if (hconn) {
5846 status = rpc_client_call(hconn, RPC_CNAF24, CNAF, 0, c, n, a, f, &d, &size, &x, &q);
5847 }
5848 }
5849 }
5850
5851 if (status != SUCCESS) {
5852 rr->rsprintf
5853 ("<tr><td colspan=6 class=\"redLight\">Error executing function, code = %d</tr>",
5854 status);
5855 } else {
5856 rr->rsprintf("<tr align=center><td>%d", n);
5857 rr->rsprintf("<td>%d", a);
5858 rr->rsprintf("<td>%d", f);
5859 rr->rsprintf("<td colspan=3>%d / 0x%04X Q%d X%d", d, d, q, x);
5860 }
5861
5862 d += id;
5863 a += ia;
5864
5865 if (w > 0)
5866 ss_sleep(w);
5867 }
5868 }
5869
5870 /* input fields */
5871 rr->rsprintf
5872 ("<tr align=center><td><input type=text size=3 name=N value=%d>\n",
5873 n);
5874 rr->rsprintf("<td><input type=text size=3 name=A value=%d>\n", a);
5875 rr->rsprintf("<td><input type=text size=3 name=F value=%d>\n", f);
5876 rr->rsprintf
5877 ("<td colspan=3><input type=text size=8 name=D value=%d></tr>\n",
5878 d);
5879
5880 /* control fields */
5881 rr->rsprintf("<tr><td colspan=2>Repeat");
5882 rr->rsprintf("<td><input type=text size=3 name=R value=%d>\n", r);
5883
5884 rr->rsprintf
5885 ("<td align=center colspan=3><input type=submit name=cmd value=\"C cycle\">\n");
5886 rr->rsprintf("<input type=submit name=cmd value=\"Z cycle\">\n");
5887
5888 rr->rsprintf("<tr><td colspan=2>Repeat delay [ms]");
5889 rr->rsprintf("<td><input type=text size=3 name=W value=%d>\n", w);
5890
5891 rr->rsprintf
5892 ("<td align=center colspan=3><input type=submit name=cmd value=\"Set inhibit\">\n");
5893 rr->rsprintf("<input type=submit name=cmd value=\"Clear inhibit\">\n");
5894
5895 rr->rsprintf("<tr><td colspan=2>Data increment");
5896 rr->rsprintf("<td><input type=text size=3 name=ID value=%d>\n", id);
5897
5898 rr->rsprintf
5899 ("<td colspan=3 align=center>Branch <input type=text size=3 name=B value=0>\n");
5900
5901 rr->rsprintf("<tr><td colspan=2>A increment");
5902 rr->rsprintf("<td><input type=text size=3 name=IA value=%d>\n", ia);
5903
5904 rr->rsprintf
5905 ("<td colspan=3 align=center>Crate <input type=text size=3 name=C value=%d>\n",
5906 c);
5907
5908 rr->rsprintf("</table></body>\r\n");
5909}
5910
5911/*------------------------------------------------------------------*/
5912
5913#ifdef HAVE_MSCB
5914
5915typedef struct {
5916 signed char id;
5917 char name[32];
5918} NAME_TABLE;
5919
5920static const NAME_TABLE prefix_table[] = {
5921 {PRFX_PICO, "pico",},
5922 {PRFX_NANO, "nano",},
5923 {PRFX_MICRO, "micro",},
5924 {PRFX_MILLI, "milli",},
5925 {PRFX_NONE, "",},
5926 {PRFX_KILO, "kilo",},
5927 {PRFX_MEGA, "mega",},
5928 {PRFX_GIGA, "giga",},
5929 {PRFX_TERA, "tera",},
5930 {99}
5931};
5932
5933static const NAME_TABLE unit_table[] = {
5934
5935 {UNIT_METER, "meter",},
5936 {UNIT_GRAM, "gram",},
5937 {UNIT_SECOND, "second",},
5938 {UNIT_MINUTE, "minute",},
5939 {UNIT_HOUR, "hour",},
5940 {UNIT_AMPERE, "ampere",},
5941 {UNIT_KELVIN, "kelvin",},
5942 {UNIT_CELSIUS, "deg. celsius",},
5943 {UNIT_FARENHEIT, "deg. farenheit",},
5944
5945 {UNIT_HERTZ, "hertz",},
5946 {UNIT_PASCAL, "pascal",},
5947 {UNIT_BAR, "bar",},
5948 {UNIT_WATT, "watt",},
5949 {UNIT_VOLT, "volt",},
5950 {UNIT_OHM, "ohm",},
5951 {UNIT_TESLA, "tesls",},
5952 {UNIT_LITERPERSEC, "liter/sec",},
5953 {UNIT_RPM, "RPM",},
5954 {UNIT_FARAD, "farad",},
5955
5956 {UNIT_BOOLEAN, "boolean",},
5957 {UNIT_BYTE, "byte",},
5958 {UNIT_WORD, "word",},
5959 {UNIT_DWORD, "dword",},
5960 {UNIT_ASCII, "ascii",},
5961 {UNIT_STRING, "string",},
5962 {UNIT_BAUD, "baud",},
5963
5964 {UNIT_PERCENT, "percent",},
5965 {UNIT_PPM, "RPM",},
5966 {UNIT_COUNT, "counts",},
5967 {UNIT_FACTOR, "factor",},
5968 {0}
5969};
5970
5971/*------------------------------------------------------------------*/
5972
5973void print_mscb_var(char *value, char *evalue, char *unit, MSCB_INFO_VAR *info_chn, void *pdata)
5974{
5975 char str[80];
5976 signed short sdata;
5977 unsigned short usdata;
5978 signed int idata;
5979 unsigned int uidata;
5980 float fdata;
5981 int i;
5982
5983 value[0] = 0;
5984 evalue[0] = 0;
5985
5986 if (info_chn->unit == UNIT_STRING) {
5987 memset(str, 0, sizeof(str));
5988 strncpy(str, (char *)pdata, info_chn->width);
5989 for (i = 0; i < (int) strlen(str); i++)
5990 switch (str[i]) {
5991 case 1:
5992 strcat(value, "\\001");
5993 break;
5994 case 2:
5995 strcat(value, "\\002");
5996 break;
5997 case 9:
5998 strcat(value, "\\t");
5999 break;
6000 case 10:
6001 strcat(value, "\\n");
6002 break;
6003 case 13:
6004 strcat(value, "\\r");
6005 break;
6006 default:
6007 value[strlen(value) + 1] = 0;
6008 value[strlen(value)] = str[i];
6009 break;
6010 }
6011 mstrlcpy(evalue, value, 256);
6012 } else {
6013 switch (info_chn->width) {
6014 case 0:
6015 strcpy(value, "0");
6016 strcpy(evalue, "0");
6017 break;
6018
6019 case 1:
6020 if (info_chn->flags & MSCBF_SIGNED) {
6021 sprintf(value, "%d (0x%02X/", *((signed char *)pdata), *((signed char *)pdata));
6022 sprintf(evalue, "%d", *((signed char *)pdata));
6023 } else {
6024 sprintf(value, "%u (0x%02X/", *((unsigned char *)pdata), *((unsigned char *)pdata));
6025 sprintf(evalue, "%u", *((unsigned char *)pdata));
6026 }
6027
6028 for (i = 0; i < 8; i++)
6029 if (*((unsigned char *)pdata) & (0x80 >> i))
6030 sprintf(value + strlen(value), "1");
6031 else
6032 sprintf(value + strlen(value), "0");
6033 sprintf(value + strlen(value), ")");
6034 break;
6035
6036 case 2:
6037 if (info_chn->flags & MSCBF_SIGNED) {
6038 sdata = *((signed short *)pdata);
6039 WORD_SWAP(&sdata);
6040 sprintf(value, "%d (0x%04X)", sdata, sdata);
6041 sprintf(evalue, "%d", sdata);
6042 } else {
6043 usdata = *((unsigned short *)pdata);
6044 WORD_SWAP(&usdata);
6045 sprintf(value, "%u (0x%04X)", usdata, usdata);
6046 sprintf(evalue, "%u", usdata);
6047 }
6048 break;
6049
6050 case 4:
6051 if (info_chn->flags & MSCBF_FLOAT) {
6052 fdata = *((float *)pdata);
6053 DWORD_SWAP(&fdata);
6054 sprintf(value, "%1.6lg", fdata);
6055 sprintf(evalue, "%1.6lg", fdata);
6056 } else {
6057 if (info_chn->flags & MSCBF_SIGNED) {
6058 idata = *((signed int *)pdata);
6059 DWORD_SWAP(&idata);
6060 sprintf(value, "%d (0x%08X)", idata, idata);
6061 sprintf(evalue, "%d", idata);
6062 } else {
6063 uidata = *((unsigned int *)pdata);
6064 DWORD_SWAP(&uidata);
6065 sprintf(value, "%u (0x%08X)", uidata, uidata);
6066 sprintf(evalue, "%u", uidata);
6067 }
6068 }
6069 break;
6070 }
6071 }
6072
6073 /* evaluate prefix */
6074 unit[0] = 0;
6075 if (info_chn->prefix) {
6076 for (i = 0; prefix_table[i].id != 99; i++)
6077 if ((unsigned char)prefix_table[i].id == info_chn->prefix)
6078 break;
6079 if (prefix_table[i].id)
6080 strcpy(unit, prefix_table[i].name);
6081 }
6082
6083 /* evaluate unit */
6084 if (info_chn->unit && info_chn->unit != UNIT_STRING) {
6085 for (i = 0; unit_table[i].id; i++)
6086 if ((unsigned char)unit_table[i].id == info_chn->unit)
6087 break;
6088 if (unit_table[i].id)
6089 strcat(unit, unit_table[i].name);
6090 }
6091}
6092
6093static int cmp_int(const void *a, const void *b)
6094{
6095 return *((int *)a) > *((int *)b);
6096}
6097
6098/*------------------------------------------------------------------*/
6099
6100void create_mscb_tree()
6101{
6102 HNDLE hDB, hKeySubm, hKeyEq, hKeyAdr, hKey, hKeyDev;
6103 KEY key;
6104 int i, j, k, l, size, address[1000], dev_badr[1000], dev_adr[1000], dev_chn[1000],
6105 n_address, n_dev_adr;
6106 char mscb_dev[256], mscb_pwd[32], eq_name[32];
6107
6109
6110 db_create_key(hDB, 0, "MSCB/Submaster", TID_KEY);
6111 db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6112 assert(hKeySubm);
6113
6114 /*---- go through equipment list ----*/
6115 db_find_key(hDB, 0, "Equipment", &hKeyEq);
6116 if (hKeyEq) {
6117 for (i=0 ; ; i++) {
6118 db_enum_key(hDB, hKeyEq, i, &hKey);
6119 if (!hKey)
6120 break;
6121 db_get_key(hDB, hKey, &key);
6122 strcpy(eq_name, key.name);
6123 db_find_key(hDB, hKey, "Settings/Devices", &hKeyDev);
6124 if (hKeyDev) {
6125 for (j=0 ;; j++) {
6126 db_enum_key(hDB, hKeyDev, j, &hKey);
6127 if (!hKey)
6128 break;
6129
6130 if (db_find_key(hDB, hKey, "MSCB Address", &hKeyAdr) == DB_SUCCESS) {
6131 /* mscbdev type of device */
6132 size = sizeof(mscb_dev);
6133 if (db_get_value(hDB, hKey, "Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6134 continue;
6135 size = sizeof(mscb_pwd);
6136 if (db_get_value(hDB, hKey, "Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6137 continue;
6138
6139 size = sizeof(dev_adr);
6140 db_get_data(hDB, hKeyAdr, dev_adr, &size, TID_INT);
6141 n_dev_adr = size / sizeof(int);
6142 } else if (db_find_key(hDB, hKey, "Block Address", &hKeyAdr) == DB_SUCCESS) {
6143 /* mscbhvr type of device */
6144 size = sizeof(mscb_dev);
6145 if (db_get_value(hDB, hKey, "MSCB Device", mscb_dev, &size, TID_STRING, FALSE) != DB_SUCCESS)
6146 continue;
6147 size = sizeof(mscb_pwd);
6148 if (db_get_value(hDB, hKey, "MSCB Pwd", mscb_pwd, &size, TID_STRING, FALSE) != DB_SUCCESS)
6149 continue;
6150
6151 n_dev_adr = 0;
6152 size = sizeof(dev_badr);
6153 db_get_data(hDB, hKeyAdr, dev_badr, &size, TID_INT);
6154 size = sizeof(dev_chn);
6155 if (db_get_value(hDB, hKey, "Block Channels", dev_chn, &size, TID_INT, FALSE) == DB_SUCCESS) {
6156 for (k=0 ; k<size/(int)sizeof(int) && n_dev_adr < (int)(sizeof(dev_adr)/sizeof(int)) ; k++) {
6157 for (l=0 ; l<dev_chn[k] ; l++)
6158 dev_adr[n_dev_adr++] = dev_badr[k]+l;
6159 }
6160 }
6161 } else
6162 continue;
6163
6164 /* create or open submaster entry */
6165 db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
6166 if (!hKey) {
6167 db_create_key(hDB, hKeySubm, mscb_dev, TID_KEY);
6168 db_find_key(hDB, hKeySubm, mscb_dev, &hKey);
6169 assert(hKey);
6170 }
6171
6172 /* get old address list */
6173 size = sizeof(address);
6174 if (db_get_value(hDB, hKey, "Address", address, &size, TID_INT, FALSE) == DB_SUCCESS)
6175 n_address = size / sizeof(int);
6176 else
6177 n_address = 0;
6178
6179 /* merge with new address list */
6180 for (k=0 ; k<n_dev_adr ; k++) {
6181 for (l=0 ; l<n_address ; l++)
6182 if (address[l] == dev_adr[k])
6183 break;
6184
6185 if (l == n_address)
6186 address[n_address++] = dev_adr[k];
6187 }
6188
6189 /* sort address list */
6190 qsort(address, n_address, sizeof(int), cmp_int);
6191
6192 /* store new address list */
6193 db_set_value(hDB, hKey, "Pwd", mscb_pwd, 32, 1, TID_STRING);
6194 db_set_value(hDB, hKey, "Comment", eq_name, 32, 1, TID_STRING);
6195 db_set_value(hDB, hKey, "Address", address, n_address*sizeof(int), n_address, TID_INT);
6196 }
6197 }
6198 }
6199 }
6200}
6201
6202/*------------------------------------------------------------------*/
6203
6204void show_mscb_page(Param* p, Return* r, int refresh)
6205{
6206 int i, j, n, ind, fi, fd, status, size, n_addr, cur_node, adr, show_hidden;
6207 unsigned int uptime;
6208 BOOL comment_created;
6209 float fvalue;
6210 char *pd;
6211 char dbuf[256], evalue[256], unit[256], cur_subm_name[256];
6212 HNDLE hDB, hKeySubm, hKeyCurSubm, hKey, hKeyAddr, hKeyComm;
6213 KEY key;
6214 MSCB_INFO info;
6215 MSCB_INFO_VAR info_var;
6216 int ping_addr[0x10000];
6217
6219
6220 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6221 if (!hKeySubm)
6222 create_mscb_tree();
6223
6224 mstrlcpy(cur_subm_name, p->getparam("subm"), sizeof(cur_subm_name));
6225 if (cur_subm_name[0] == 0) {
6226 db_enum_key(hDB, hKeySubm, 0, &hKeyCurSubm);
6227 if (!hKeyCurSubm) {
6228 char errorstr[256];
6229 sprintf(errorstr, "No submaster defined under /MSCB/Submaster");
6230 show_error(r, errorstr);
6231 return;
6232 }
6233 db_get_key(hDB, hKeyCurSubm, &key);
6234 strcpy(cur_subm_name, key.name);
6235 } else
6236 db_find_key(hDB, hKeySubm, cur_subm_name, &hKeyCurSubm);
6237
6238 if (p->isparam("node"))
6239 cur_node = atoi(p->getparam("node"));
6240 else
6241 cur_node = -1;
6242
6243 /* perform MSCB rescan */
6244 if (p->isparam("mcmd") && equal_ustring(p->getparam("mcmd"), "Rescan") && p->isparam("subm")) {
6245 /* create Pwd and Comment if not there */
6246 char tmp[32];
6247 size = 32;
6248 tmp[0] = 0;
6249 db_get_value(hDB, hKeyCurSubm, "Pwd", (void *)tmp, &size, TID_STRING, true);
6250 tmp[0] = 0;
6251 db_get_value(hDB, hKeyCurSubm, "Comment", (void *)tmp, &size, TID_STRING, true);
6252
6253 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6254 std::vector<int> addr;
6255 std::vector<char> node_comment;
6256 if (hKeyAddr) {
6257 /* get current address array */
6258 db_get_key(hDB, hKeyAddr, &key);
6259 n_addr = key.num_values;
6260 addr.resize(n_addr);
6261 size = sizeof(int)*n_addr;
6262 db_get_data(hDB, hKeyAddr, addr.data(), &size, TID_INT);
6263 } else {
6264 /* create new address array */
6265 db_create_key(hDB, hKeyCurSubm, "Address", TID_INT);
6266 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6267 n_addr = 0;
6268 addr.resize(1);
6269 }
6270
6271 comment_created = FALSE;
6272 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6273 if (hKeyComm) {
6274 /* get current node comments */
6275 db_get_key(hDB, hKeyComm, &key);
6276 node_comment.resize(32*key.num_values);
6277 size = 32*key.num_values;
6278 db_get_data(hDB, hKeyComm, node_comment.data(), &size, TID_STRING);
6279 } else {
6280 /* create new comment array */
6281 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6282 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6283 node_comment.resize(32);
6284 comment_created = TRUE;
6285 }
6286
6287 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6288 if (fd >= 0) {
6289 /* fill table of possible addresses */
6290 for (i=0 ; i<0x10000 ; i++)
6291 ping_addr[i] = 0;
6292 for (i=0 ; i<1000 ; i++) // 0..999
6293 ping_addr[i] = 1;
6294 for (i=0 ; i<0x10000 ; i+=100) // 100, 200, ...
6295 ping_addr[i] = 1;
6296 for (i=0 ; i<0x10000 ; i+= 0x100)
6297 ping_addr[i] = 1; // 256, 512, ...
6298 for (i=0xFF00 ; i<0x10000 ; i++)
6299 ping_addr[i] = 1; // 0xFF00-0xFFFF
6300
6301 for (ind = n = 0; ind < 0x10000; ind++) {
6302 if (!ping_addr[ind])
6303 continue;
6304
6305 status = mscb_ping(fd, (unsigned short) ind, 1, 0);
6306 if (status == MSCB_SUCCESS) {
6307
6308 /* node found, search next 100 as well */
6309 for (j=ind; j<ind+100 && j<0x10000 ; j++)
6310 if (j >= 0)
6311 ping_addr[j] = 1;
6312
6313 status = mscb_info(fd, (unsigned short) ind, &info);
6314
6315 if (status == MSCB_SUCCESS) {
6316 /* check if node already in list */
6317 for (j=0 ; j<n_addr ; j++)
6318 if (addr[j] == ind)
6319 break;
6320 if (j == n_addr) {
6321 addr.resize(n_addr+1);
6322 addr[n_addr] = ind;
6323 node_comment.resize(32*(n_addr+1));
6324 /* use node name as default comment */
6325 strncpy(node_comment.data()+n_addr*32, info.node_name, 32);
6326 n_addr ++;
6327 } else if (comment_created) {
6328 node_comment.resize(32*n_addr);
6329 /* use node name as default comment */
6330 strncpy(node_comment.data()+j*32, info.node_name, 32);
6331 }
6332 }
6333 }
6334 }
6335
6336 db_set_data(hDB, hKeyAddr, addr.data(), n_addr*sizeof(int), n_addr, TID_INT);
6337 db_set_data(hDB, hKeyComm, node_comment.data(), n_addr*32, n_addr, TID_STRING);
6338
6339 char redirstr[512];
6340 sprintf(redirstr, "?cmd=mscb&subm=%s", cur_subm_name);
6341 redirect(r, redirstr);
6342 return;
6343
6344 } else {
6345 char errorstr[512];
6346 sprintf(errorstr, "Cannot talk to submaster \"%s\"", cur_subm_name);
6347 show_error(r, errorstr);
6348 return;
6349 }
6350 }
6351
6352 /* write data to node */
6353 if (p->isparam("subm") && p->isparam("node") &&
6354 p->isparam("idx") && p->isparam("value")) {
6355 i = atoi(p->getparam("idx"));
6356 char value[256];
6357 mstrlcpy(value, p->getparam("value"), sizeof(value));
6358
6359 fd = mscb_init(cur_subm_name, 0, "", FALSE);
6360 if (fd >= 0) {
6361 status = mscb_info_variable(fd,
6362 (unsigned short) cur_node, (unsigned char) i, &info_var);
6363 if (status == MSCB_SUCCESS) {
6364 if (info_var.unit == UNIT_STRING) {
6365 char valstr[256];
6366 mstrlcpy(valstr, value, sizeof(valstr));
6367 if (strlen(valstr) > 0 && valstr[strlen(valstr) - 1] == '\n')
6368 valstr[strlen(valstr) - 1] = 0;
6369
6370 status = mscb_write(fd, (unsigned short) cur_node,
6371 (unsigned char) i, valstr, strlen(valstr) + 1);
6372 } else {
6373 if (info_var.flags & MSCBF_FLOAT) {
6374 fvalue = (float) atof(value);
6375 memcpy(&dbuf, &fvalue, sizeof(float));
6376 } else {
6377 if (value[1] == 'x')
6378 sscanf(value + 2, "%x", (int *)&dbuf);
6379 else
6380 *((int *)dbuf) = atoi(value);
6381 }
6382
6383 status = mscb_write(fd, (unsigned short) cur_node,
6384 (unsigned char) i, dbuf, info_var.width);
6385 }
6386 }
6387 }
6388 char redirstr[512];
6389 sprintf(redirstr, "?cmd=mscb&subm=%s&node=%d", cur_subm_name, cur_node);
6390 redirect(r, redirstr);
6391 return;
6392 }
6393
6394 if (p->isparam("hidden"))
6395 show_hidden = atoi(p->getparam("hidden"));
6396 else
6397 show_hidden = FALSE;
6398
6399 show_header(r, "MSCB", "GET", "./", refresh);
6400 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6401 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6402 show_navigation_bar(r, "MSCB");
6403
6404 /* style sheet */
6405 r->rsprintf("<style type=\"text/css\">\r\n");
6406 r->rsprintf("select { width:150px; background-color:#FFFFE0; font-size:12px; }\r\n");
6407 r->rsprintf(".subm {\r\n");
6408 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6409 r->rsprintf(" padding:5px;\r\n");
6410 r->rsprintf(" vertical-align:top;\r\n");
6411 r->rsprintf(" font-size:16px;\r\n");
6412 r->rsprintf(" border-right:1px solid #808080;\r\n");
6413 r->rsprintf("}\r\n");
6414 r->rsprintf(".node {\r\n");
6415 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6416 r->rsprintf(" padding:5px;\r\n");
6417 r->rsprintf(" vertical-align:top;\r\n");
6418 r->rsprintf(" font-size:16px;\r\n");
6419 r->rsprintf(" border-right:1px solid #808080;\r\n");
6420 r->rsprintf("}\r\n");
6421 r->rsprintf(".vars {\r\n");
6422 r->rsprintf(" background-color:#E0E0E0; text-align:center; font-weight:bold;\r\n");
6423 r->rsprintf(" padding:5px;\r\n");
6424 r->rsprintf(" vertical-align:top;\r\n");
6425 r->rsprintf(" font-size:10px;\r\n");
6426 r->rsprintf("}\r\n");
6427 r->rsprintf(".v1 {\r\n");
6428 r->rsprintf(" padding:3px;\r\n");
6429 r->rsprintf(" font-weight:bold;\r\n");
6430 r->rsprintf(" font-size:12px;\r\n");
6431 r->rsprintf("}\r\n");
6432 r->rsprintf(".v2 {\r\n");
6433 r->rsprintf(" background-color:#F0F0F0;\r\n");
6434 r->rsprintf(" padding:3px;\r\n");
6435 r->rsprintf(" font-size:12px;\r\n");
6436 r->rsprintf(" border:1px solid #808080;\r\n");
6437 r->rsprintf(" border-right:1px solid #FFFFFF;\r\n");
6438 r->rsprintf(" border-bottom:1px solid #FFFFFF;\r\n");
6439 r->rsprintf("}\r\n");
6440 r->rsprintf(".v3 {\r\n");
6441 r->rsprintf(" padding:3px;\r\n");
6442 r->rsprintf(" font-size:12px;\r\n");
6443 r->rsprintf("}\r\n");
6444 r->rsprintf("</style>\r\n\r\n");
6445
6446 /* javascript */
6447 r->rsprintf("<script type=\"text/javascript\">\r\n");
6448 r->rsprintf("function mscb_edit(index, value)\r\n");
6449 r->rsprintf("{\r\n");
6450 r->rsprintf(" var new_value = prompt('Please enter new value', value);\r\n");
6451 r->rsprintf(" if (new_value != undefined) {\r\n");
6452 r->rsprintf(" window.location.search = '?cmd=mscb&subm=%s&node=%d&idx='+index+'&value='+new_value;\n", cur_subm_name, cur_node);
6453 r->rsprintf(" }\n");
6454 r->rsprintf("}\r\n");
6455 r->rsprintf("</script>\r\n\r\n");
6456
6457 /*---- main content ----*/
6458
6459 r->rsprintf("<table class=\"mtable\">"); //main table
6460 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>MSCB</th><tr>");
6461
6462 /*---- menu buttons ----*/
6463
6464 r->rsprintf("<tr><td colspan=2>\n");
6465 r->rsprintf("<table width=100%%><tr>\n");
6466 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());
6467
6468 r->rsprintf("<tr><td colspan=\"2\" cellpadding=\"0\" cellspacing=\"0\">\r\n");
6469
6470 status = db_find_key(hDB, 0, "MSCB/Submaster", &hKeySubm);
6471 if (status != DB_SUCCESS) {
6472 r->rsprintf("<h1>No MSCB Submasters defined in ODB</h1>\r\n");
6473 r->rsprintf("</td></tr>\r\n");
6474 r->rsprintf("</table>\r\n"); //submaster table
6475 r->rsprintf("</td></tr>\r\n");
6476 r->rsprintf("</table>\r\n"); //main table
6477 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6478 r->rsprintf("</form>\n");
6479 r->rsprintf("</body></html>\r\n");
6480 return;
6481 }
6482
6483 r->rsprintf("<table width=\"100%%\" cellpadding=\"0\" cellspacing=\"0\">");
6484
6485 /*---- submaster list ----*/
6486 r->rsprintf("<tr><td class=\"subm\">\r\n");
6487 r->rsprintf("Submaster<hr>\r\n");
6488
6489 /* count submasters */
6490 for (i = 0;;i++) {
6491 db_enum_key(hDB, hKeySubm, i, &hKey);
6492 if (!hKey)
6493 break;
6494 }
6495 if (i<2)
6496 i = 2;
6497
6498 r->rsprintf("<select name=\"subm\" id=\"subm\" size=%d ", i);
6499 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm='+document.getElementById('subm').value;\">\r\n");
6500 hKeyCurSubm = 0;
6501 for (i = 0;;i++) {
6502 db_enum_key(hDB, hKeySubm, i, &hKey);
6503 if (!hKey)
6504 break;
6505 db_get_key(hDB, hKey, &key);
6506 char str[NAME_LENGTH+10+256];
6507 mstrlcpy(str, key.name, sizeof(str));
6508 char comment[256];
6509 size = sizeof(comment);
6510 if (db_get_value(hDB, hKey, "Comment", comment, &size, TID_STRING, FALSE) == DB_SUCCESS) {
6511 mstrlcat(str, ": ", sizeof(str));
6512 mstrlcat(str, comment, sizeof(str));
6513 }
6514
6515 if ((cur_subm_name[0] && equal_ustring(cur_subm_name, key.name)) ||
6516 (cur_subm_name[0] == 0 && i == 0)) {
6517 r->rsprintf("<option value=\"%s\" selected>%s</option>\r\n", key.name, str);
6518 hKeyCurSubm = hKey;
6519 } else
6520 r->rsprintf("<option value=\"%s\">%s</option>\r\n", key.name, str);
6521 }
6522 r->rsprintf("</select>\r\n");
6523
6524 /*---- node list ----*/
6525 r->rsprintf("<td class=\"node\">\r\n");
6526 r->rsprintf("Node ");
6527
6528 r->rsprintf("<script type=\"text/javascript\">\n");
6529 r->rsprintf("<!--\n");
6530 r->rsprintf("function rescan()\n");
6531 r->rsprintf("{\n");
6532 r->rsprintf(" flag = confirm('Rescan can take up to one minute.');\n");
6533 r->rsprintf(" if (flag == true)\n");
6534 r->rsprintf(" window.location.href = '?cmd=mscb&mcmd=Rescan&subm=%s';\n", cur_subm_name);
6535 r->rsprintf("}\n");
6536 r->rsprintf("//-->\n");
6537 r->rsprintf("</script>\n");
6538
6539 r->rsprintf("<input type=button name=cmd value=\"Rescan\" onClick=\"rescan();\">");
6540 r->rsprintf("<hr>\r\n");
6541
6542 if (!hKeyCurSubm) {
6543 r->rsprintf("No submaster found in ODB\r\n");
6544 r->rsprintf("</td></tr>\r\n");
6545 r->rsprintf("</table>\r\n"); //inner submaster table
6546 r->rsprintf("</td></tr>\r\n");
6547 r->rsprintf("</table>\r\n"); //submaster table
6548 r->rsprintf("</td></tr>\r\n");
6549 r->rsprintf("</table>\r\n"); //main table
6550 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6551 r->rsprintf("</form>\n");
6552 r->rsprintf("</body></html>\r\n");
6553 return;
6554 }
6555
6556 db_find_key(hDB, hKeyCurSubm, "Address", &hKeyAddr);
6557 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6558
6559 i = 10;
6560 if (hKeyAddr) {
6561 db_get_key(hDB, hKeyAddr, &key);
6562 i = key.num_values;
6563
6564 if (hKeyComm == 0) {
6565 db_create_key(hDB, hKeyCurSubm, "Node comment", TID_STRING);
6566 db_find_key(hDB, hKeyCurSubm, "Node comment", &hKeyComm);
6567 }
6568 db_get_key(hDB, hKeyComm, &key);
6569 if (key.num_values < i) {
6570 char str[32] = "";
6571 for (int j=key.num_values ; j<i ; j++)
6572 db_set_data_index(hDB, hKeyComm, str, 32, j, TID_STRING);
6573 }
6574 }
6575 if (i < 2)
6576 i = 2;
6577
6578 r->rsprintf("<select name=\"node\" id=\"node\" size=%d ", i);
6579 r->rsprintf("onChange=\"window.location.search='?cmd=mscb&subm=%s&node='+document.getElementById('node').value;\">\r\n", cur_subm_name);
6580
6581 if (hKeyAddr) {
6582 db_get_key(hDB, hKeyAddr, &key);
6583 size = sizeof(adr);
6584
6585 /* check if current node is in list */
6586 for (i = 0; i<key.num_values ;i++) {
6587 size = sizeof(adr);
6588 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6589 if (adr == cur_node)
6590 break;
6591 }
6592 if (i == key.num_values) // if not found, use first one in list
6593 db_get_data_index(hDB, hKeyAddr, &cur_node, &size, 0, TID_INT);
6594
6595 for (i = 0; i<key.num_values ;i++) {
6596 char str[100+256];
6597 size = sizeof(adr);
6598 db_get_data_index(hDB, hKeyAddr, &adr, &size, i, TID_INT);
6599 if (hKeyComm) {
6600 char comment[256];
6601 size = sizeof(comment);
6602 db_get_data_index(hDB, hKeyComm, comment, &size, i, TID_STRING);
6603 sprintf(str, "%d: %s", adr, comment);
6604 } else {
6605 sprintf(str, "%d", adr);
6606 }
6607 if (cur_node == 0 && i == 0)
6608 cur_node = adr;
6609 if (adr == cur_node)
6610 r->rsprintf("<option selected>%s</option>\r\n", str);
6611 else
6612 r->rsprintf("<option>%s</option>\r\n", str);
6613 }
6614 }
6615 r->rsprintf("</select>\r\n");
6616
6617 /*---- node contents ----*/
6618 r->rsprintf("<td class=\"vars\">\r\n");
6619 r->rsprintf("<table>\r\n");
6620 db_get_key(hDB, hKeyCurSubm, &key);
6621 if (cur_node != -1)
6622 r->rsprintf("<tr><td colspan=3 align=center><b>%s:%d</b>", key.name, cur_node);
6623 else
6624 r->rsprintf("<tr><td colspan=3 align=center><b>%s</b>", key.name);
6625 r->rsprintf("<hr></td></tr>\r\n");
6626
6627 char passwd[32];
6628 passwd[0] = 0;
6629 size = 32;
6630 db_get_value(hDB, hKeyCurSubm, "Pwd", passwd, &size, TID_STRING, TRUE);
6631
6632 fd = mscb_init(key.name, 0, passwd, FALSE);
6633 if (fd < 0) {
6634 if (fd == EMSCB_WRONG_PASSWORD)
6635 r->rsprintf("<tr><td colspan=3><b>Invalid password</b></td>");
6636 else
6637 r->rsprintf("<tr><td colspan=3><b>Submaster does not respond</b></td>");
6638 goto mscb_error;
6639 }
6640 mscb_set_eth_max_retry(fd, 3);
6641 mscb_set_max_retry(1);
6642
6643 status = mscb_ping(fd, cur_node, 0, 1);
6644 if (status != MSCB_SUCCESS) {
6645 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6646 goto mscb_error;
6647 }
6648 status = mscb_info(fd, (unsigned short) cur_node, &info);
6649 if (status != MSCB_SUCCESS) {
6650 r->rsprintf("<tr><td colspan=3><b>No response from node</b></td>");
6651 goto mscb_error;
6652 }
6653 char tr16[17];
6654 mstrlcpy(tr16, info.node_name, sizeof(tr16));
6655 r->rsprintf("<tr><td class=\"v1\">Node name<td colspan=2 class=\"v2\">%s</tr>\n", tr16);
6656 r->rsprintf("<tr><td class=\"v1\">GIT revision<td colspan=2 class=\"v2\">%d</tr>\n", info.revision);
6657
6658 if (info.rtc[0] && info.rtc[0] != 0xFF) {
6659 for (i=0 ; i<6 ; i++)
6660 info.rtc[i] = (info.rtc[i] / 0x10) * 10 + info.rtc[i] % 0x10;
6661 r->rsprintf("<tr><td class=\"v1\">Real Time Clock<td colspan=2 class=\"v2\">%02d-%02d-%02d %02d:%02d:%02d</td>\n",
6662 info.rtc[0], info.rtc[1], info.rtc[2],
6663 info.rtc[3], info.rtc[4], info.rtc[5]);
6664 }
6665
6666 status = mscb_uptime(fd, (unsigned short) cur_node, &uptime);
6667 if (status == MSCB_SUCCESS)
6668 r->rsprintf("<tr><td class=\"v1\">Uptime<td colspan=2 class=\"v2\">%dd %02dh %02dm %02ds</tr>\n",
6669 uptime / (3600 * 24),
6670 (uptime % (3600 * 24)) / 3600, (uptime % 3600) / 60,
6671 (uptime % 60));
6672
6673 r->rsprintf("<tr><td colspan=3><hr></td></tr>\r\n");
6674
6675 /* check for hidden variables */
6676 for (i=0 ; i < info.n_variables ; i++) {
6677 mscb_info_variable(fd, cur_node, i, &info_var);
6678 if (info_var.flags & MSCBF_HIDDEN)
6679 break;
6680 }
6681 if (i < info.n_variables) {
6682 char str[32];
6683 strcpy(str, show_hidden ? " checked" : "");
6684 r->rsprintf("<tr><td colspan=3><input type=checkbox%s name=\"hidden\" value=\"1\"", str);
6685 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);
6686 }
6687
6688 /* read variables in blocks of 100 bytes */
6689 for (fi=0 ; fi < info.n_variables ; ) {
6690 for (i=fi,size=0 ; i < info.n_variables && size < 100; i++) {
6691 mscb_info_variable(fd, cur_node, i, &info_var);
6692 size += info_var.width;
6693 }
6694
6695 size = sizeof(dbuf);
6696 status = mscb_read_range(fd, cur_node, fi, i-1, dbuf, &size);
6697 if (status != MSCB_SUCCESS) {
6698 r->rsprintf("<tr><td colspan=3><b>Error reading data from node</b></td>");
6699 goto mscb_error;
6700 }
6701 pd = dbuf;
6702
6703 for (j=fi ; j<i ; j++) {
6704 status = mscb_info_variable(fd, cur_node, j, &info_var);
6705 if ((info_var.flags & MSCBF_HIDDEN) == 0 || show_hidden) {
6706 char tr8[9];
6707 mstrlcpy(tr8, info_var.name, sizeof(tr8));
6708 r->rsprintf("<tr><td class=\"v1\">%s</td>\r\n", tr8);
6709 r->rsprintf("<td class=\"v2\">\r\n");
6710 char value[256];
6711 print_mscb_var(value, evalue, unit, &info_var, pd);
6712 r->rsprintf("<a href=\"#\" onClick=\"mscb_edit(%d,'%s')\">%s</a>",
6713 j, evalue, value);
6714 r->rsprintf("</td><td class=\"v3\">%s</td>", unit);
6715 r->rsprintf("</tr>\r\n");
6716 }
6717 pd += info_var.width;
6718 }
6719
6720 fi = i;
6721 }
6722
6723mscb_error:
6724 r->rsprintf("</tr></table>\r\n");
6725 r->rsprintf("</td></tr></table>\r\n");
6726 r->rsprintf("</td></tr></table>\r\n");
6727 r->rsprintf("</td></tr></table>\r\n");
6728 r->rsprintf("</div></body></html>\r\n");
6729}
6730
6731#endif // HAVE_MSCB
6732
6733/*------------------------------------------------------------------*/
6734
6735void show_password_page(Return* r, const char* dec_path, const char *password)
6736{
6737 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6738 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6739 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6740
6741 r->rsprintf("<html><head>\n");
6742 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6743 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6744 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6745 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6746
6747 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6748
6749 /*---- page header ----*/
6750 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6751
6752 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6753 if (password[0])
6754 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6755
6756 r->rsprintf("<tr><th>Please enter password</tr>\n");
6757 r->rsprintf("<tr><td align=center><input type=password name=pwd></tr>\n");
6758 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6759
6760 r->rsprintf("</table>\n");
6761
6762 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6763 r->rsprintf("</form>\n");
6764 r->rsprintf("</body></html>\r\n");
6765}
6766
6767/*------------------------------------------------------------------*/
6768
6769BOOL check_web_password(Return* r, HNDLE hDB, const char* dec_path, const char *password, const char *redir)
6770{
6771 HNDLE hkey;
6772 INT size;
6773 char str[256];
6774
6775 /* check for password */
6776 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
6777 if (hkey) {
6778 size = sizeof(str);
6779 db_get_data(hDB, hkey, str, &size, TID_STRING);
6780 if (strcmp(password, str) == 0)
6781 return TRUE;
6782
6783 /* show web password page */
6784 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
6785 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
6786 r->rsprintf("Content-Type: text/html; charset=%s\r\n\r\n", HTTP_ENCODING);
6787
6788 r->rsprintf("<html><head>\n");
6789 r->rsprintf("<link rel=\"icon\" href=\"favicon.png\" type=\"image/png\" />\n");
6790 r->rsprintf("<link rel=\"stylesheet\" href=\"midas.css\" type=\"text/css\" />\n");
6791 r->rsprintf("<link rel=\"stylesheet\" href=\"mhttpd.css\" type=\"text/css\" />\n");
6792 r->rsprintf("<title>Enter password</title></head><body>\n\n");
6793
6794 r->rsprintf("<form method=\"GET\" action=\".\">\n\n");
6795
6796 /* define hidden fields for current experiment and destination */
6797 if (redir[0])
6798 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", redir);
6799
6800 /*---- page header ----*/
6801 r->rsprintf("<table class=\"headerTable\"><tr><td></td><tr></table>\n");
6802
6803 r->rsprintf("<table class=\"dialogTable\">\n"); //main table
6804
6805 if (password[0])
6806 r->rsprintf("<tr><th class=\"redLight\">Wrong password!</tr>\n");
6807
6808 r->rsprintf
6809 ("<tr><th>Please enter password to obtain write access</tr>\n");
6810 r->rsprintf("<tr><td align=center><input type=password name=wpwd></tr>\n");
6811 r->rsprintf("<tr><td align=center><input type=submit value=Submit></tr>");
6812
6813 r->rsprintf("</table>\n");
6814
6815 r->rsprintf("</div>\n"); // closing for <div id="mmain">
6816 r->rsprintf("</form>\n");
6817 r->rsprintf("</body></html>\r\n");
6818
6819 return FALSE;
6820 } else
6821 return TRUE;
6822}
6823
6824/*------------------------------------------------------------------*/
6825
6826void show_odb_page(Param* pp, Return* r, const char* dec_path, int write_access)
6827{
6828 int keyPresent, size, status, line, link_index;
6829 char colspan;
6830 char style[32];
6831 HNDLE hDB, hkey, hkeyroot;
6832 KEY key;
6833 DWORD delta;
6834
6836
6837 //printf("path [%s]\n", dec_path);
6838
6839 if (strcmp(dec_path, "root") == 0) {
6840 dec_path = "";
6841 }
6842
6843 char xdecpath[256];
6844 mstrlcpy(xdecpath, dec_path, sizeof(xdecpath));
6845 if (strrchr(xdecpath, '/'))
6846 mstrlcpy(xdecpath, strrchr(xdecpath, '/')+1, sizeof(xdecpath));
6847 if (xdecpath[0] == 0)
6848 mstrlcpy(xdecpath, "root", sizeof(xdecpath));
6849 show_header(r, "MIDAS online database", "", xdecpath, 0);
6850
6851 /* use javascript file */
6852 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
6853 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
6854 r->rsprintf("<script type=\"text/javascript\" src=\"obsolete.js\"></script>\n");
6855 r->rsprintf("<script type=\"text/javascript\" src=\"controls.js\"></script>\n");
6856
6857 /* find key via path */
6858 status = db_find_key(hDB, 0, dec_path, &hkeyroot);
6859 if (status != DB_SUCCESS) {
6860 r->rsprintf("Error: cannot find key %s<P>\n", dec_path);
6861 r->rsprintf("</body></html>\r\n");
6862 return;
6863 }
6864
6865 char xdec_path[MAX_ODB_PATH];
6866
6867 /* if key is not of type TID_KEY, cut off key name */
6868 db_get_key(hDB, hkeyroot, &key);
6869 if (key.type != TID_KEY) {
6870 mstrlcpy(xdec_path, dec_path, sizeof(xdec_path));
6871
6872 /* strip variable name from path */
6873 char* p = xdec_path + strlen(xdec_path) - 1;
6874 while (*p && *p != '/')
6875 *p-- = 0;
6876 if (*p == '/')
6877 *p = 0;
6878
6879 status = db_find_key(hDB, 0, xdec_path, &hkeyroot);
6880 if (status != DB_SUCCESS) {
6881 r->rsprintf("Error: cannot find key %s<P>\n", xdec_path);
6882 r->rsprintf("</body></html>\r\n");
6883 return;
6884 }
6885
6886 dec_path = xdec_path;
6887 }
6888
6889 //mstrlcpy(enc_path, dec_path, enc_path_size);
6890 //urlEncode(enc_path, enc_path_size);
6891
6892 std::string odbpath = db_get_path(hDB, hkeyroot);
6893
6894 /*---- navigation bar ----*/
6895
6896 colspan = 7;
6897
6898 if (elog_mode) {
6899 r->rsprintf("<table class=\"mtableheader\">\n");
6900 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6901 r->rsprintf("<input type=button value=ELog onclick=\"self.location=\'?cmd=Alarms\';\">\n");
6902 r->rsprintf("</td></tr></table>\n\n");
6903 } else
6904 show_navigation_bar(r, "ODB");
6905
6906 /*---- begin ODB directory table ----*/
6907
6908 r->rsprintf("<table class=\"mtable\" style=\"border-spacing:0px;\">\n");
6909 r->rsprintf("<tr><th colspan=%d class=\"mtableheader\">Online Database Browser</tr>\n", colspan);
6910 //buttons:
6911 if(!elog_mode){
6912 r->rsprintf("<tr><td colspan=%d>\n", colspan);
6913 r->rsprintf("<input type=button value=Find onclick=\"self.location=\'?cmd=Find\';\">\n");
6914 r->rsprintf("<input type=button value=Create onclick=\"dlgShow('dlgCreate')\">\n");
6915 r->rsprintf("<input type=button value=Link onclick=\"dlgShow('dlgLink')\">\n");
6916 r->rsprintf("<input type=button value=Delete onclick=\"dlgShow('dlgDelete')\">\n");
6917 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());
6918 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());
6919 r->rsprintf("<input type=button value=\"Show ODB clients\" onclick=\"self.location=\'?cmd=odb_scl\';\">\n");
6920 r->rsprintf("</td></tr>\n");
6921 }
6922
6923 /*---- Build the Delete dialog------------------------------------*/
6924
6925 std::string dd = "";
6926
6927 dd += "<!-- Demo dialog -->\n";
6928 dd += "<div id=\"dlgDelete\" class=\"dlgFrame\">\n";
6929 dd += "<div class=\"dlgTitlebar\">Delete ODB entry</div>\n";
6930 dd += "<div class=\"dlgPanel\">\n";
6931 dd += "<div id=odbpath>";
6932 dd += "\"";
6933 dd += MJsonNode::Encode(odbpath.c_str());
6934 dd += "\"";
6935 dd += "</div>\n";
6936 dd += "<div><br></div>\n";
6937
6938 dd += "<table class=\"dialogTable\">\n";
6939 dd += "<th colspan=2>Delete ODB entries:</th>\n";
6940
6941 std::vector<std::string> delete_list;
6942
6943 int count_delete = 0;
6944
6945 /*---- ODB display -----------------------------------------------*/
6946
6947 /* display root key */
6948 r->rsprintf("<tr><td colspan=%d class='ODBpath'><b>", colspan);
6949 r->rsprintf("<a href=\"?cmd=oldodb\">/</a> \n");
6950
6951 std::string enc_root_path;
6952
6953 /*---- display path ----*/
6954 {
6955 const char* p = dec_path;
6956 while (*p) {
6957 std::string pd;
6958 while (*p && *p != '/')
6959 pd += *p++;
6960
6961 enc_root_path += urlEncode(pd.c_str());
6962
6963 if (pd.length() > 0)
6964 r->rsprintf("<a href=\"?cmd=oldodb&odb_path=%s\">%s</a>\n / ", enc_root_path.c_str(), pd.c_str());
6965
6966 enc_root_path += "/";
6967 if (*p == '/')
6968 p++;
6969 }
6970 }
6971
6972 r->rsprintf("</b></tr>\n");
6973
6974 /* enumerate subkeys */
6975 keyPresent = 0;
6976 for(int scan=0; scan<2; scan++){
6977 if(scan==1 && keyPresent==1) {
6978 r->rsprintf("<tr class=\"titleRow\">\n");
6979 r->rsprintf("<th class=\"ODBkey\">Key</th>\n");
6980 r->rsprintf("<th class=\"ODBvalue\">Value&nbsp;");
6981 r->rsprintf("<script type=\"text/javascript\">\n");
6982 r->rsprintf("function expand()\n");
6983 r->rsprintf("{\n");
6984 r->rsprintf(" var n = document.getElementsByName('ext');\n");
6985 r->rsprintf(" for (i=0 ; i<n.length ; i++) {\n");
6986 r->rsprintf(" if (n[i].style.display == 'none')\n");
6987 r->rsprintf(" n[i].style.display = 'table-cell';\n");
6988 r->rsprintf(" else\n");
6989 r->rsprintf(" n[i].style.display = 'none';\n");
6990 r->rsprintf(" }\n");
6991 r->rsprintf(" if (document.getElementById('expp').expflag === true) {\n");
6992 r->rsprintf(" document.getElementById('expp').expflag = false;\n");
6993 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E5;';\n");
6994 r->rsprintf(" } else {\n");
6995 r->rsprintf(" document.getElementById('expp').expflag = true;\n");
6996 r->rsprintf(" document.getElementById('expp').innerHTML = '&#x21E4;';\n");
6997 r->rsprintf(" }\n");
6998 r->rsprintf("}\n");
6999 r->rsprintf("</script>");
7000 r->rsprintf("<div style=\"display:inline;float:right\"><a id=\"expp\"href=\"#\" onClick=\"expand();return false;\">&#x21E5;</div>");
7001 r->rsprintf("</th>\n");
7002 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Type</th>\n");
7003 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">#Val</th>\n");
7004 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Size</th>\n");
7005 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Written</th>\n");
7006 r->rsprintf("<th class=\"ODBvalue\" name=\"ext\" style=\"display:none\">Mode</th>\n");
7007 r->rsprintf("</tr>\n");
7008 }
7009 line = 0;
7010 for (int i = 0;; i++) {
7011 db_enum_link(hDB, hkeyroot, i, &hkey);
7012 if (!hkey)
7013 break;
7014 db_get_link(hDB, hkey, &key);
7015
7016 if (scan == 0) {
7017 delete_list.push_back(key.name);
7018 }
7019
7020 if (line % 2 == 0)
7021 mstrlcpy(style, "ODBtableEven", sizeof(style));
7022 else
7023 mstrlcpy(style, "ODBtableOdd", sizeof(style));
7024
7025 std::string keyname = key.name;
7026 std::string enc_keyname = urlEncode(key.name);
7027
7028 std::string enc_full_path = enc_root_path + enc_keyname;
7029
7030 std::string odb_path = dec_path;
7031 if (odb_path.length() > 0 && odb_path[odb_path.length() - 1] != '/')
7032 odb_path += "/";
7033 odb_path += key.name;
7034
7035 /* resolve links */
7036 std::string enc_link_ref;
7037 char link_name[MAX_ODB_PATH];
7038 link_name[0] = 0;
7040 if (key.type == TID_LINK) {
7041 size = sizeof(link_name);
7042 db_get_link_data(hDB, hkey, link_name, &size, TID_LINK);
7043
7044 status = db_find_key(hDB, 0, link_name, &hkey);
7045
7046 if (status == DB_SUCCESS)
7047 db_get_key(hDB, hkey, &key);
7048
7049 //sprintf(link_ref, "?cmd=Set&odb_path=%s", full_path);
7050 enc_link_ref = "?cmd=Set&odb_path=";
7051 enc_link_ref += enc_full_path;
7052
7053 if (status == DB_SUCCESS && link_name[0] == 0) {
7054 // fake the case when an empty link somehow resolves
7055 sprintf(link_name, "%s", "(empty)");
7056 }
7057 }
7058
7059 std::string enc_ref;
7060
7061 if (link_name[0]) {
7062 if (enc_root_path.back() == '/' && link_name[0] == '/') {
7063 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name+1);
7064 enc_ref = "";
7065 enc_ref += "?cmd=Set&odb_path=";
7066 enc_ref += enc_root_path;
7067 enc_ref += urlEncode(link_name + 1);
7068 } else {
7069 //sprintf(ref, "?cmd=Set&odb_path=%s%s", root_path, link_name);
7070 enc_ref = "";
7071 enc_ref += "?cmd=Set&odb_path=";
7072 enc_ref += enc_root_path;
7073 enc_ref += urlEncode(link_name);
7074 }
7075 } else {
7076 //sprintf(ref, "?cmd=Set&odb_path=%s", full_path);
7077 enc_ref = "";
7078 enc_ref += "?cmd=Set&odb_path=";
7079 enc_ref += enc_full_path;
7080 }
7081
7082 if (status != DB_SUCCESS) {
7083 if (scan == 1) {
7084 r->rsprintf("<tr><td class=\"yellowLight\">");
7085 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)");
7086 }
7087 } else {
7088
7089 if (key.type == TID_KEY && scan == 0) {
7090 /* for keys, don't display data value */
7091 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());
7092 if (link_name[0])
7093 r->rsprintf("<i>&rarr; <a href=\"%s\">%s</a></i>", enc_link_ref.c_str(), link_name);
7094 r->rsprintf("</tr>\n");
7095 } else if(key.type != TID_KEY && scan == 1) {
7096
7097 if (strchr(link_name, '['))
7098 link_index = atoi(strchr(link_name, '[')+1);
7099 else
7100 link_index = -1;
7101
7102 /* display single value */
7103 if (key.num_values == 1 || link_index != -1) {
7104 char data[TEXT_SIZE];
7105 size = sizeof(data);
7106 db_get_data(hDB, hkey, data, &size, key.type);
7107
7108 std::string data_str;
7109
7110 if (link_index != -1)
7111 data_str = db_sprintf(data, key.item_size, link_index, key.type);
7112 else
7113 data_str = db_sprintf(data, key.item_size, 0, key.type);
7114
7115 if (key.type == TID_STRING) {
7116 if (size == sizeof(data)) {
7117 data_str += "...(truncated)";
7118 }
7119 }
7120
7121 std::string hex_str;
7122
7123 if (key.type != TID_STRING) {
7124 if (link_index != -1)
7125 hex_str = db_sprintfh(data, key.item_size, link_index, key.type);
7126 else
7127 hex_str = db_sprintfh(data, key.item_size, 0, key.type);
7128 }
7129
7130 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7131 data_str = "(empty)";
7132 hex_str = "";
7133 }
7134
7135 r->rsprintf("<tr>\n");
7136 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0]) {
7137 if (link_name[0]) {
7138 r->rsprintf("<td class=\"ODBkey\">\n");
7139 r->rsprintf("%s <i>&rarr; ", keyname.c_str());
7140 r->rsprintf("<a href=\"%s\">%s</a></i>\n", enc_link_ref.c_str(), link_name);
7141 r->rsprintf("<td class=\"%s\">\n", style);
7142 if (!write_access)
7143 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7144 else {
7145 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7146 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7147 }
7148 } else {
7149 r->rsprintf("<td class=\"ODBkey\">\n");
7150 r->rsprintf("%s<td class=\"%s\">", keyname.c_str(), style);
7151 if (!write_access)
7152 r->rsprintf("%s (%s)", data_str.c_str(), hex_str.c_str());
7153 else {
7154 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7155 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">%s (%s)</a>\n", odb_path.c_str(), data_str.c_str(), hex_str.c_str());
7156 }
7157 }
7158 } else {
7159 if (strchr(data_str.c_str(), '\n')) {
7160 if (link_name[0]) {
7161 r->rsprintf("<td class=\"ODBkey\">");
7162 r->rsprintf("%s <i>&rarr; <a href=\"%s\">%s</a></i><td class=\"ODBvalue\">", keyname.c_str(), enc_link_ref.c_str(), link_name);
7163 } else
7164 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7165 r->rsprintf("\n<pre>");
7166 strencode3(r, data_str.c_str());
7167 r->rsprintf("</pre>");
7168 if (strlen(data) > data_str.length())
7169 r->rsprintf("<i>... (%d bytes total)<p>\n", (int)strlen(data));
7170
7171 r->rsprintf("<a href=\"%s\">Edit</a>\n", enc_ref.c_str());
7172 } else {
7173 if (link_name[0]) {
7174 r->rsprintf("<td class=\"ODBkey\">\n");
7175 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);
7176 if (!write_access)
7177 strencode(r, data_str.c_str());
7178 else {
7179 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7180 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7181 strencode(r, data_str.c_str());
7182 r->rsprintf("</a>\n");
7183 }
7184 } else {
7185 r->rsprintf("<td class=\"ODBkey\">%s<td class=\"%s\">", keyname.c_str(), style);
7186 if (!write_access) {
7187 strencode(r, data_str.c_str());
7188 } else {
7189 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), odb_path.c_str());
7190 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", odb_path.c_str());
7191 strencode(r, data_str.c_str());
7192 r->rsprintf("</a>\n");
7193 }
7194 }
7195 }
7196 }
7197
7198 /* extended key information */
7199 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7200 r->rsprintf("%s", rpc_tid_name(key.type));
7201 r->rsprintf("</td>\n");
7202
7203 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7204 r->rsprintf("%d", key.num_values);
7205 r->rsprintf("</td>\n");
7206
7207 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7208 r->rsprintf("%d", key.item_size);
7209 r->rsprintf("</td>\n");
7210
7211 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7212 db_get_key_time(hDB, hkey, &delta);
7213 if (delta < 60)
7214 r->rsprintf("%ds", delta);
7215 else if (delta < 3600)
7216 r->rsprintf("%1.0lfm", delta / 60.0);
7217 else if (delta < 86400)
7218 r->rsprintf("%1.0lfh", delta / 3600.0);
7219 else if (delta < 86400 * 99)
7220 r->rsprintf("%1.0lfd", delta / 86400.0);
7221 else
7222 r->rsprintf(">99d");
7223 r->rsprintf("</td>\n");
7224
7225 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\">");
7227 r->rsprintf("R");
7229 r->rsprintf("W");
7231 r->rsprintf("D");
7233 r->rsprintf("E");
7234 r->rsprintf("</td>\n");
7235
7236 line++;
7237 r->rsprintf("</tr>\n");
7238 } else { /* display array value */
7239 /* check for exceeding length */
7240 if (key.num_values > 1000 && !pp->isparam("all"))
7241 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);
7242 else {
7243 /* display first value */
7244 if (link_name[0])
7245 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);
7246 else
7247 r->rsprintf("<tr><td class=\"ODBkey\" rowspan=%d>%s\n", key.num_values, keyname.c_str());
7248
7249 for (int j = 0; j < key.num_values; j++) {
7250 if (line % 2 == 0)
7251 mstrlcpy(style, "ODBtableEven", sizeof(style));
7252 else
7253 mstrlcpy(style, "ODBtableOdd", sizeof(style));
7254
7255 char data[TEXT_SIZE];
7256 size = sizeof(data);
7257 db_get_data_index(hDB, hkey, data, &size, j, key.type);
7258 std::string data_str = db_sprintf(data, key.item_size, 0, key.type);
7259
7260 std::string hex_str;
7261 if (key.type == TID_STRING || key.type == TID_LINK) {
7262 hex_str = "";
7263 } else {
7264 hex_str = db_sprintfh(data, key.item_size, 0, key.type);
7265 }
7266
7267 if (key.type == TID_STRING) {
7268 if (size == sizeof(data)) {
7269 data_str += "...(truncated)";
7270 }
7271 }
7272
7273 if (data_str.empty() || equal_ustring(data_str.c_str(), "<NULL>")) {
7274 data_str = "(empty)";
7275 hex_str = "";
7276 }
7277
7278 //sprintf(ref, "?cmd=Set&odb_path=%s&index=%d", full_path, j);
7279 enc_ref = "";
7280 enc_ref += "?cmd=Set&odb_path=";
7281 enc_ref += enc_full_path;
7282 enc_ref += "&index=";
7283 enc_ref += toString(j);
7284
7285 std::string tmpstr;
7286 //sprintf(str, "%s[%d]", odb_path, j);
7287 tmpstr += odb_path;
7288 tmpstr += "[";
7289 tmpstr += toString(j);
7290 tmpstr += "]";
7291
7292 if (j > 0)
7293 r->rsprintf("<tr>");
7294
7295 r->rsprintf("<td class=\"%s\">[%d]&nbsp;", style, j);
7296 if (!write_access)
7297 r->rsprintf("<a href=\"%s\">", enc_ref.c_str());
7298 else {
7299 r->rsprintf("<a href=\"%s\" onClick=\"ODBInlineEdit(this.parentNode,\'%s\');return false;\" ", enc_ref.c_str(), tmpstr.c_str());
7300 r->rsprintf("onFocus=\"ODBInlineEdit(this.parentNode,\'%s\');\">", tmpstr.c_str());
7301 }
7302 if (strcmp(data_str.c_str(), hex_str.c_str()) != 0 && hex_str[0])
7303 r->rsprintf("%s (%s)</a>\n", data_str.c_str(), hex_str.c_str());
7304 else
7305 r->rsprintf("%s</a>\n", data_str.c_str());
7306
7307 if (j == 0) {
7308 /* extended key information */
7309 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7310 r->rsprintf("%s", rpc_tid_name(key.type));
7311 r->rsprintf("</td>\n");
7312
7313 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7314 r->rsprintf("%d", key.num_values);
7315 r->rsprintf("</td>\n");
7316
7317 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7318 r->rsprintf("%d", key.item_size);
7319 r->rsprintf("</td>\n");
7320
7321 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7322 db_get_key_time(hDB, hkey, &delta);
7323 if (delta < 60)
7324 r->rsprintf("%ds", delta);
7325 else if (delta < 3600)
7326 r->rsprintf("%1.0lfm", delta / 60.0);
7327 else if (delta < 86400)
7328 r->rsprintf("%1.0lfh", delta / 3600.0);
7329 else if (delta < 86400 * 99)
7330 r->rsprintf("%1.0lfh", delta / 86400.0);
7331 else
7332 r->rsprintf(">99d");
7333 r->rsprintf("</td>\n");
7334
7335 r->rsprintf("<td class=\"ODBkey\" name=\"ext\" style=\"display:none\" rowspan=%d>", key.num_values);
7337 r->rsprintf("R");
7339 r->rsprintf("W");
7341 r->rsprintf("D");
7343 r->rsprintf("E");
7344 r->rsprintf("</td>\n");
7345 }
7346 line++;
7347 }
7348
7349 r->rsprintf("</tr>\n");
7350 }
7351 }
7352 } else if(key.type != TID_KEY){
7353 keyPresent = 1; //flag that we've seen a key on the first pass, and should therefore write the Key / Value headline
7354 }
7355 }
7356 }
7357 }
7358 r->rsprintf("</table>\n");
7359 r->rsprintf("</div>\n"); // <div id="mmain">
7360
7361 /*---- Build the Delete dialog------------------------------------*/
7362
7363 std::sort(delete_list.begin(), delete_list.end());
7364
7365 for (unsigned i=0; i<delete_list.size(); i++) {
7366 std::string name = delete_list[i];
7367
7368 dd += "<tr><td style=\"text-align:left;\" align=left><input align=left type=checkbox id=delete";
7369 dd += toString(count_delete++);
7370 dd += " value=\'";
7371 dd += "\"";
7372 dd += MJsonNode::Encode(name.c_str());
7373 dd += "\"";
7374 dd += "\'>";
7375 dd += name;
7376 dd += "</input></td></tr>\n";
7377 }
7378
7379 dd += "</table>\n";
7380 dd += "<input type=button value=Delete onClick='mhttpd_delete_page_handle_delete(event);'>\n";
7381 dd += "<input type=button value=Cancel onClick='mhttpd_delete_page_handle_cancel(event);'>\n";
7382 dd += "</div>\n";
7383 dd += "</div>\n";
7384
7385 r->rsputs(dd.c_str());
7386
7387 /*---- Build the Create dialog------------------------------------*/
7388
7389 std::string cd = "";
7390
7391 cd += "<!-- Demo dialog -->\n";
7392 cd += "<div id=\"dlgCreate\" class=\"dlgFrame\">\n";
7393 cd += "<div class=\"dlgTitlebar\">Create ODB entry</div>\n";
7394 cd += "<div class=\"dlgPanel\">\n";
7395 cd += "<br />\n";
7396 cd += "<div id=odbpath>";
7397 cd += "\"";
7398 cd += MJsonNode::Encode(odbpath.c_str());
7399 cd += "\"";
7400 cd += "</div>\n";
7401 cd += "<div><br></div>\n";
7402
7403 cd += "<table class=\"dialogTable\">\n";
7404 cd += "<th colspan=2>Create ODB entry:</th>\n";
7405 cd += "<tr>";
7406 cd += "<td>Type";
7407 cd += "<td>";
7408 cd += "<select type=text size=1 id=create_tid name=type>";
7409 cd += "<option value=7>Integer (32-bit)";
7410 cd += "<option value=9>Float (4 Bytes)";
7411 cd += "<option value=12>String";
7412 cd += "<option selected value=15>Subdirectory";
7413 cd += "<option value=1>Byte";
7414 cd += "<option value=2>Signed byte";
7415 cd += "<option value=3>Character (8-bit)";
7416 cd += "<option value=4>Word (16-bit)";
7417 cd += "<option value=5>Short integer (16-bit)";
7418 cd += "<option value=6>Double Word (32-bit)";
7419 cd += "<option value=8>Boolean";
7420 cd += "<option value=10>Double float (8 Bytes)";
7421 //cd += "<option value=16>Symbolic link";
7422 cd += "</select>";
7423 cd += "</tr>\n";
7424 cd += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=create_name name=value></tr>\n";
7425 cd += "<tr><td>Array size<td><input type=text size=31 maxlength=31 id=create_array_length name=index value=1></tr>\n";
7426 cd += "<tr><td>String length<td><input type=text size=31 maxlength=31 id=create_strlen name=strlen value=32></tr>\n";
7427 cd += "</table>\n";
7428 cd += "<input type=button value=Create onClick='mhttpd_create_page_handle_create(event);'>\n";
7429 cd += "<input type=button value=Cancel onClick='mhttpd_create_page_handle_cancel(event);'>\n";
7430 cd += "</div>\n";
7431 cd += "</div>\n";
7432
7433 r->rsputs(cd.c_str());
7434
7435 /*---- Build the Link dialog------------------------------------*/
7436
7437 std::string ld = "";
7438
7439 ld += "<!-- Demo dialog -->\n";
7440 ld += "<div id=\"dlgLink\" class=\"dlgFrame\">\n";
7441 ld += "<div class=\"dlgTitlebar\">Create a link to an ODB entry</div>\n";
7442 ld += "<div class=\"dlgPanel\">\n";
7443 ld += "<br />\n";
7444 ld += "<div id=link_odbpath>";
7445 ld += "\"";
7446 ld += MJsonNode::Encode(odbpath.c_str());
7447 ld += "\"";
7448 ld += "</div>\n";
7449 ld += "<div><br></div>\n";
7450
7451 ld += "<table class=\"dialogTable\">\n";
7452 ld += "<th colspan=2>Create a link to an ODB entry:</th>\n";
7453 ld += "<tr><td>Name<td><input type=text size=31 maxlength=31 id=link_name name=value></tr>\n";
7454 ld += "<tr><td>Link target<td><input type=text size=31 maxlength=256 id=link_target name=target></tr>\n";
7455 ld += "</table>\n";
7456 ld += "<input type=button value=Link onClick='mhttpd_link_page_handle_link(event);'>\n";
7457 ld += "<input type=button value=Cancel onClick='mhttpd_link_page_handle_cancel(event);'>\n";
7458 ld += "</div>\n";
7459 ld += "</div>\n";
7460
7461 r->rsputs(ld.c_str());
7462}
7463
7464/*------------------------------------------------------------------*/
7465
7467 const char *group,
7468 int index, const char *value)
7469{
7470 int status, size;
7471 HNDLE hDB, hkey;
7472 KEY key;
7473 char data[TEXT_SIZE];
7474
7475 std::string odb_path = pp->getparam("odb_path");
7476
7477 //printf("show_set_page: odb_path [%s] group [%s] index %d value [%s]\n", odb_path.c_str(), group, index, value);
7478
7480
7481 /* show set page if no value is given */
7482 if (!pp->isparam("value") && !*pp->getparam("text")) {
7483 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7484 if (status != DB_SUCCESS) {
7485 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7486 return;
7487 }
7488 db_get_link(hDB, hkey, &key);
7489
7490 show_header(r, "Set value", "POST", "", 0);
7491 //close header:
7492 r->rsprintf("</table>");
7493
7494 //main table:
7495 r->rsprintf("<table class=\"dialogTable\">");
7496
7497 if (index > 0)
7498 r->rsprintf("<input type=hidden name=index value=\"%d\">\n", index);
7499 else
7500 index = 0;
7501
7502 if (group[0])
7503 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", group);
7504
7505 r->rsprintf("<input type=hidden name=odb_path value=\"%s\">\n", odb_path.c_str());
7506
7507 std::string data_str1 = rpc_tid_name(key.type);
7508 std::string str1;
7509 if (key.num_values > 1) {
7510 data_str1 += msprintf("[%d]", key.num_values);
7511 str1 = msprintf("%s[%d]", odb_path.c_str(), index);
7512 } else
7513 str1 = odb_path.c_str();
7514
7515 r->rsprintf("<tr><th colspan=2>Set new value - type = %s</tr>\n", data_str1.c_str());
7516 r->rsprintf("<tr><td>%s<td>\n", str1.c_str());
7517
7518 /* set current value as default */
7519 size = sizeof(data);
7520 db_get_link_data(hDB, hkey, data, &size, key.type);
7521 std::string data_str = db_sprintf(data, key.item_size, index, key.type);
7522
7523 if (equal_ustring(data_str.c_str(), "<NULL>"))
7524 data_str = "";
7525
7526 if (strchr(data_str.c_str(), '\n') != NULL) {
7527 r->rsprintf("<textarea rows=20 cols=80 name=\"text\">\n");
7528 strencode3(r, data);
7529 r->rsprintf("</textarea>\n");
7530 } else {
7531 size = 20;
7532 if ((int) data_str.length() > size)
7533 size = data_str.length() + 3;
7534 if (size > 80)
7535 size = 80;
7536
7537 r->rsprintf("<input type=\"text\" size=%d maxlength=256 name=\"value\" value=\"", size);
7538 strencode(r, data_str.c_str());
7539 r->rsprintf("\">\n");
7540 }
7541
7542 r->rsprintf("</tr>\n");
7543
7544 r->rsprintf("<tr><td align=center colspan=2>");
7545 r->rsprintf("<input type=submit name=cmd value=Set>");
7546 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7547 r->rsprintf("</tr>");
7548 r->rsprintf("</table>");
7549
7550 r->rsprintf("<input type=hidden name=cmd value=Set>\n");
7551
7552 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7553 r->rsprintf("</form>\n");
7554 r->rsprintf("</body></html>\r\n");
7555 return;
7556 } else {
7557 /* set value */
7558
7559 status = db_find_link(hDB, 0, odb_path.c_str(), &hkey);
7560 if (status != DB_SUCCESS) {
7561 r->rsprintf("Error: cannot find key %s<P>\n", odb_path.c_str());
7562 return;
7563 }
7564 db_get_link(hDB, hkey, &key);
7565
7566 memset(data, 0, sizeof(data));
7567
7568 if (pp->getparam("text") && *pp->getparam("text"))
7569 mstrlcpy(data, pp->getparam("text"), sizeof(data));
7570 else
7571 db_sscanf(value, data, &size, 0, key.type);
7572
7573 if (index < 0)
7574 index = 0;
7575
7576 /* extend data size for single string if necessary */
7577 if ((key.type == TID_STRING || key.type == TID_LINK)
7578 && (int) strlen(data) + 1 > key.item_size && key.num_values == 1)
7579 key.item_size = strlen(data) + 1;
7580
7581 if (key.item_size == 0)
7583
7584 if (key.num_values > 1)
7586 else
7588
7589 if (status == DB_NO_ACCESS)
7590 r->rsprintf("<h2>Write access not allowed</h2>\n");
7591
7592 redirect(r, "");
7593
7594 return;
7595 }
7596}
7597
7598/*------------------------------------------------------------------*/
7599
7600void show_find_page(Return* r, const char *value)
7601{
7602 HNDLE hDB, hkey;
7603
7605
7606 if (value[0] == 0) {
7607 /* without value, show find dialog */
7608 show_header(r, "Find value", "GET", "", 0);
7609
7610 //end header:
7611 r->rsprintf("</table>");
7612
7613 //find dialog:
7614 r->rsprintf("<table class=\"dialogTable\">");
7615
7616 r->rsprintf("<tr><th colspan=2>Find string in Online Database</tr>\n");
7617 r->rsprintf("<tr><td>Enter substring (case insensitive)\n");
7618
7619 r->rsprintf("<td><input type=\"text\" size=\"20\" maxlength=\"80\" name=\"value\">\n");
7620 r->rsprintf("</tr>");
7621
7622 r->rsprintf("<tr><td align=center colspan=2>");
7623 r->rsprintf("<input type=submit name=cmd value=Find>");
7624 r->rsprintf("<input type=submit name=cmd value=Cancel>");
7625 r->rsprintf("</tr>");
7626 r->rsprintf("</table>");
7627
7628 r->rsprintf("<input type=hidden name=cmd value=Find>");
7629
7630 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7631 r->rsprintf("</form>\n");
7632 r->rsprintf("</body></html>\r\n");
7633 } else {
7634 show_header(r, "Search results", "GET", "", 0);
7635
7636 r->rsprintf("<table class=\"mtable\">\n");
7637 r->rsprintf("<tr><th colspan=2 class=\"mtableheader\">");
7638 r->rsprintf("Results of search for substring \"%s\"</tr>\n", value);
7639 r->rsprintf("<tr><th class=\"titlerow\">Key<th>Value</tr>\n");
7640
7641 /* start from root */
7642 db_find_key(hDB, 0, "", &hkey);
7643 assert(hkey);
7644
7645 /* scan tree, call "search_callback" for each key */
7647 data.r = r;
7648 data.search_name = value;
7649
7650 db_scan_tree(hDB, hkey, 0, search_callback, (void *)&data);
7651
7652 r->rsprintf("</table>");
7653 r->rsprintf("</div>\n"); // closing for <div id="mmain">
7654 r->rsprintf("</form>\n");
7655 r->rsprintf("</body></html>\r\n");
7656 }
7657}
7658
7659/*------------------------------------------------------------------*/
7660
7661#define LN10 2.302585094
7662#define LOG2 0.301029996
7663#define LOG5 0.698970005
7664
7665void haxis(gdImagePtr im, gdFont * font, int col, int gcol,
7666 int x1, int y1, int width,
7667 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7668{
7669 double dx, int_dx, frac_dx, x_act, label_dx, major_dx, x_screen, maxwidth;
7670 int tick_base, major_base, label_base, n_sig1, n_sig2, xs;
7671 char str[80];
7672 double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7673
7674 if (xmax <= xmin || width <= 0)
7675 return;
7676
7677 /* use 5 as min tick distance */
7678 dx = (xmax - xmin) / (double) (width / 5);
7679
7680 frac_dx = modf(log(dx) / LN10, &int_dx);
7681 if (frac_dx < 0) {
7682 frac_dx += 1;
7683 int_dx -= 1;
7684 }
7685
7686 tick_base = frac_dx < LOG2 ? 1 : frac_dx < LOG5 ? 2 : 3;
7687 major_base = label_base = tick_base + 1;
7688
7689 /* rounding up of dx, label_dx */
7690 dx = pow(10, int_dx) * base[tick_base];
7691 major_dx = pow(10, int_dx) * base[major_base];
7692 label_dx = major_dx;
7693
7694 /* number of significant digits */
7695 if (xmin == 0)
7696 n_sig1 = 0;
7697 else
7698 n_sig1 = (int) floor(log(fabs(xmin)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7699
7700 if (xmax == 0)
7701 n_sig2 = 0;
7702 else
7703 n_sig2 =
7704 (int) floor(log(fabs(xmax)) / LN10) - (int) floor(log(fabs(label_dx)) / LN10) + 1;
7705
7706 n_sig1 = MAX(n_sig1, n_sig2);
7707 n_sig1 = MAX(n_sig1, 4);
7708
7709 /* determination of maximal width of labels */
7710 sprintf(str, "%1.*lG", n_sig1, floor(xmin / dx) * dx);
7711 maxwidth = font->h / 2 * strlen(str);
7712 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx);
7713 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7714 sprintf(str, "%1.*lG", n_sig1, floor(xmax / dx) * dx + label_dx);
7715 maxwidth = MAX(maxwidth, font->h / 2 * strlen(str));
7716
7717 /* increasing label_dx, if labels would overlap */
7718 while (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7719 label_base++;
7720 label_dx = pow(10, int_dx) * base[label_base];
7721 if (label_base % 3 == 2 && major_base % 3 == 1) {
7722 major_base++;
7723 major_dx = pow(10, int_dx) * base[major_base];
7724 }
7725 }
7726
7727 x_act = floor(xmin / dx) * dx;
7728
7729 gdImageLine(im, x1, y1, x1 + width, y1, col);
7730
7731 do {
7732 x_screen = (x_act - xmin) / (xmax - xmin) * width + x1;
7733 xs = (int) (x_screen + 0.5);
7734
7735 if (x_screen > x1 + width + 0.001)
7736 break;
7737
7738 if (x_screen >= x1) {
7739 if (fabs(floor(x_act / major_dx + 0.5) - x_act / major_dx) <
7740 dx / major_dx / 10.0) {
7741
7742 if (fabs(floor(x_act / label_dx + 0.5) - x_act / label_dx) <
7743 dx / label_dx / 10.0) {
7744 /* label tick mark */
7745 gdImageLine(im, xs, y1, xs, y1 + text, col);
7746
7747 /* grid line */
7748 if (grid != 0 && xs > x1 && xs < x1 + width)
7749 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7750
7751 /* label */
7752 if (label != 0) {
7753 sprintf(str, "%1.*lG", n_sig1, x_act);
7754 gdImageString(im, font, (int) xs - font->w * strlen(str) / 2,
7755 y1 + label, str, col);
7756 }
7757 } else {
7758 /* major tick mark */
7759 gdImageLine(im, xs, y1, xs, y1 + major, col);
7760
7761 /* grid line */
7762 if (grid != 0 && xs > x1 && xs < x1 + width)
7763 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7764 }
7765
7766 } else
7767 /* minor tick mark */
7768 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7769
7770 }
7771
7772 x_act += dx;
7773
7774 /* supress 1.23E-17 ... */
7775 if (fabs(x_act) < dx / 100)
7776 x_act = 0;
7777
7778 } while (1);
7779}
7780
7781/*------------------------------------------------------------------*/
7782
7783void sec_to_label(char *result, int sec, int base, int force_date)
7784{
7785 char mon[80];
7786 time_t t_sec;
7787
7788 t_sec = (time_t) sec;
7789
7790 struct tm tms;
7791 localtime_r(&t_sec, &tms);
7792 strcpy(mon, mname[tms.tm_mon]);
7793 mon[3] = 0;
7794
7795 if (force_date) {
7796 if (base < 600)
7797 sprintf(result, "%02d %s %02d %02d:%02d:%02d",
7798 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min,
7799 tms.tm_sec);
7800 else if (base < 3600 * 24)
7801 sprintf(result, "%02d %s %02d %02d:%02d",
7802 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7803 else
7804 sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7805 } else {
7806 if (base < 600)
7807 sprintf(result, "%02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec);
7808 else if (base < 3600 * 3)
7809 sprintf(result, "%02d:%02d", tms.tm_hour, tms.tm_min);
7810 else if (base < 3600 * 24)
7811 sprintf(result, "%02d %s %02d %02d:%02d",
7812 tms.tm_mday, mon, tms.tm_year % 100, tms.tm_hour, tms.tm_min);
7813 else
7814 sprintf(result, "%02d %s %02d", tms.tm_mday, mon, tms.tm_year % 100);
7815 }
7816}
7817
7818void taxis(gdImagePtr im, gdFont * font, int col, int gcol,
7819 int x1, int y1, int width, int xr,
7820 int minor, int major, int text, int label, int grid, double xmin, double xmax)
7821{
7822 int dx, x_act, label_dx, major_dx, x_screen, maxwidth;
7823 int tick_base, major_base, label_base, xs, xl;
7824 char str[80];
7825 const int base[] = { 1, 5, 10, 60, 300, 600, 1800, 3600, 3600 * 6, 3600 * 12, 3600 * 24, 0 };
7826 time_t ltime;
7827 int force_date, d1, d2;
7828 struct tm tms;
7829
7830 if (xmax <= xmin || width <= 0)
7831 return;
7832
7833 /* force date display if xmax not today */
7834 ltime = ss_time();
7835 localtime_r(&ltime, &tms);
7836 d1 = tms.tm_mday;
7837 ltime = (time_t) xmax;
7838 localtime_r(&ltime, &tms);
7839 d2 = tms.tm_mday;
7840 force_date = (d1 != d2);
7841
7842 /* use 5 pixel as min tick distance */
7843 dx = (int) ((xmax - xmin) / (double) (width / 5) + 0.5);
7844
7845 for (tick_base = 0; base[tick_base]; tick_base++) {
7846 if (base[tick_base] > dx)
7847 break;
7848 }
7849 if (!base[tick_base])
7850 tick_base--;
7851 dx = base[tick_base];
7852
7853 if (base[tick_base + 1])
7854 major_base = tick_base + 1;
7855 else
7856 major_base = tick_base;
7857 major_dx = base[major_base];
7858
7859 if (base[major_base + 1])
7860 label_base = major_base + 1;
7861 else
7862 label_base = major_base;
7863 label_dx = base[label_base];
7864
7865 do {
7866 sec_to_label(str, (int) (xmin + 0.5), label_dx, force_date);
7867 maxwidth = font->h / 2 * strlen(str);
7868
7869 /* increasing label_dx, if labels would overlap */
7870 if (maxwidth > 0.7 * label_dx / (xmax - xmin) * width) {
7871 if (base[label_base + 1])
7872 label_dx = base[++label_base];
7873 else
7874 label_dx += 3600 * 24;
7875 } else
7876 break;
7877 } while (1);
7878
7879 x_act =
7880 (int) floor((double) (xmin - ss_timezone()) / label_dx) * label_dx + ss_timezone();
7881
7882 gdImageLine(im, x1, y1, x1 + width, y1, col);
7883
7884 do {
7885 x_screen = (int) ((x_act - xmin) / (xmax - xmin) * width + x1 + 0.5);
7886 xs = (int) (x_screen + 0.5);
7887
7888 if (x_screen > x1 + width + 0.001)
7889 break;
7890
7891 if (x_screen >= x1) {
7892 if ((x_act - ss_timezone()) % major_dx == 0) {
7893 if ((x_act - ss_timezone()) % label_dx == 0) {
7894 /* label tick mark */
7895 gdImageLine(im, xs, y1, xs, y1 + text, col);
7896
7897 /* grid line */
7898 if (grid != 0 && xs > x1 && xs < x1 + width)
7899 gdImageLine(im, xs, y1, xs, y1 + grid, col);
7900
7901 /* label */
7902 if (label != 0) {
7903 sec_to_label(str, x_act, label_dx, force_date);
7904
7905 /* if labels at edge, shift them in */
7906 xl = (int) xs - font->w * strlen(str) / 2;
7907 if (xl < 0)
7908 xl = 0;
7909 if (xl + font->w * (int) strlen(str) > xr)
7910 xl = xr - font->w * strlen(str);
7911 gdImageString(im, font, xl, y1 + label, str, col);
7912 }
7913 } else {
7914 /* major tick mark */
7915 gdImageLine(im, xs, y1, xs, y1 + major, col);
7916
7917 /* grid line */
7918 if (grid != 0 && xs > x1 && xs < x1 + width)
7919 gdImageLine(im, xs, y1 - 1, xs, y1 + grid, gcol);
7920 }
7921
7922 } else
7923 /* minor tick mark */
7924 gdImageLine(im, xs, y1, xs, y1 + minor, col);
7925
7926 }
7927
7928 x_act += dx;
7929
7930 /* supress 1.23E-17 ... */
7931 if (fabs((double)x_act) < dx / 100)
7932 x_act = 0;
7933
7934 } while (1);
7935}
7936
7937/*------------------------------------------------------------------*/
7938
7939int vaxis(gdImagePtr im, gdFont * font, int col, int gcol,
7940 int x1, int y1, int width,
7941 int minor, int major, int text, int label, int grid, double ymin, double ymax,
7942 BOOL logaxis)
7943{
7944 double dy, int_dy, frac_dy, y_act, label_dy, major_dy, y_screen, y_next;
7945 int tick_base, major_base, label_base, n_sig1, n_sig2, ys, max_width;
7946 int last_label_y;
7947 char str[80];
7948 const double base[] = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
7949
7950 if (ymax <= ymin || width <= 0)
7951 return 0;
7952
7953 // 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
7954 if (fabs(ymax - ymin) <= 1e-10)
7955 return 0;
7956
7957 if (logaxis) {
7958 dy = pow(10, floor(log(ymin) / LN10));
7959 label_dy = dy;
7960 major_dy = dy * 10;
7961 n_sig1 = 4;
7962 } else {
7963 dy = (ymax - ymin) / (double) (width / 5);
7964
7965 frac_dy = modf(log(dy) / LN10, &int_dy);
7966 if (frac_dy < 0) {
7967 frac_dy += 1;
7968 int_dy -= 1;
7969 }
7970
7971 tick_base = frac_dy < LOG2 ? 1 : frac_dy < LOG5 ? 2 : 3;
7972 major_base = label_base = tick_base + 1;
7973
7974 /* rounding up of dy, label_dy */
7975 dy = pow(10, int_dy) * base[tick_base];
7976 major_dy = pow(10, int_dy) * base[major_base];
7977 label_dy = major_dy;
7978
7979 /* number of significant digits */
7980 if (ymin == 0)
7981 n_sig1 = 0;
7982 else
7983 n_sig1 =
7984 (int) floor(log(fabs(ymin)) / LN10) -
7985 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7986
7987 if (ymax == 0)
7988 n_sig2 = 0;
7989 else
7990 n_sig2 =
7991 (int) floor(log(fabs(ymax)) / LN10) -
7992 (int) floor(log(fabs(label_dy)) / LN10) + 1;
7993
7994 n_sig1 = MAX(n_sig1, n_sig2);
7995 n_sig1 = MAX(n_sig1, 4);
7996
7997 /* increasing label_dy, if labels would overlap */
7998 while (label_dy / (ymax - ymin) * width < 1.5 * font->h) {
7999 label_base++;
8000 label_dy = pow(10, int_dy) * base[label_base];
8001 if (label_base % 3 == 2 && major_base % 3 == 1) {
8002 major_base++;
8003 major_dy = pow(10, int_dy) * base[major_base];
8004 }
8005 }
8006 }
8007
8008 max_width = 0;
8009 y_act = floor(ymin / dy) * dy;
8010
8011 if (x1 != 0 || y1 != 0)
8012 gdImageLine(im, x1, y1, x1, y1 - width, col);
8013
8014 last_label_y = y1 + 2 * font->h;
8015
8016 do {
8017 if (logaxis)
8018 y_screen = y1 - (log(y_act) - log(ymin)) / (log(ymax) - log(ymin)) * width;
8019 else
8020 y_screen = y1 - (y_act - ymin) / (ymax - ymin) * width;
8021 ys = (int) (y_screen + 0.5);
8022
8023 if (y_screen < y1 - width - 0.001)
8024 break;
8025
8026 if (y_screen <= y1 + 0.001) {
8027 if (fabs(floor(y_act / major_dy + 0.5) - y_act / major_dy) <
8028 dy / major_dy / 10.0) {
8029 if (fabs(floor(y_act / label_dy + 0.5) - y_act / label_dy) <
8030 dy / label_dy / 10.0) {
8031 if (x1 != 0 || y1 != 0) {
8032 /* label tick mark */
8033 gdImageLine(im, x1, ys, x1 + text, ys, col);
8034
8035 /* grid line */
8036 if (grid != 0 && y_screen < y1 && y_screen > y1 - width) {
8037 if (grid > 0)
8038 gdImageLine(im, x1 + 1, ys, x1 + grid, ys, gcol);
8039 else
8040 gdImageLine(im, x1 - 1, ys, x1 + grid, ys, gcol);
8041 }
8042
8043 /* label */
8044 if (label != 0) {
8045 sprintf(str, "%1.*lG", n_sig1, y_act);
8046 if (label < 0)
8047 gdImageString(im, font, x1 + label - font->w * strlen(str),
8048 ys - font->h / 2, str, col);
8049 else
8050 gdImageString(im, font, x1 + label, ys - font->h / 2, str, col);
8051
8052 last_label_y = ys - font->h / 2;
8053 }
8054 } else {
8055 sprintf(str, "%1.*lG", n_sig1, y_act);
8056 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8057 }
8058 } else {
8059 if (x1 != 0 || y1 != 0) {
8060 /* major tick mark */
8061 gdImageLine(im, x1, ys, x1 + major, ys, col);
8062
8063 /* grid line */
8064 if (grid != 0 && y_screen < y1 && y_screen > y1 - width)
8065 gdImageLine(im, x1, ys, x1 + grid, ys, col);
8066 }
8067 }
8068 if (logaxis) {
8069 dy *= 10;
8070 major_dy *= 10;
8071 label_dy *= 10;
8072 }
8073
8074 } else {
8075 if (x1 != 0 || y1 != 0) {
8076 /* minor tick mark */
8077 gdImageLine(im, x1, ys, x1 + minor, ys, col);
8078 }
8079
8080 /* for logaxis, also put labes on minor tick marks */
8081 if (logaxis) {
8082 if (label != 0) {
8083 if (x1 != 0 || y1 != 0) {
8084 /* calculate position of next major label */
8085 y_next = pow(10, floor(log(y_act) / LN10) + 1);
8086 y_screen =
8087 (int) (y1 -
8088 (log(y_next) - log(ymin)) / (log(ymax) -
8089 log(ymin)) * width + 0.5);
8090
8091 if (ys + font->h / 2 < last_label_y
8092 && ys - font->h / 2 > y_screen + font->h / 2) {
8093 sprintf(str, "%1.*lG", n_sig1, y_act);
8094 if (label < 0)
8095 gdImageString(im, font, x1 + label - font->w * strlen(str),
8096 ys - font->h / 2, str, col);
8097 else
8098 gdImageString(im, font, x1 + label, ys - font->h / 2, str,
8099 col);
8100 }
8101
8102 last_label_y = ys - font->h / 2;
8103 } else {
8104 sprintf(str, "%1.*lG", n_sig1, y_act);
8105 max_width = MAX(max_width, (int) (font->w * strlen(str)));
8106 }
8107 }
8108 }
8109 }
8110 }
8111
8112 y_act += dy;
8113
8114 /* supress 1.23E-17 ... */
8115 if (fabs(y_act) < dy / 100)
8116 y_act = 0;
8117
8118 } while (1);
8119
8120 return max_width + abs(label);
8121}
8122
8123/*------------------------------------------------------------------*/
8124
8125int time_to_sec(const char *str)
8126{
8127 double s;
8128
8129 s = atof(str);
8130 switch (str[strlen(str) - 1]) {
8131 case 'm':
8132 case 'M':
8133 s *= 60;
8134 break;
8135 case 'h':
8136 case 'H':
8137 s *= 3600;
8138 break;
8139 case 'd':
8140 case 'D':
8141 s *= 3600 * 24;
8142 break;
8143 }
8144
8145 return (int) s;
8146}
8147
8148/*------------------------------------------------------------------*/
8149
8150time_t string_to_time(const char *str)
8151{
8152 time_t t = 0;
8153 for (; *str != 0; str++) {
8154 if (*str < '0')
8155 break;
8156 if (*str > '9')
8157 break;
8158 t *= 10;
8159 t += *str - '0';
8160 }
8161 return t;
8162}
8163
8164/*------------------------------------------------------------------*/
8165
8166std::string time_to_string(time_t t)
8167{
8168 char buf[256];
8169 sprintf(buf, "%.0f", (double)t);
8170 return buf;
8171}
8172
8173/*------------------------------------------------------------------*/
8174
8175static bool gDoSetupHistoryWatch = true;
8176static bool gDoReloadHistory = false;
8177
8179{
8180 //printf("history_watch_callback %d %d %d\n", hDB, hKey, index);
8181 gDoReloadHistory = true;
8182 cm_msg(MINFO, "history_watch_callback", "History configuration may have changed, will reconnect");
8183}
8184
8186static HNDLE gMhkey = 0;
8187
8188/*------------------------------------------------------------------*/
8189
8190static MidasHistoryInterface* get_history(bool reset = false)
8191{
8192 int status;
8193 HNDLE hDB;
8194
8195 // history reconnect requested by watch callback?
8196
8197 if (gDoReloadHistory) {
8198 gDoReloadHistory = false;
8199 reset = true;
8200 }
8201
8202 // disconnect from previous history
8203
8204 if (reset && gMh) {
8205 gMh->hs_disconnect();
8206 delete gMh;
8207 gMh = NULL;
8208 gMhkey = 0;
8209 }
8210
8212 assert(status == CM_SUCCESS);
8213
8214 // setup a watch on history configuration
8215
8217 HNDLE hKey;
8218 gDoSetupHistoryWatch = false;
8219
8220 status = db_find_key(hDB, 0, "/Logger/History", &hKey);
8221 if (status == DB_SUCCESS)
8223
8224 status = db_find_key(hDB, 0, "/History/LoggerHistoryChannel", &hKey);
8225 if (status == DB_SUCCESS)
8227 }
8228
8229 // find out if ODB settings have changed and we need to connect to a different history channel
8230
8231 HNDLE hKey = 0;
8233 if (status != HS_SUCCESS)
8234 return gMh;
8235
8236 //printf("mh %p, hKey %d, mhkey %d\n", mh, hKey, mhkey);
8237
8238 if (gMh && hKey == gMhkey) // same channel as before
8239 return gMh;
8240
8241 if (gMh) {
8242 delete gMh;
8243 gMh = NULL;
8244 gMhkey = 0;
8245 }
8246
8248 if (status != HS_SUCCESS || gMh==NULL) {
8249 cm_msg(MERROR, "get_history", "Cannot configure history, hs_get_history() status %d", status);
8250 gMh = NULL;
8251 return NULL;
8252 }
8253
8254 gMhkey = hKey;
8255
8256 // cm_msg(MINFO, "get_history", "Reading history from channel \'%s\' type \'%s\'", mh->name, mh->type);
8257
8258 return gMh;
8259}
8260
8261/*------------------------------------------------------------------*/
8262
8263#ifdef OS_WINNT
8264#undef DELETE
8265#endif
8266
8267#define ALLOC(t,n) (t*)calloc(sizeof(t),(n))
8268#define DELETE(x) if (x) { free(x); (x)=NULL; }
8269#define DELETEA(x, n) if (x) { for (int i=0; i<(n); i++) { free((x)[i]); (x)[i]=NULL; }; DELETE(x); }
8270#define STRDUP(x) strdup(x)
8271
8273{
8282 time_t** t;
8283 double** v;
8284
8287
8288 time_t tstart;
8289 time_t tend;
8290 time_t scale;
8291
8292 void Allocate(int xnvars) {
8293 if (alloc_nvars > 0)
8294 Free();
8295 nvars = 0;
8296 alloc_nvars = xnvars;
8297 event_names = ALLOC(char*, alloc_nvars);
8298 var_names = ALLOC(char*, alloc_nvars);
8299 var_index = ALLOC(int, alloc_nvars);
8300 odb_index = ALLOC(int, alloc_nvars);
8301 status = ALLOC(int, alloc_nvars);
8303 t = ALLOC(time_t*, alloc_nvars);
8304 v = ALLOC(double*, alloc_nvars);
8305
8306 have_last_written = false;
8307 last_written = ALLOC(time_t, alloc_nvars);
8308 }
8309
8310 void Free() {
8315 DELETE(status);
8320 nvars = 0;
8321 alloc_nvars = 0;
8322 have_last_written = false;
8323 }
8324
8325 void Print() const {
8326 printf("this %p, nvars %d. tstart %d, tend %d, scale %d\n", this, nvars, (int)tstart, (int)tend, (int)scale);
8327 for (int i=0; i<nvars; i++) {
8328 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]);
8329 if (status[i]==HS_SUCCESS && num_entries[i]>0 && t[i] && v[i])
8330 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]);
8331 printf(" last_written %d", (int)last_written[i]);
8332 printf("\n");
8333 }
8334 }
8335
8336 HistoryData() // ctor
8337 {
8338 nvars = 0;
8339 alloc_nvars = 0;
8340 have_last_written = false;
8341 tstart = 0;
8342 tend = 0;
8343 scale = 0;
8344 }
8345
8347 {
8348 if (alloc_nvars > 0)
8349 Free();
8350 }
8351};
8352
8353#define READ_HISTORY_DATA 0x1
8354#define READ_HISTORY_RUNMARKER 0x2
8355#define READ_HISTORY_LAST_WRITTEN 0x4
8356
8358{
8359 std::string event_name;
8360 std::string tag_name;
8361 std::string formula;
8362 std::string colour;
8363 std::string label;
8364 bool show_raw_value = false;
8365 int order = -1;
8366 double factor = 1.0;
8367 double offset = 0;
8368 double voffset = 0;
8369};
8370
8372{
8373 std::string timescale = "1h";
8374 double minimum = 0;
8375 double maximum = 0;
8376 bool zero_ylow = false;
8377 bool log_axis = false;
8378 bool show_run_markers = true;
8379 bool show_values = true;
8380 bool show_fill = true;
8381 bool show_factor = false;
8382 bool enable_factor = true;
8383
8384 std::vector<HistVar> vars;
8385};
8386
8387static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel);
8388
8389int 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)
8390{
8391 //HNDLE hkeypanel, hkeydvar, hkey;
8392 //KEY key;
8393 //char path[256];
8394 //int n_vars;
8395 int status;
8396 int debug = 1;
8397
8398 //mstrlcpy(path, group, sizeof(path));
8399 //mstrlcat(path, "/", sizeof(path));
8400 //mstrlcat(path, panel, sizeof(path));
8401
8402 //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);
8403
8404 /* connect to history */
8406 if (mh == NULL) {
8407 //r->rsprintf(str, "History is not configured\n");
8408 return HS_FILE_ERROR;
8409 }
8410
8411#if 0
8412 /* check panel name in ODB */
8413 status = db_find_key(hDB, 0, "/History/Display", &hkey);
8414 if (!hkey) {
8415 cm_msg(MERROR, "read_history", "Cannot find \'/History/Display\' in ODB, status %d", status);
8416 return HS_FILE_ERROR;
8417 }
8418
8419 /* check panel name in ODB */
8420 status = db_find_key(hDB, hkey, path, &hkeypanel);
8421 if (!hkeypanel) {
8422 cm_msg(MERROR, "read_history", "Cannot find \'%s\' in ODB, status %d", path, status);
8423 return HS_FILE_ERROR;
8424 }
8425
8426 status = db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8427 if (!hkeydvar) {
8428 cm_msg(MERROR, "read_history", "Cannot find \'%s/Variables\' in ODB, status %d", path, status);
8429 return HS_FILE_ERROR;
8430 }
8431
8432 db_get_key(hDB, hkeydvar, &key);
8433 n_vars = key.num_values;
8434#endif
8435
8436 data->Allocate(hp.vars.size()+2);
8437
8438 data->tstart = tstart;
8439 data->tend = tend;
8440 data->scale = scale;
8441
8442 for (size_t i=0; i<hp.vars.size(); i++) {
8443 if (index != -1 && (size_t)index != i)
8444 continue;
8445
8446 //char str[256];
8447 //int size = sizeof(str);
8448 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8449 //if (status != DB_SUCCESS) {
8450 // cm_msg(MERROR, "read_history", "Cannot read tag %d in panel %s, status %d", i, path, status);
8451 // continue;
8452 //}
8453
8454 /* split varname in event, variable and index: "event/tag[index]" */
8455
8456 //char *p = strchr(str, ':');
8457 //if (!p)
8458 // p = strchr(str, '/');
8459 //
8460 //if (!p) {
8461 // cm_msg(MERROR, "read_history", "Tag \"%s\" has wrong format in panel \"%s\"", str, path);
8462 // continue;
8463 //}
8464
8465 //*p = 0;
8466
8467 data->odb_index[data->nvars] = i;
8468 data->event_names[data->nvars] = STRDUP(hp.vars[i].event_name.c_str());
8469 data->var_names[data->nvars] = STRDUP(hp.vars[i].tag_name.c_str());
8470 data->var_index[data->nvars] = 0;
8471
8472 char *q = strchr(data->var_names[data->nvars], '[');
8473 if (q) {
8474 data->var_index[data->nvars] = atoi(q+1);
8475 *q = 0;
8476 }
8477
8478 data->nvars++;
8479 } // loop over variables
8480
8481 /* write run markes if selected */
8482 if (flags & READ_HISTORY_RUNMARKER) {
8483
8484 data->event_names[data->nvars+0] = STRDUP("Run transitions");
8485 data->event_names[data->nvars+1] = STRDUP("Run transitions");
8486
8487 data->var_names[data->nvars+0] = STRDUP("State");
8488 data->var_names[data->nvars+1] = STRDUP("Run number");
8489
8490 data->var_index[data->nvars+0] = 0;
8491 data->var_index[data->nvars+1] = 0;
8492
8493 data->odb_index[data->nvars+0] = -1;
8494 data->odb_index[data->nvars+1] = -2;
8495
8496 data->nvars += 2;
8497 }
8498
8499 bool get_last_written = false;
8500
8501 if (flags & READ_HISTORY_DATA) {
8502 status = mh->hs_read(tstart, tend, scale,
8503 data->nvars,
8504 data->event_names,
8505 data->var_names,
8506 data->var_index,
8507 data->num_entries,
8508 data->t,
8509 data->v,
8510 data->status);
8511
8512 if (debug) {
8513 printf("read_history: nvars %d, hs_read() status %d\n", data->nvars, status);
8514 for (int i=0; i<data->nvars; i++) {
8515 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]);
8516 }
8517 }
8518
8519 if (status != HS_SUCCESS) {
8520 cm_msg(MERROR, "read_history", "Complete history failure, hs_read() status %d, see messages", status);
8521 return HS_FILE_ERROR;
8522 }
8523
8524 for (int i=0; i<data->nvars; i++) {
8525 if (data->status[i] != HS_SUCCESS || data->num_entries[i] < 1) {
8526 get_last_written = true;
8527 break;
8528 }
8529 }
8530 }
8531
8532 if (flags & READ_HISTORY_LAST_WRITTEN)
8533 get_last_written = true;
8534
8535 if (get_last_written) {
8536 data->have_last_written = true;
8537
8539 tstart,
8540 data->nvars,
8541 data->event_names,
8542 data->var_names,
8543 data->var_index,
8544 data->last_written);
8545
8546 if (status != HS_SUCCESS) {
8547 data->have_last_written = false;
8548 }
8549 }
8550
8551 return SUCCESS;
8552}
8553
8554int get_hist_last_written(MVOdb* odb, const char *group, const char *panel, time_t endtime, int index, int want_all, time_t *plastwritten)
8555{
8556 //HNDLE hDB;
8557 int status;
8558
8559 time_t now = ss_time();
8560
8561 if (endtime == 0)
8562 endtime = now;
8563
8564 HistoryData hsxxx;
8565 HistoryData* hsdata = &hsxxx;
8566
8567 //cm_get_experiment_database(&hDB, NULL);
8568
8569 HistPlot hp;
8570 LoadHistPlotFromOdb(odb, &hp, group, panel);
8571
8572 double tstart = ss_millitime();
8573
8574 int flags = READ_HISTORY_LAST_WRITTEN;
8575
8576 status = read_history(hp, /*hDB, group, panel,*/ index, flags, endtime, endtime, 0, hsdata);
8577
8578 if (status != HS_SUCCESS) {
8579 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8580 return status;
8581 }
8582
8583 if (!hsdata->have_last_written) {
8584 //sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
8585 return HS_FILE_ERROR;
8586 }
8587
8588 int count = 0;
8589 time_t tmin = endtime;
8590 time_t tmax = 0;
8591
8592 for (int k=0; k<hsdata->nvars; k++) {
8593 int i = hsdata->odb_index[k];
8594
8595 if (i<0)
8596 continue;
8597 if (index != -1 && index != i)
8598 continue;
8599
8600 time_t lw = hsdata->last_written[k];
8601
8602 if (lw==0) // no last_written for this variable, skip it.
8603 continue;
8604
8605 if (lw > endtime)
8606 lw = endtime; // just in case hs_get_last_written() returns dates in the "future" for this plot
8607
8608 if (lw > tmax)
8609 tmax = lw;
8610
8611 if (lw < tmin)
8612 tmin = lw;
8613
8614 count++;
8615
8616 //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);
8617 }
8618
8619 if (count == 0) // all variables have no last_written
8620 return HS_FILE_ERROR;
8621
8622 if (want_all)
8623 *plastwritten = tmin; // all variables have data
8624 else
8625 *plastwritten = tmax; // at least one variable has data
8626
8627 //printf("tmin %.0f, tmax %.0f, endtime %.0f, last written %.0f\n", (double)tmin, (double)tmax, (double)endtime, (double)*plastwritten);
8628
8629 double tend = ss_millitime();
8630
8631 if (/* DISABLES CODE */ (0))
8632 printf("get_hist_last_written: elapsed time %f ms\n", tend-tstart);
8633
8634 return HS_SUCCESS;
8635}
8636
8637void generate_hist_graph(MVOdb* odb, Return* rr, const char *hgroup, const char *hpanel, char *buffer, int *buffer_size,
8638 int width, int height,
8639 time_t xendtime,
8640 int scale,
8641 int index,
8642 int labels, const char *bgcolor, const char *fgcolor, const char *gridcolor)
8643{
8644 HNDLE hDB;
8645 //KEY key;
8646 gdImagePtr im;
8647 gdGifBuffer gb;
8648 int i, j, k, l;
8649 //int n_vars;
8650 int size, status, r, g, b;
8651 //int x_marker;
8652 int length;
8653 int white, grey, red;
8654 //int black, ltgrey, green, blue;
8655 int fgcol, bgcol, gridcol;
8656 int curve_col[MAX_VARS];
8657 int state_col[3];
8658 char str[256], *p;
8659 //INT var_index[MAX_VARS];
8660 //char event_name[MAX_VARS][NAME_LENGTH];
8661 //char tag_name[MAX_VARS][64];
8662 //char var_name[MAX_VARS][NAME_LENGTH];
8663 //char varname[64];
8664 //char key_name[256];
8665 //float factor[MAX_VARS], offset[MAX_VARS];
8666 //BOOL logaxis, runmarker;
8667 //double xmin, xrange;
8668 double ymin, ymax;
8669 double upper_limit[MAX_VARS], lower_limit[MAX_VARS];
8670 //float minvalue = (float) -HUGE_VAL;
8671 //float maxvalue = (float) +HUGE_VAL;
8672 //int show_values = 0;
8673 //int sort_vars = 0;
8674 //int old_vars = 0;
8675 time_t starttime, endtime;
8676 int flags;
8677
8678 time_t now = ss_time();
8679
8680 if (xendtime == 0)
8681 xendtime = now;
8682
8683 HistPlot hp;
8684 LoadHistPlotFromOdb(odb, &hp, hgroup, hpanel);
8685
8686 std::vector<int> var_index; var_index.resize(hp.vars.size());
8687
8688 for (size_t i=0; i<hp.vars.size(); i++) {
8689 var_index[i] = 0;
8690 const char *vp = strchr(hp.vars[i].tag_name.c_str(), '[');
8691 if (vp) {
8692 var_index[i] = atoi(vp + 1);
8693 }
8694 }
8695
8696 int logaxis = hp.log_axis;
8697 double minvalue = hp.minimum;
8698 double maxvalue = hp.maximum;
8699
8700 if ((minvalue == 0) && (maxvalue == 0)) {
8701 minvalue = -HUGE_VAL;
8702 maxvalue = +HUGE_VAL;
8703 }
8704
8705 std::vector<int> x[MAX_VARS];
8706 std::vector<double> y[MAX_VARS];
8707
8708 HistoryData hsxxx;
8709 HistoryData* hsdata = &hsxxx;
8710
8712
8713 /* generate image */
8714 im = gdImageCreate(width, height);
8715
8716 /* allocate standard colors */
8717 sscanf(bgcolor, "%02x%02x%02x", &r, &g, &b);
8718 bgcol = gdImageColorAllocate(im, r, g, b);
8719 sscanf(fgcolor, "%02x%02x%02x", &r, &g, &b);
8720 fgcol = gdImageColorAllocate(im, r, g, b);
8721 sscanf(gridcolor, "%02x%02x%02x", &r, &g, &b);
8722 gridcol = gdImageColorAllocate(im, r, g, b);
8723
8724 grey = gdImageColorAllocate(im, 192, 192, 192);
8725 //ltgrey = gdImageColorAllocate(im, 208, 208, 208);
8726 white = gdImageColorAllocate(im, 255, 255, 255);
8727 //black = gdImageColorAllocate(im, 0, 0, 0);
8728 red = gdImageColorAllocate(im, 255, 0, 0);
8729 //green = gdImageColorAllocate(im, 0, 255, 0);
8730 //blue = gdImageColorAllocate(im, 0, 0, 255);
8731
8732 curve_col[0] = gdImageColorAllocate(im, 0, 0, 255);
8733 curve_col[1] = gdImageColorAllocate(im, 0, 192, 0);
8734 curve_col[2] = gdImageColorAllocate(im, 255, 0, 0);
8735 curve_col[3] = gdImageColorAllocate(im, 0, 192, 192);
8736 curve_col[4] = gdImageColorAllocate(im, 255, 0, 255);
8737 curve_col[5] = gdImageColorAllocate(im, 192, 192, 0);
8738 curve_col[6] = gdImageColorAllocate(im, 128, 128, 128);
8739 curve_col[7] = gdImageColorAllocate(im, 128, 255, 128);
8740 curve_col[8] = gdImageColorAllocate(im, 255, 128, 128);
8741 curve_col[9] = gdImageColorAllocate(im, 128, 128, 255);
8742 for (i=10; i<MAX_VARS; i++)
8743 curve_col[i] = gdImageColorAllocate(im, 128, 128, 128);
8744
8745 state_col[0] = gdImageColorAllocate(im, 255, 0, 0);
8746 state_col[1] = gdImageColorAllocate(im, 255, 255, 0);
8747 state_col[2] = gdImageColorAllocate(im, 0, 255, 0);
8748
8749 /* Set transparent color. */
8750 gdImageColorTransparent(im, grey);
8751
8752 /* Title */
8753 gdImageString(im, gdFontGiant, width / 2 - (strlen(hpanel) * gdFontGiant->w) / 2, 2, (char*)hpanel, fgcol);
8754
8755 /* connect to history */
8757 if (mh == NULL) {
8758 sprintf(str, "History is not configured, see messages");
8759 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8760 goto error;
8761 }
8762
8764 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
8765 //db_find_key(hDB, 0, str, &hkeypanel);
8766 //if (!hkeypanel) {
8767 // sprintf(str, "Cannot find /History/Display/%s/%s in ODB", hgroup, hpanel);
8768 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8769 // goto error;
8770 //}
8771
8772 //db_find_key(hDB, hkeypanel, "Variables", &hkeydvar);
8773 //if (!hkeydvar) {
8774 // sprintf(str, "Cannot find /History/Display/%s/%s/Variables in ODB", hgroup, hpanel);
8775 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8776 // goto error;
8777 //}
8778
8779 //db_get_key(hDB, hkeydvar, &key);
8780 //n_vars = key.num_values;
8781
8782 if (hp.vars.empty()) {
8783 sprintf(str, "No variables in panel %s/%s", hgroup, hpanel);
8784 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8785 goto error;
8786 }
8787
8788 if (hp.vars.size() > MAX_VARS) {
8789 sprintf(str, "Too many variables in panel %s/%s", hgroup, hpanel);
8790 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8791 goto error;
8792 }
8793
8794 ymin = ymax = 0;
8795 //logaxis = runmarker = 0;
8796
8797 for (i = 0; i < (int)hp.vars.size(); i++) {
8798 if (index != -1 && index != i)
8799 continue;
8800
8801 //size = sizeof(str);
8802 //status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
8803 //if (status != DB_SUCCESS) {
8804 // sprintf(str, "Cannot read tag %d in panel %s/%s, status %d", i, hgroup, hpanel, status);
8805 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8806 // goto error;
8807 //}
8808 //
8809 //mstrlcpy(tag_name[i], str, sizeof(tag_name[0]));
8810
8812 //char *tp = strchr(tag_name[i], ':');
8813 //if (tp) {
8814 // mstrlcpy(event_name[i], tag_name[i], sizeof(event_name[0]));
8815 // char *ep = strchr(event_name[i], ':');
8816 // if (ep)
8817 // *ep = 0;
8818 // mstrlcpy(var_name[i], tp+1, sizeof(var_name[0]));
8819 // var_index[i] = 0;
8820 // char *vp = strchr(var_name[i], '[');
8821 // if (vp) {
8822 // var_index[i] = atoi(vp + 1);
8823 // *vp = 0;
8824 // }
8825 //} else {
8826 // sprintf(str, "Tag \"%s\" has wrong format in panel \"%s/%s\"", tag_name[i], hgroup, hpanel);
8827 // gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
8828 // goto error;
8829 //}
8830 //
8831 //db_find_key(hDB, hkeypanel, "Colour", &hkey);
8832 //if (hkey) {
8833 // size = sizeof(str);
8834 // status = db_get_data_index(hDB, hkey, str, &size, i, TID_STRING);
8835 // if (status == DB_SUCCESS) {
8836 // if (str[0] == '#') {
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 //}
8857
8858 if (hp.vars[i].colour[0] == '#') {
8859 const char* str = hp.vars[i].colour.c_str();
8860 char sss[3];
8861 int r, g, b;
8862
8863 sss[0] = str[1];
8864 sss[1] = str[2];
8865 sss[2] = 0;
8866 r = strtoul(sss, NULL, 16);
8867 sss[0] = str[3];
8868 sss[1] = str[4];
8869 sss[2] = 0;
8870 g = strtoul(sss, NULL, 16);
8871 sss[0] = str[5];
8872 sss[1] = str[6];
8873 sss[2] = 0;
8874 b = strtoul(sss, NULL, 16);
8875
8876 curve_col[i] = gdImageColorAllocate(im, r, g, b);
8877 }
8878
8879 /* get timescale */
8880 if (scale == 0) {
8881 //std::string ts = "1h";
8882 //status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8883 //if (status != DB_SUCCESS) {
8884 // /* delete old integer key */
8885 // db_find_key(hDB, hkeypanel, "Timescale", &hkey);
8886 // if (hkey)
8887 // db_delete_key(hDB, hkey, FALSE);
8888 //
8889 // ts = "1h";
8890 // status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
8891 //}
8892
8893 scale = time_to_sec(hp.timescale.c_str());
8894 }
8895
8896 //for (j = 0; j < MAX_VARS; j++) {
8897 // factor[j] = 1;
8898 // offset[j] = 0;
8899 //}
8900
8902 //size = sizeof(float) * n_vars;
8903 //db_get_value(hDB, hkeypanel, "Factor", factor, &size, TID_FLOAT, TRUE);
8904
8906 //size = sizeof(float) * n_vars;
8907 //db_get_value(hDB, hkeypanel, "Offset", offset, &size, TID_FLOAT, TRUE);
8908
8910 //size = sizeof(logaxis);
8911 //logaxis = 0;
8912 //db_get_value(hDB, hkeypanel, "Log axis", &logaxis, &size, TID_BOOL, TRUE);
8913
8915 //size = sizeof(show_values);
8916 //show_values = 0;
8917 //db_get_value(hDB, hkeypanel, "Show values", &show_values, &size, TID_BOOL, TRUE);
8918
8920 //size = sizeof(sort_vars);
8921 //sort_vars = 0;
8922 //db_get_value(hDB, hkeypanel, "Sort vars", &sort_vars, &size, TID_BOOL, TRUE);
8923
8925 //size = sizeof(old_vars);
8926 //old_vars = 0;
8927 //db_get_value(hDB, hkeypanel, "Show old vars", &old_vars, &size, TID_BOOL, TRUE);
8928
8930 //size = sizeof(minvalue);
8931 //minvalue = (float) -HUGE_VAL;
8932 //db_get_value(hDB, hkeypanel, "Minimum", &minvalue, &size, TID_FLOAT, TRUE);
8933
8935 //size = sizeof(maxvalue);
8936 //maxvalue = (float) +HUGE_VAL;
8937 //db_get_value(hDB, hkeypanel, "Maximum", &maxvalue, &size, TID_FLOAT, TRUE);
8938
8939 //if ((minvalue == 0) && (maxvalue == 0)) {
8940 // minvalue = (float) -HUGE_VAL;
8941 // maxvalue = (float) +HUGE_VAL;
8942 //}
8943
8945 //size = sizeof(runmarker);
8946 //runmarker = 1;
8947 //db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
8948
8949 /* make ODB path from tag name */
8950 std::string odbpath;
8951 HNDLE hkeyeq = 0;
8952 HNDLE hkeyroot;
8953 db_find_key(hDB, 0, "/Equipment", &hkeyroot);
8954 if (hkeyroot) {
8955 for (j = 0;; j++) {
8956 HNDLE hkeyeq;
8957 db_enum_key(hDB, hkeyroot, j, &hkeyeq);
8958
8959 if (!hkeyeq)
8960 break;
8961
8962 KEY key;
8963 db_get_key(hDB, hkeyeq, &key);
8964 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
8965 /* check if variable is individual key under variables/ */
8966 sprintf(str, "Variables/%s", hp.vars[i].tag_name.c_str());
8967 HNDLE hkey;
8968 db_find_key(hDB, hkeyeq, str, &hkey);
8969 if (hkey) {
8970 //sprintf(odbpath, "/Equipment/%s/Variables/%s", event_name[i], var_name[i]);
8971 odbpath = "";
8972 odbpath += "/Equipment/";
8973 odbpath += hp.vars[i].event_name;
8974 odbpath += "/Variables/";
8975 odbpath += hp.vars[i].tag_name;
8976 break;
8977 }
8978
8979 /* check if variable is in setttins/names array */
8980 HNDLE hkeynames;
8981 db_find_key(hDB, hkeyeq, "Settings/Names", &hkeynames);
8982 if (hkeynames) {
8983 /* extract variable name and Variables/<key> */
8984 mstrlcpy(str, hp.vars[i].tag_name.c_str(), sizeof(str));
8985 p = str + strlen(str) - 1;
8986 while (p > str && *p != ' ')
8987 p--;
8988 std::string key_name = p + 1;
8989 *p = 0;
8990
8991 std::string varname = str;
8992
8993 /* find key in single name array */
8994 db_get_key(hDB, hkeynames, &key);
8995 for (k = 0; k < key.num_values; k++) {
8996 size = sizeof(str);
8997 db_get_data_index(hDB, hkeynames, str, &size, k, TID_STRING);
8998 if (equal_ustring(str, varname.c_str())) {
8999 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, k);
9000 odbpath = "";
9001 odbpath += "/Equipment/";
9002 odbpath += hp.vars[i].event_name;
9003 odbpath += "/Variables/";
9004 odbpath += key_name;
9005 odbpath += "[";
9006 odbpath += toString(k);
9007 odbpath += "]";
9008 break;
9009 }
9010 }
9011 } else {
9012 /* go through /variables/<name> entries */
9013 HNDLE hkeyvars;
9014 db_find_key(hDB, hkeyeq, "Variables", &hkeyvars);
9015 if (hkeyvars) {
9016 for (k = 0;; k++) {
9017 db_enum_key(hDB, hkeyvars, k, &hkey);
9018
9019 if (!hkey)
9020 break;
9021
9022 /* find "settins/names <key>" for this key */
9023 db_get_key(hDB, hkey, &key);
9024
9025 /* find key in key_name array */
9026 std::string key_name = key.name;
9027
9028 std::string path;
9029 //sprintf(str, "Settings/Names %s", key_name);
9030 path += "Settings/Names ";
9031 path += key_name;
9032
9033 HNDLE hkeynames;
9034 db_find_key(hDB, hkeyeq, path.c_str(), &hkeynames);
9035 if (hkeynames) {
9036 db_get_key(hDB, hkeynames, &key);
9037 for (l = 0; l < key.num_values; l++) {
9038 size = sizeof(str);
9039 db_get_data_index(hDB, hkeynames, str, &size, l, TID_STRING);
9040 if (equal_ustring(str, hp.vars[i].tag_name.c_str())) {
9041 //sprintf(odbpath, "/Equipment/%s/Variables/%s[%d]", event_name[i], key_name, l);
9042 odbpath = "";
9043 odbpath += "/Equipment/";
9044 odbpath += hp.vars[i].event_name;
9045 odbpath += "/Variables/";
9046 odbpath += key_name;
9047 odbpath += "[";
9048 odbpath += toString(l);
9049 odbpath += "]";
9050 break;
9051 }
9052 }
9053 }
9054 }
9055 }
9056 }
9057
9058 break;
9059 }
9060 }
9061
9062 if (!hkeyeq) {
9063 db_find_key(hDB, 0, "/History/Links", &hkeyroot);
9064 if (hkeyroot) {
9065 for (j = 0;; j++) {
9066 HNDLE hkey;
9067 db_enum_link(hDB, hkeyroot, j, &hkey);
9068
9069 if (!hkey)
9070 break;
9071
9072 KEY key;
9073 db_get_key(hDB, hkey, &key);
9074 if (equal_ustring(key.name, hp.vars[i].event_name.c_str())) {
9075 db_enum_key(hDB, hkeyroot, j, &hkey);
9076 db_find_key(hDB, hkey, hp.vars[i].tag_name.c_str(), &hkey);
9077 if (hkey) {
9078 db_get_key(hDB, hkey, &key);
9079 odbpath = db_get_path(hDB, hkey);
9080 if (key.num_values > 1) {
9081 odbpath += "[";
9082 odbpath += toString(var_index[i]);
9083 odbpath += "]";
9084 }
9085 break;
9086 }
9087 }
9088 }
9089 }
9090 }
9091 }
9092
9093 /* search alarm limits */
9094 upper_limit[i] = lower_limit[i] = -12345;
9095 db_find_key(hDB, 0, "Alarms/Alarms", &hkeyroot);
9096 if (odbpath.length() > 0 && hkeyroot) {
9097 for (j = 0;; j++) {
9098 HNDLE hkey;
9099 db_enum_key(hDB, hkeyroot, j, &hkey);
9100
9101 if (!hkey)
9102 break;
9103
9104 size = sizeof(str);
9105 db_get_value(hDB, hkey, "Condition", str, &size, TID_STRING, TRUE);
9106
9107 if (strstr(str, odbpath.c_str())) {
9108 if (strchr(str, '<')) {
9109 p = strchr(str, '<') + 1;
9110 if (*p == '=')
9111 p++;
9112 if (hp.enable_factor) {
9113 lower_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9114 } else {
9115 lower_limit[i] = atof(p);
9116 }
9117 }
9118 if (strchr(str, '>')) {
9119 p = strchr(str, '>') + 1;
9120 if (*p == '=')
9121 p++;
9122 if (hp.enable_factor) {
9123 upper_limit[i] = (hp.vars[i].factor * (atof(p) - hp.vars[i].voffset) + hp.vars[i].offset);
9124 } else {
9125 upper_limit[i] = atof(p);
9126 }
9127 }
9128 }
9129 }
9130 }
9131 } // loop over variables
9132
9133 //starttime = now - scale + toffset;
9134 //endtime = now + toffset;
9135
9136 starttime = xendtime - scale;
9137 endtime = xendtime;
9138
9139 //printf("now %d, scale %d, xendtime %d, starttime %d, endtime %d\n", now, scale, xendtime, starttime, endtime);
9140
9141 flags = READ_HISTORY_DATA;
9142 if (hp.show_run_markers)
9143 flags |= READ_HISTORY_RUNMARKER;
9144
9145 status = read_history(hp, /*hDB, hgroup, hpanel,*/ index, flags, starttime, endtime, scale/1000+1, hsdata);
9146
9147 if (status != HS_SUCCESS) {
9148 sprintf(str, "Complete history failure, read_history() status %d, see messages", status);
9149 gdImageString(im, gdFontSmall, width / 2 - (strlen(str) * gdFontSmall->w) / 2, height / 2, str, red);
9150 goto error;
9151 }
9152
9153 DWORD n_point[MAX_VARS];
9154 char var_status[MAX_VARS][256];
9155
9156 for (int k=0; k<hsdata->nvars; k++) {
9157 int i = hsdata->odb_index[k];
9158
9159 if (i<0)
9160 continue;
9161
9162 if (index != -1 && index != i)
9163 continue;
9164
9165 n_point[i] = 0;
9166
9167 var_status[i][0] = 0;
9168 if (hsdata->status[k] == HS_UNDEFINED_VAR) {
9169 sprintf(var_status[i], "not found in history");
9170 continue;
9171 } else if (hsdata->status[k] != HS_SUCCESS) {
9172 sprintf(var_status[i], "hs_read() error %d, see messages", hsdata->status[k]);
9173 continue;
9174 }
9175
9176 int n_vp = 0;
9177 for (int j=0; j<hsdata->num_entries[k]; j++) {
9178 int xx = (int)(hsdata->t[k][j]);
9179 double yy = hsdata->v[k][j];
9180
9181 /* skip NaNs */
9182 if (ss_isnan(yy))
9183 continue;
9184
9185 /* skip INFs */
9186 if (!ss_isfin(yy))
9187 continue;
9188
9189 /* avoid overflow */
9190 if (yy > 1E30)
9191 yy = 1E30f;
9192
9193 /* apply factor and offset */
9194 if (hp.enable_factor) {
9195 yy = hp.vars[i].factor * (yy - hp.vars[i].voffset) + hp.vars[i].offset;
9196 }
9197
9198 /* calculate ymin and ymax */
9199 if ((i == 0 || index != -1) && n_vp == 0)
9200 ymin = ymax = yy;
9201 else {
9202 if (yy > ymax)
9203 ymax = yy;
9204 if (yy < ymin)
9205 ymin = yy;
9206 }
9207
9208 /* increment number of valid points */
9209
9210 x[i].push_back(xx);
9211 y[i].push_back(yy);
9212
9213 n_vp++;
9214
9215 } // loop over data
9216
9217 n_point[i] = n_vp;
9218
9219 assert(x[i].size() == y[i].size());
9220 }
9221
9222 //int flag;
9223 int xmaxm;
9224 int row;
9225 int xold;
9226 int yold;
9227 int aoffset;
9228 double yb1, yb2, yf1, yf2;
9229 int xs, ys;
9230 int x1, x2;
9231 int y1, y2;
9232 int xs_old;
9233 double ybase;
9234
9235 gdPoint poly[3];
9236
9237 if (ymin < minvalue)
9238 ymin = minvalue;
9239
9240 if (ymax > maxvalue)
9241 ymax = maxvalue;
9242
9243 /* check if ylow = 0 */
9244 if (index == -1) {
9245 //flag = 0;
9246 //size = sizeof(flag);
9247 //db_get_value(hDB, hkeypanel, "Zero ylow", &flag, &size, TID_BOOL, TRUE);
9248 if (hp.zero_ylow && ymin > 0)
9249 ymin = 0;
9250 }
9251
9252 /* if min and max too close together, switch to linear axis */
9253 if (logaxis && ymin > 0 && ymax > 0) {
9254 yb1 = pow(10, floor(log(ymin) / LN10));
9255 yf1 = floor(ymin / yb1);
9256 yb2 = pow(10, floor(log(ymax) / LN10));
9257 yf2 = floor(ymax / yb2);
9258
9259 if (yb1 == yb2 && yf1 == yf2)
9260 logaxis = 0;
9261 else {
9262 /* round down and up ymin and ymax */
9263 ybase = pow(10, floor(log(ymin) / LN10));
9264 ymin = (floor(ymin / ybase) * ybase);
9265 ybase = pow(10, floor(log(ymax) / LN10));
9266 ymax = ((floor(ymax / ybase) + 1) * ybase);
9267 }
9268 }
9269
9270 /* avoid negative limits for log axis */
9271 if (logaxis) {
9272 if (ymax <= 0)
9273 ymax = 1;
9274 if (ymin <= 0)
9275 ymin = 1E-12f;
9276 }
9277
9278 /* increase limits by 5% */
9279 if (ymin == 0 && ymax == 0) {
9280 ymin = -1;
9281 ymax = 1;
9282 } else {
9283 if (!logaxis) {
9284 ymax += (ymax - ymin) / 20.f;
9285
9286 if (ymin != 0)
9287 ymin -= (ymax - ymin) / 20.f;
9288 }
9289 }
9290
9291 /* avoid ymin == ymax */
9292 if (ymax == ymin) {
9293 if (logaxis) {
9294 ymax *= 2;
9295 ymin /= 2;
9296 } else {
9297 ymax += 10;
9298 ymin -= 10;
9299 }
9300 }
9301
9302 /* calculate X limits */
9303 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9304 //xmax = (double) (toffset / 3600.0);
9305 //xrange = xmax - xmin;
9306 //xrange = scale/3600.0;
9307
9308 /* caluclate required space for Y-axis */
9309 aoffset = vaxis(im, gdFontSmall, fgcol, gridcol, 0, 0, height, -3, -5, -7, -8, 0, ymin, ymax, logaxis);
9310 aoffset += 2;
9311
9312 x1 = aoffset;
9313 y1 = height - 20;
9314 x2 = width - 20;
9315 y2 = 20;
9316
9317 gdImageFilledRectangle(im, x1, y2, x2, y1, bgcol);
9318
9319 /* draw axis frame */
9320 taxis(im, gdFontSmall, fgcol, gridcol, x1, y1, x2 - x1, width, 3, 5, 9, 10, 0, (double)starttime, (double)endtime);
9321
9322 vaxis(im, gdFontSmall, fgcol, gridcol, x1, y1, y1 - y2, -3, -5, -7, -8, x2 - x1, ymin, ymax, logaxis);
9323 gdImageLine(im, x1, y2, x2, y2, fgcol);
9324 gdImageLine(im, x2, y2, x2, y1, fgcol);
9325
9326 xs = ys = xold = yold = 0;
9327
9328 /* old code for run markers, new code is below */
9329
9330 /* write run markes if selected */
9331 if (/* DISABLES CODE */ (0) && hp.show_run_markers) {
9332
9333 const char* event_names[] = {
9334 "Run transitions",
9335 "Run transitions",
9336 0 };
9337
9338 const char* tag_names[] = {
9339 "State",
9340 "Run number",
9341 0 };
9342
9343 const int tag_indexes[] = {
9344 0,
9345 0,
9346 0 };
9347
9348 int num_entries[3];
9349 time_t *tbuf[3];
9350 double *dbuf[3];
9351 int st[3];
9352
9353 num_entries[0] = 0;
9354 num_entries[1] = 0;
9355
9356 status = mh->hs_read(starttime - scale, endtime, 0,
9357 2, event_names, tag_names, tag_indexes,
9358 num_entries, tbuf, dbuf, st);
9359
9360 //printf("read run info: status %d, entries %d %d\n", status, num_entries[0], num_entries[1]);
9361
9362 int n_marker = num_entries[0];
9363
9364 if (status == HS_SUCCESS && n_marker > 0 && n_marker < 100) {
9365 xs_old = -1;
9366 xmaxm = x1;
9367 for (j = 0; j < (int) n_marker; j++) {
9368 int col;
9369
9370 // explicit algebra manipulation to clarify computations:
9371
9372 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9373 //xrange = scale/3600.0;
9374 //time_t starttime = now - scale + toffset;
9375
9376 //x_marker = (int)(tbuf[1][j] - now);
9377 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9378 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9379 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9380 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9381 xs = (int) ((tbuf[1][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9382
9383 if (xs < x1)
9384 continue;
9385 if (xs >= x2)
9386 continue;
9387
9388 double run_number = dbuf[1][j];
9389
9390 if (xs <= xs_old)
9391 xs = xs_old + 1;
9392 xs_old = xs;
9393
9394 if (dbuf[0][j] == 1)
9395 col = state_col[0];
9396 else if (dbuf[0][j] == 2)
9397 col = state_col[1];
9398 else if (dbuf[0][j] == 3)
9399 col = state_col[2];
9400 else
9401 col = state_col[0];
9402
9403 gdImageDashedLine(im, xs, y1, xs, y2, col);
9404
9405 sprintf(str, "%.0f", run_number);
9406
9407 if (dbuf[0][j] == STATE_RUNNING) {
9408 if (xs > xmaxm) {
9409 gdImageStringUp(im, gdFontSmall, xs + 0, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9410 xmaxm = xs - 2 + gdFontSmall->h;
9411 }
9412 } else if (dbuf[0][j] == STATE_STOPPED) {
9413 if (xs + 2 - gdFontSmall->h > xmaxm) {
9414 gdImageStringUp(im, gdFontSmall, xs + 2 - gdFontSmall->h, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9415 xmaxm = xs - 1;
9416 }
9417 }
9418 }
9419 }
9420
9421 if (num_entries[0]) {
9422 free(tbuf[0]);
9423 free(dbuf[0]);
9424 tbuf[0] = NULL;
9425 dbuf[0] = NULL;
9426 }
9427
9428 if (num_entries[1]) {
9429 free(tbuf[1]);
9430 free(dbuf[1]);
9431 tbuf[1] = NULL;
9432 dbuf[1] = NULL;
9433 }
9434 }
9435
9436 /* write run markes if selected */
9437 if (hp.show_run_markers) {
9438
9439 int index_state = -1;
9440 int index_run_number = -1;
9441
9442 for (int k=0; k<hsdata->nvars; k++) {
9443 if (hsdata->odb_index[k] == -1)
9444 index_state = k;
9445
9446 if (hsdata->odb_index[k] == -2)
9447 index_run_number = k;
9448 }
9449
9450 bool ok = true;
9451
9452 if (ok)
9453 ok = (index_state >= 0) && (index_run_number >= 0);
9454
9455 if (ok)
9456 ok = (hsdata->status[index_state] == HS_SUCCESS);
9457
9458 if (ok)
9459 ok = (hsdata->status[index_run_number] == HS_SUCCESS);
9460
9461 if (/* DISABLES CODE */ (0) && ok)
9462 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]);
9463
9464 if (ok)
9465 ok = (hsdata->num_entries[index_state] == hsdata->num_entries[index_run_number]);
9466
9467 int n_marker = hsdata->num_entries[index_state];
9468
9469 if (ok && n_marker > 0 && n_marker < 100) {
9470 xs_old = -1;
9471 xmaxm = x1;
9472 for (j = 0; j < (int) n_marker; j++) {
9473 int col;
9474
9475 // explicit algebra manipulation to clarify computations:
9476
9477 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9478 //xrange = scale/3600.0;
9479 //time_t starttime = now - scale + toffset;
9480
9481 //x_marker = (int)(tbuf[1][j] - now);
9482 //xs = (int) ((x_marker / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9483 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9484 //xs = (int) (((tbuf[1][j] - now) / 3600.0 - (-scale / 3600.0 + toffset / 3600.0)) / (scale/3600.0) * (x2 - x1) + x1 + 0.5);
9485 //xs = (int) (((tbuf[1][j] - now) - (-scale + toffset)) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9486 xs = (int) ((hsdata->t[index_state][j] - starttime) / (scale/1.0) * (x2 - x1) + x1 + 0.5);
9487
9488 if (xs < x1)
9489 continue;
9490 if (xs >= x2)
9491 continue;
9492
9493 double run_number = hsdata->v[index_run_number][j];
9494
9495 if (xs <= xs_old)
9496 xs = xs_old + 1;
9497 xs_old = xs;
9498
9499 int state = (int)hsdata->v[index_state][j];
9500
9501 if (state == 1)
9502 col = state_col[0];
9503 else if (state == 2)
9504 col = state_col[1];
9505 else if (state == 3)
9506 col = state_col[2];
9507 else
9508 col = state_col[0];
9509
9510 gdImageDashedLine(im, xs, y1, xs, y2, col);
9511
9512 sprintf(str, "%.0f", run_number);
9513
9514 if (state == STATE_RUNNING) {
9515 if (xs > xmaxm) {
9516 gdImageStringUp(im, gdFontSmall, xs + 0, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9517 xmaxm = xs - 2 + gdFontSmall->h;
9518 }
9519 } else if (state == STATE_STOPPED) {
9520 if (xs + 2 - gdFontSmall->h > xmaxm) {
9521 gdImageStringUp(im, gdFontSmall, xs + 2 - gdFontSmall->h, y2 + 2 + gdFontSmall->w * strlen(str), str, fgcol);
9522 xmaxm = xs - 1;
9523 }
9524 }
9525 }
9526 }
9527 }
9528
9529 for (i = 0; i < (int)hp.vars.size(); i++) {
9530 if (index != -1 && index != i)
9531 continue;
9532
9533 /* draw alarm limits */
9534 if (lower_limit[i] != -12345) {
9535 if (logaxis) {
9536 if (lower_limit[i] <= 0)
9537 ys = y1;
9538 else
9539 ys = (int) (y1 - (log(lower_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9540 } else {
9541 ys = (int) (y1 - (lower_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9542 }
9543
9544 if (xs < 0)
9545 xs = 0;
9546 if (xs >= width)
9547 xs = width-1;
9548 if (ys < 0)
9549 ys = 0;
9550 if (ys >= height)
9551 ys = height-1;
9552
9553 if (ys > y2 && ys < y1) {
9554 gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
9555
9556 poly[0].x = x1;
9557 poly[0].y = ys;
9558 poly[1].x = x1 + 5;
9559 poly[1].y = ys;
9560 poly[2].x = x1;
9561 poly[2].y = ys - 5;
9562
9563 gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9564 }
9565 }
9566 if (upper_limit[i] != -12345) {
9567 if (logaxis) {
9568 if (upper_limit[i] <= 0)
9569 ys = y1;
9570 else
9571 ys = (int) (y1 - (log(upper_limit[i]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9572 } else {
9573 ys = (int) (y1 - (upper_limit[i] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9574 }
9575
9576 if (xs < 0)
9577 xs = 0;
9578 if (xs >= width)
9579 xs = width-1;
9580 if (ys < 0)
9581 ys = 0;
9582 if (ys >= height)
9583 ys = height-1;
9584
9585 if (ys > y2 && ys < y1) {
9586 gdImageDashedLine(im, x1, ys, x2, ys, curve_col[i]);
9587
9588 poly[0].x = x1;
9589 poly[0].y = ys;
9590 poly[1].x = x1 + 5;
9591 poly[1].y = ys;
9592 poly[2].x = x1;
9593 poly[2].y = ys + 5;
9594
9595 gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9596 }
9597 }
9598
9599 for (j = 0; j < (int) n_point[i]; j++) {
9600 //xmin = (double) (-scale / 3600.0 + toffset / 3600.0);
9601 //xrange = scale/3600.0;
9602 //xs = (int) (((x[i][j]-now) / 3600.0 - xmin) / xrange * (x2 - x1) + x1 + 0.5);
9603 //xs = (int) (((x[i][j] - now + scale - toffset) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9604 //xs = (int) (((x[i][j] - starttime) / 3600.0) / xrange * (x2 - x1) + x1 + 0.5);
9605 xs = (int) (((x[i][j] - starttime)/1.0) / (1.0*scale) * (x2 - x1) + x1 + 0.5);
9606
9607 if (logaxis) {
9608 if (y[i][j] <= 0)
9609 ys = y1;
9610 else
9611 ys = (int) (y1 - (log(y[i][j]) - log(ymin)) / (log(ymax) - log(ymin)) * (y1 - y2) + 0.5);
9612 } else {
9613 ys = (int) (y1 - (y[i][j] - ymin) / (ymax - ymin) * (y1 - y2) + 0.5);
9614 }
9615
9616 if (xs < 0)
9617 xs = 0;
9618 if (xs >= width)
9619 xs = width-1;
9620 if (ys < 0)
9621 ys = 0;
9622 if (ys >= height)
9623 ys = height-1;
9624
9625 if (j > 0)
9626 gdImageLine(im, xold, yold, xs, ys, curve_col[i]);
9627 xold = xs;
9628 yold = ys;
9629 }
9630
9631 if (n_point[i] > 0) {
9632 poly[0].x = xs;
9633 poly[0].y = ys;
9634 poly[1].x = xs + 12;
9635 poly[1].y = ys - 6;
9636 poly[2].x = xs + 12;
9637 poly[2].y = ys + 6;
9638
9639 gdImageFilledPolygon(im, poly, 3, curve_col[i]);
9640 }
9641 }
9642
9643 if (labels) {
9644 for (i = 0; i < (int)hp.vars.size(); i++) {
9645 if (index != -1 && index != i)
9646 continue;
9647
9648 //str[0] = 0;
9649 //status = db_find_key(hDB, hkeypanel, "Label", &hkeydvar);
9650 //if (status == DB_SUCCESS) {
9651 // size = sizeof(str);
9652 // status = db_get_data_index(hDB, hkeydvar, str, &size, i, TID_STRING);
9653 //}
9654
9655 std::string str = hp.vars[i].label.c_str();
9656
9657 if (str.empty()) {
9658 if (hp.enable_factor) {
9659 str = hp.vars[i].tag_name;
9660
9661 if (hp.vars[i].voffset > 0)
9662 str += msprintf(" - %G", hp.vars[i].voffset);
9663 else if (hp.vars[i].voffset < 0)
9664 str += msprintf(" + %G", -hp.vars[i].voffset);
9665
9666 if (hp.vars[i].factor != 1) {
9667 if (hp.vars[i].voffset == 0)
9668 str += msprintf(" * %+G", hp.vars[i].factor);
9669 else {
9670 str = msprintf("(%s) * %+G", str.c_str(), hp.vars[i].factor);
9671 }
9672 }
9673
9674 if (hp.vars[i].offset > 0)
9675 str += msprintf(" + %G", hp.vars[i].offset);
9676 else if (hp.vars[i].offset < 0)
9677 str += msprintf(" - %G", -hp.vars[i].offset);
9678
9679 } else {
9680 str = hp.vars[i].tag_name;
9681 }
9682 }
9683
9684 int k=0;
9685 for (int j=0; j<hsdata->nvars; j++)
9686 if (hsdata->odb_index[j] == i) {
9687 k = j;
9688 break;
9689 }
9690
9691 if (/* DISABLES CODE */ (0)) {
9692 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]);
9693 }
9694
9695 if (hp.show_values) {
9696 char xstr[256];
9697 if (n_point[i] > 0) {
9698 sprintf(xstr," = %g", y[i][n_point[i]-1]);
9699 } else if (hsdata->num_entries[k] > 0) {
9700 sprintf(xstr," = all data is NaN or INF");
9701 } else if (hsdata->have_last_written) {
9702 if (hsdata->last_written[k]) {
9703 char ctimebuf[32];
9704 ctime_r(&hsdata->last_written[k], ctimebuf);
9705 sprintf(xstr," = last data %s", ctimebuf);
9706 // kill trailing '\n'
9707 char*s = strchr(xstr, '\n');
9708 if (s) *s=0;
9709 // clear the unnecessary error status report
9710 if (hsdata->status[k] == HS_UNDEFINED_VAR)
9711 var_status[i][0] = 0;
9712 } else {
9713 sprintf(xstr," = no data ever");
9714 }
9715 } else {
9716 sprintf(xstr," = no data");
9717 }
9718 str += xstr;
9719 }
9720
9721 if (strlen(var_status[i]) > 1) {
9722 str += msprintf(" (%s)", var_status[i]);
9723 }
9724
9725 row = index == -1 ? i : 0;
9726
9728 x1 + 10,
9729 y2 + 10 + row * (gdFontMediumBold->h + 10),
9730 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9731 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9732 gdFontMediumBold->h + 2 + 2, white);
9733 gdImageRectangle(im, x1 + 10, y2 + 10 + row * (gdFontMediumBold->h + 10),
9734 x1 + 10 + str.length() * gdFontMediumBold->w + 10,
9735 y2 + 10 + row * (gdFontMediumBold->h + 10) +
9736 gdFontMediumBold->h + 2 + 2, curve_col[i]);
9737
9739 x1 + 10 + 5, y2 + 10 + 2 + row * (gdFontMediumBold->h + 10),
9740 (char*)str.c_str(),
9741 curve_col[i]);
9742 }
9743 }
9744
9745 gdImageRectangle(im, x1, y2, x2, y1, fgcol);
9746
9747 error:
9748
9749 /* generate GIF */
9750 gdImageInterlace(im, 1);
9751 gdImageGif(im, &gb);
9752 gdImageDestroy(im);
9753 length = gb.size;
9754
9755 if (buffer == NULL) {
9756 rr->rsprintf("HTTP/1.1 200 Document follows\r\n");
9757 rr->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
9758
9759 rr->rsprintf("Content-Type: image/gif\r\n");
9760 rr->rsprintf("Content-Length: %d\r\n", length);
9761 rr->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
9762 rr->rsprintf("Expires: Fri, 01-Jan-1983 00:00:00 GMT\r\n\r\n");
9763
9764 rr->rmemcpy(gb.data, length);
9765 } else {
9766 if (length > *buffer_size) {
9767 printf("return buffer too small\n");
9768 return;
9769 }
9770
9771 memcpy(buffer, gb.data, length);
9772 *buffer_size = length;
9773 }
9774}
9775
9776/*------------------------------------------------------------------*/
9777
9778time_t mktime_with_dst(const struct tm* ptms)
9779{
9780 // this silly stuff is required to correctly handle daylight savings time (Summer time/Winter time)
9781 // when we fill "struct tm" from user input, we cannot know if daylight savings time is in effect
9782 // and we do not know how to initialize the value of tms.tm_isdst.
9783 // This can cause the output of mktime() to be off by one hour.
9784 // (Rules for daylight savings time are set by national and local govt and in some locations, changes yearly)
9785 // (There are no locations with 2 hour or half-hour daylight savings that I know of)
9786 // (Yes, "man mktime" talks about using "tms.tm_isdst = -1")
9787 //
9788 // We assume the user is using local time and we convert in two steps:
9789 //
9790 // first we convert "struct tm" to "time_t" using mktime() with unknown tm_isdst
9791 // second we convert "time_t" back to "struct tm" using localtime_r()
9792 // this fills "tm_isdst" with correct value from the system time zone database
9793 // then we reset all the time fields (except for sub-minute fields not affected by daylight savings)
9794 // and call mktime() again, now with the correct value of "tm_isdst".
9795 // K.O. 2013-09-14
9796
9797 struct tm tms = *ptms;
9798 struct tm tms2;
9799 time_t t1 = ss_mktime(&tms);
9800 localtime_r(&t1, &tms2);
9801 tms2.tm_year = ptms->tm_year;
9802 tms2.tm_mon = ptms->tm_mon;
9803 tms2.tm_mday = ptms->tm_mday;
9804 tms2.tm_hour = ptms->tm_hour;
9805 tms2.tm_min = ptms->tm_min;
9806 time_t t2 = ss_mktime(&tms2);
9807 //printf("t1 %.0f, t2 %.0f, diff %d\n", (double)t1, (double)t2, (int)(t1-t2));
9808 return t2;
9809}
9810
9811/*------------------------------------------------------------------*/
9812
9813static std::string add_param_to_url(const char* name, const char* value)
9814{
9815 std::string s;
9816 s += name; // FIXME: should be URI-encoded
9817 s += "=";
9818 s += value; // FIXME: should be URI-encoded
9819 return s;
9820}
9821
9822/*------------------------------------------------------------------*/
9823
9825{
9826 int i;
9827 HNDLE hDB;
9828
9829 if (p->getparam("m1") && *p->getparam("m1")) {
9830 struct tm tms;
9831 memset(&tms, 0, sizeof(struct tm));
9832
9833 tms.tm_year = atoi(p->getparam("y1")) % 100;
9834
9835 std::string m1 = p->getparam("m1");
9836 for (i = 0; i < 12; i++)
9837 if (equal_ustring(m1.c_str(), mname[i]))
9838 break;
9839 if (i == 12)
9840 i = 0;
9841
9842 tms.tm_mon = i;
9843 tms.tm_mday = atoi(p->getparam("d1"));
9844 tms.tm_hour = atoi(p->getparam("h1"));
9845
9846 if (tms.tm_year < 90)
9847 tms.tm_year += 100;
9848
9849 time_t ltime_start = mktime_with_dst(&tms);
9850
9851 memset(&tms, 0, sizeof(struct tm));
9852 tms.tm_year = atoi(p->getparam("y2")) % 100;
9853
9854 std::string m2 = p->getparam("m2");
9855 for (i = 0; i < 12; i++)
9856 if (equal_ustring(m2.c_str(), mname[i]))
9857 break;
9858 if (i == 12)
9859 i = 0;
9860
9861 tms.tm_mon = i;
9862 tms.tm_mday = atoi(p->getparam("d2"));
9863 tms.tm_hour = atoi(p->getparam("h2"));
9864
9865 if (tms.tm_year < 90)
9866 tms.tm_year += 100;
9867
9868 time_t ltime_end = mktime_with_dst(&tms);
9869
9870 if (ltime_end == ltime_start)
9871 ltime_end += 3600 * 24;
9872
9873 std::string redir;
9874 redir += "?cmd=oldhistory&";
9875 redir += add_param_to_url("group", p->getparam("group"));
9876 redir += "&";
9877 redir += add_param_to_url("panel", p->getparam("panel"));
9878 redir += "&";
9879 redir += add_param_to_url("scale", toString((int)(ltime_end - ltime_start)).c_str());
9880 redir += "&";
9881 redir += add_param_to_url("time", time_to_string(ltime_end).c_str());
9882 if (p->isparam("hindex")) {
9883 redir += "&";
9884 redir += add_param_to_url("index", p->getparam("hindex"));
9885 }
9886 redirect(r, redir.c_str());
9887 return;
9888 }
9889
9891 show_header(r, "History", "GET", "", 0);
9892
9893 /* set the times */
9894
9895 time_t now = time(NULL);
9896
9897 time_t starttime = now - 3600 * 24;
9898 time_t endtime = now;
9899 bool full_day = true;
9900
9901 if (p->isparam("htime")) {
9902 endtime = string_to_time(p->getparam("htime"));
9903
9904 if (p->isparam("hscale")) {
9905 starttime = endtime - atoi(p->getparam("hscale"));
9906 full_day = false;
9907 } else {
9908 starttime = endtime - 3600 * 24;
9909 full_day = false;
9910 }
9911 }
9912
9913 /* menu buttons */
9914 r->rsprintf("<tr><td colspan=2>\n");
9915 r->rsprintf("<input type=hidden name=cmd value=OldHistory>\n");
9916 r->rsprintf("<input type=submit name=hcmd value=Query>\n");
9917 r->rsprintf("<input type=submit name=hcmd value=Cancel>\n");
9918 if (p->isparam("group"))
9919 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", p->getparam("group"));
9920 if (p->isparam("panel"))
9921 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", p->getparam("panel"));
9922 if (p->isparam("htime"))
9923 r->rsprintf("<input type=hidden name=htime value=\"%s\">\n", p->getparam("htime"));
9924 if (p->isparam("hscale"))
9925 r->rsprintf("<input type=hidden name=hscale value=\"%s\">\n", p->getparam("hscale"));
9926 if (p->isparam("hindex"))
9927 r->rsprintf("<input type=hidden name=hindex value=\"%s\">\n", p->getparam("hindex"));
9928 r->rsprintf("</tr>\n\n");
9929 r->rsprintf("</table>"); //end header
9930
9931 r->rsprintf("<table class=\"dialogTable\">"); //main table
9932
9933 struct tm tms;
9934 localtime_r(&starttime, &tms);
9935 tms.tm_year += 1900;
9936
9937 r->rsprintf("<tr><td nowrap>Start date:</td>");
9938
9939 r->rsprintf("<td>Month: <select name=\"m1\">\n");
9940 r->rsprintf("<option value=\"\">\n");
9941 for (i = 0; i < 12; i++)
9942 if (i == tms.tm_mon)
9943 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9944 else
9945 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9946 r->rsprintf("</select>\n");
9947
9948 r->rsprintf("&nbsp;Day: <select name=\"d1\">");
9949 r->rsprintf("<option selected value=\"\">\n");
9950 for (i = 0; i < 31; i++)
9951 if (i + 1 == tms.tm_mday)
9952 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9953 else
9954 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9955 r->rsprintf("</select>\n");
9956
9957 int start_hour = tms.tm_hour;
9958 if (full_day)
9959 start_hour = 0;
9960
9961 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h1\" value=\"%d\">", start_hour);
9962
9963 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y1\" value=\"%d\">", tms.tm_year);
9964 r->rsprintf("</td></tr>\n");
9965
9966 r->rsprintf("<tr><td nowrap>End date:</td>");
9967
9968 localtime_r(&endtime, &tms);
9969 tms.tm_year += 1900;
9970
9971 r->rsprintf("<td>Month: <select name=\"m2\">\n");
9972 r->rsprintf("<option value=\"\">\n");
9973 for (i = 0; i < 12; i++)
9974 if (i == tms.tm_mon)
9975 r->rsprintf("<option selected value=\"%s\">%s\n", mname[i], mname[i]);
9976 else
9977 r->rsprintf("<option value=\"%s\">%s\n", mname[i], mname[i]);
9978 r->rsprintf("</select>\n");
9979
9980 r->rsprintf("&nbsp;Day: <select name=\"d2\">");
9981 r->rsprintf("<option selected value=\"\">\n");
9982 for (i = 0; i < 31; i++)
9983 if (i + 1 == tms.tm_mday)
9984 r->rsprintf("<option selected value=%d>%d\n", i + 1, i + 1);
9985 else
9986 r->rsprintf("<option value=%d>%d\n", i + 1, i + 1);
9987 r->rsprintf("</select>\n");
9988
9989 int end_hour = tms.tm_hour;
9990 if (full_day)
9991 end_hour = 24;
9992
9993 r->rsprintf("&nbsp;Hour: <input type=\"text\" size=5 maxlength=5 name=\"h2\" value=\"%d\">", end_hour);
9994
9995 r->rsprintf("&nbsp;Year: <input type=\"text\" size=5 maxlength=5 name=\"y2\" value=\"%d\">", tms.tm_year);
9996 r->rsprintf("</td></tr>\n");
9997
9998 r->rsprintf("</table>\n");
9999 r->rsprintf("</div>\n"); // closing for <div id="mmain">
10000 r->rsprintf("</form>\n");
10001 r->rsprintf("</body></html>\r\n");
10002}
10003
10004/*------------------------------------------------------------------*/
10005/* history plot code starts here */
10006/*------------------------------------------------------------------*/
10007
10008static int cmp_names(const void *a, const void *b)
10009{
10010 int i;
10011 const char*sa = (const char*)a;
10012 const char*sb = (const char*)b;
10013
10014 int debug = 0;
10015
10016 // Cannot use strcmp() because it does not know how to compare numerical values, e.g.
10017 // it thinks "111" is smaller than "9"
10018 //return strcmp(sa, sb);
10019
10020 if (debug)
10021 printf("compare [%s] and [%s]\n", sa, sb);
10022
10023 for (i=0; ; i++) {
10024 if (sa[i]==0 && sb[i]==0)
10025 return 0; // both strings have the same length and the same characters
10026
10027 //printf("index %d, char [%c] [%c], isdigit %d %d\n", i, sa[i], sb[i], isdigit(sa[i]), isdigit(sb[i]));
10028
10029 if (isdigit(sa[i]) && isdigit(sb[i])) {
10030 int va = atoi(sa+i);
10031 int vb = atoi(sb+i);
10032
10033 if (debug)
10034 printf("index %d, values %d %d\n", i, va, vb);
10035
10036 if (va < vb)
10037 return -1;
10038 else if (va > vb)
10039 return 1;
10040
10041 // values are equal, skip the the end of the digits, compare any trailing text
10042 continue;
10043 }
10044
10045 if (sa[i]==sb[i]) {
10046 continue;
10047 }
10048
10049 if (debug)
10050 printf("index %d, char [%c] [%c]\n", i, sa[i], sb[i]);
10051
10052 if (sa[i] == 0) // string sa is shorter
10053 return -1;
10054 else if (sb[i] == 0) // string sb is shorter
10055 return 1;
10056
10057 if (sa[i]<sb[i])
10058 return -1;
10059 else
10060 return 1;
10061 }
10062
10063 // NOT REACHED
10064}
10065
10066const bool cmp_events(const std::string& a, const std::string& b)
10067{
10068 return cmp_names(a.c_str(), b.c_str()) < 0;
10069}
10070
10071const bool cmp_events1(const std::string& a, const std::string& b)
10072{
10073 return a < b;
10074}
10075
10076const bool cmp_tags(const TAG& a, const TAG& b)
10077{
10078 return cmp_names(a.name, b.name) < 0;
10079}
10080
10081#if 0
10082static int cmp_tags(const void *a, const void *b)
10083{
10084 const TAG*sa = (const TAG*)a;
10085 const TAG*sb = (const TAG*)b;
10086 return cmp_names(sa->name, sb->name);
10087}
10088
10089static void sort_tags(int ntags, TAG* tags)
10090{
10091 qsort(tags, ntags, sizeof(TAG), cmp_tags);
10092}
10093#endif
10094
10095int xdb_get_data_index(HNDLE hDB, const char* str, void *value, int size, int index, int tid)
10096{
10097 HNDLE hKey;
10098 int status = db_find_key(hDB, 0, str, &hKey);
10099 if (status != DB_SUCCESS)
10100 return status;
10101
10102 KEY key;
10103 db_get_key(hDB, hKey, &key);
10104 if (index >= key.num_values)
10105 return DB_OUT_OF_RANGE;
10106
10107 status = db_get_data_index(hDB, hKey, value, &size, index, tid);
10108 return status;
10109}
10110
10111static int xdb_find_key(HNDLE hDB, HNDLE dir, const char* str, HNDLE* hKey, int tid, int size)
10112{
10113 int status = db_find_key(hDB, dir, str, hKey);
10114 if (status == DB_SUCCESS)
10115 return status;
10116
10117 db_create_key(hDB, dir, str, tid);
10118 status = db_find_key(hDB, dir, str, hKey);
10119 if (status != DB_SUCCESS || !*hKey) {
10120 cm_msg(MERROR, "xdb_find_key", "Invalid ODB path \"%s\"", str);
10121 str = "bad_xdb_find_key";
10122 db_create_key(hDB, dir, str, tid);
10123 db_find_key(hDB, dir, str, hKey);
10124 }
10125 assert(*hKey);
10126
10127 if (tid == TID_STRING) {
10128 db_set_data_index(hDB, *hKey, "", size, 0, TID_STRING);
10129 }
10130
10131 return status;
10132}
10133
10134static bool cmp_vars(const HistVar &a, const HistVar &b)
10135{
10136 return a.order < b.order;
10137}
10138
10139static void PrintHistPlot(const HistPlot& hp)
10140{
10141 printf("hist plot: %d variables\n", (int)hp.vars.size());
10142 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);
10143
10144 for (size_t i=0; i<hp.vars.size(); i++) {
10145 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);
10146 }
10147}
10148
10149static std::string NextHistPlotColour(const HistPlot& hp)
10150{
10151 const char* const colour[] =
10152 {
10153 "#00AAFF", "#FF9000", "#FF00A0", "#00C030",
10154 "#A0C0D0", "#D0A060", "#C04010", "#807060",
10155 "#F0C000", "#2090A0", "#D040D0", "#90B000",
10156 "#B0B040", "#B0B0FF", "#FFA0A0", "#A0FFA0",
10157 NULL };
10158
10159 for (int i=0; colour[i]; i++) {
10160 bool in_use = false;
10161
10162 for (size_t j=0; j<hp.vars.size(); j++)
10163 if (hp.vars[j].colour == colour[i]) {
10164 in_use = true;
10165 break;
10166 }
10167
10168 if (!in_use)
10169 return colour[i];
10170 }
10171
10172 return "#808080";
10173}
10174
10175static int NextHistPlotOrder(const HistPlot& hp)
10176{
10177 int order = 0;
10178 for (size_t i=0; i<hp.vars.size(); i++)
10179 if (hp.vars[i].order > order)
10180 order = hp.vars[i].order;
10181 return order + 10;
10182}
10183
10184static void SplitEventAndTagNames(std::string var_name, std::string& event_name, std::string& tag_name) {
10185 event_name = "";
10186 tag_name = "";
10187
10188 std::vector<size_t> colons;
10189
10190 for (size_t i = 0; i < var_name.size(); i++) {
10191 if (var_name[i] == ':') {
10192 colons.push_back(i);
10193 }
10194 }
10195
10196 if (colons.size() == 0) {
10197 // No colons - leave the tag name empty
10198 event_name = var_name;
10199 } else {
10200 size_t split_pos;
10201 size_t slash_pos = var_name.find("/");
10202 bool uses_per_variable_naming = (slash_pos != std::string::npos);
10203
10204 if (uses_per_variable_naming && colons.size() % 2 == 1) {
10205 size_t middle_colon_pos = colons[colons.size() / 2];
10206 std::string slash_to_mid = var_name.substr(slash_pos + 1, middle_colon_pos - slash_pos - 1);
10207 std::string mid_to_end = var_name.substr(middle_colon_pos + 1);
10208
10209 if (slash_to_mid == mid_to_end) {
10210 // Special case - we have a string of the form Beamlime/GS2:FC1:GS2:FC1.
10211 // Logger has already warned people that having colons in the equipment/event
10212 // names is a bad idea, so we only need to worry about them in the tag name.
10213 split_pos = middle_colon_pos;
10214 } else {
10215 // We have a string of the form Beamlime/Demand:GS2:FC1. Split at the first colon.
10216 split_pos = colons[0];
10217 }
10218 } else {
10219 // Normal case - split at the fist colon.
10220 split_pos = colons[0];
10221 }
10222
10223 event_name = var_name.substr(0, split_pos);
10224 tag_name = var_name.substr(split_pos + 1);
10225 }
10226}
10227
10228static void LoadHistPlotFromOdb(MVOdb* odb, HistPlot* hp, const char* group, const char* panel)
10229{
10230 std::string path = "History/Display/";
10231 path += group;
10232 path += "/";
10233 path += panel;
10234
10235 MVOdb* o = odb->Chdir(path.c_str());
10236 if (!o) {
10237 return;
10238 }
10239
10240 o->RS("Timescale", &hp->timescale);
10241 o->RD("Minimum", &hp->minimum);
10242 o->RD("Maximum", &hp->maximum);
10243 o->RB("Zero ylow", &hp->zero_ylow);
10244 o->RB("Log axis", &hp->log_axis);
10245 o->RB("Zero ylow", &hp->zero_ylow);
10246 o->RB("Show run markers", &hp->show_run_markers);
10247 o->RB("Show values", &hp->show_values);
10248 o->RB("Show fill", &hp->show_fill);
10249 o->RB("Show factor", &hp->show_factor);
10250 //o->RB("Enable factor and offset", &hp->enable_factor);
10251
10252 std::vector<std::string> hist_vars;
10253 std::vector<std::string> hist_formula;
10254 std::vector<std::string> hist_colour;
10255 std::vector<std::string> hist_label;
10256 std::vector<bool> hist_show_raw_value;
10257 std::vector<double> hist_factor;
10258 std::vector<double> hist_offset;
10259 std::vector<double> hist_voffset;
10260
10261 o->RSA("Variables", &hist_vars);
10262 o->RSA("Formula", &hist_formula);
10263 o->RSA("Colour", &hist_colour);
10264 o->RSA("Label", &hist_label);
10265 o->RBA("Show raw value", &hist_show_raw_value);
10266 o->RDA("Factor", &hist_factor);
10267 o->RDA("Offset", &hist_offset);
10268 o->RDA("VOffset", &hist_voffset);
10269
10270 // fix broken plots with "factor" all zero. for reasons
10271 // unknown the new history code has corrupted many
10272 // history plot definitions like this. K.O.
10273 {
10274 bool all_zero = true;
10275 for (size_t i=0; i<hist_factor.size(); i++) {
10276 if (hist_factor[i] != 0)
10277 all_zero = false;
10278 }
10279 if (all_zero) {
10280 for (size_t i=0; i<hist_factor.size(); i++) {
10281 hist_factor[i] = 1.0;
10282 }
10283 }
10284 }
10285
10286 size_t num = std::max(hist_vars.size(), hist_formula.size());
10287 num = std::max(num, hist_colour.size());
10288 num = std::max(num, hist_label.size());
10289 num = std::max(num, hist_show_raw_value.size());
10290 num = std::max(num, hist_factor.size());
10291 num = std::max(num, hist_offset.size());
10292 num = std::max(num, hist_voffset.size());
10293
10294 hist_vars.resize(num);
10295 hist_formula.resize(num);
10296 hist_colour.resize(num);
10297 hist_label.resize(num);
10298 hist_show_raw_value.resize(num);
10299 hist_factor.resize(num, 1.0);
10300 hist_offset.resize(num, 0.0);
10301 hist_voffset.resize(num, 0.0);
10302
10303 for (size_t i=0; i<num; i++) {
10304 HistVar v;
10305
10306 SplitEventAndTagNames(hist_vars[i], v.event_name, v.tag_name);
10307
10308 v.formula = hist_formula[i];
10309 v.colour = hist_colour[i];
10310 v.label = hist_label[i];
10311 v.show_raw_value = hist_show_raw_value[i];
10312 v.factor = hist_factor[i];
10313 v.offset = hist_offset[i];
10314 v.voffset = hist_voffset[i];
10315 v.order = NextHistPlotOrder(*hp);
10316
10317 // one-time migration of factor and offset to formula
10318 if (hp->enable_factor && v.formula.empty()) {
10319 if (v.factor!=1 || v.offset!=0 || v.voffset!=0) {
10320 v.formula = msprintf("%g%+g*(x%+g)", v.offset, v.factor, -v.voffset);
10321 }
10322 }
10323
10324 hp->vars.push_back(v);
10325 }
10326
10327// printf("Load from ODB %s: ", path.c_str());
10328// PrintHistPlot(*hp);
10329
10330 delete o;
10331}
10332
10334{
10335 hp->timescale = p->getparam("timescale");
10336 hp->minimum = strtod(p->getparam("minimum"), NULL);
10337 hp->maximum = strtod(p->getparam("maximum"), NULL);
10338 hp->zero_ylow = *p->getparam("zero_ylow");
10339 hp->log_axis = *p->getparam("log_axis");
10340 hp->show_run_markers = *p->getparam("run_markers");
10341 hp->show_values = *p->getparam("show_values");
10342 hp->show_fill = *p->getparam("show_fill");
10343 hp->show_factor = *p->getparam("show_factor");
10344 //hp->enable_factor = *p->getparam("enable_factor");
10345
10346 for (int index=0; ; index++) {
10347 char str[256];
10348 sprintf(str, "event%d", index);
10349
10350 //printf("param event %d: [%s] [%s] [%d]\n", index, str, p->getparam(str), *p->getparam(str));
10351
10352 if (!p->isparam(str))
10353 break;
10354
10355 if (*p->getparam(str) == '/') // "/empty"
10356 continue;
10357
10358 HistVar v;
10359
10360 v.event_name = p->xgetparam(str);
10361
10362 sprintf(str, "var%d", index);
10363 v.tag_name = p->xgetparam(str);
10364
10365 sprintf(str, "form%d", index);
10366 v.formula = p->xgetparam(str);
10367
10368 sprintf(str, "col%d", index);
10369 v.colour = p->xgetparam(str);
10370
10371 sprintf(str, "lab%d", index);
10372 v.label = p->xgetparam(str);
10373
10374 sprintf(str, "raw%d", index);
10375 v.show_raw_value = atoi(p->xgetparam(str).c_str());
10376
10377 sprintf(str, "factor%d", index);
10378 if (p->isparam(str)) {
10379 v.factor = atof(p->xgetparam(str).c_str());
10380 } else {
10381 v.factor = 1.0;
10382 }
10383
10384 sprintf(str, "offset%d", index);
10385 v.offset = atof(p->xgetparam(str).c_str());
10386
10387 sprintf(str, "voffset%d", index);
10388 v.voffset = atof(p->xgetparam(str).c_str());
10389
10390 sprintf(str, "ord%d", index);
10391 if (p->isparam(str)) {
10392 v.order = atoi(p->xgetparam(str).c_str());
10393 } else {
10394 v.order = NextHistPlotOrder(*hp);
10395 }
10396
10397 hp->vars.push_back(v);
10398 }
10399
10400 /* correctly number newly added variables */
10401 for (size_t index=0; index<hp->vars.size(); index++) {
10402 if (hp->vars[index].order < 0)
10403 hp->vars[index].order = NextHistPlotOrder(*hp);
10404 }
10405
10406// printf("Load from param:\n");
10407// PrintHistPlot(*hp);
10408}
10409
10411{
10412 int seln = atoi(p->getparam("seln"));
10413 for (int i=0; i<seln; i++) {
10414 char str[256];
10415 sprintf(str, "sel%d", i);
10416
10417 std::string par = p->getparam(str);
10418 if (par.length() < 1)
10419 continue;
10420
10421 std::string event_name, tag_name;
10422 SplitEventAndTagNames(par, event_name, tag_name);
10423
10424 if (tag_name == "")
10425 continue;
10426
10427 HistVar v;
10428
10429 v.event_name = event_name;
10430 v.tag_name = tag_name;
10431 v.colour = NextHistPlotColour(hp);
10432 v.order = NextHistPlotOrder(hp);
10433
10434 hp.vars.push_back(v);
10435 }
10436}
10437
10438static void SaveHistPlotToOdb(MVOdb* odb, const HistPlot& hp, const char* group, const char* panel)
10439{
10440 if (strlen(group) < 1) {
10441 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid group name", group, panel);
10442 return;
10443 }
10444
10445 if (strlen(panel) < 1) {
10446 cm_msg(MERROR, "SaveHistPlotToOdb", "Error: Cannot write history plot to ODB, group \"%s\", panel \"%s\", invalid panel name", group, panel);
10447 return;
10448 }
10449
10450 std::string path = "History/Display/";
10451 path += group;
10452 path += "/";
10453 path += panel;
10454
10455// printf("Save to ODB %s: ", path.c_str());
10456// PrintHistPlot(hp);
10457
10458 MVOdb* o = odb->Chdir(path.c_str(), true);
10459
10460 o->WS("Timescale", hp.timescale.c_str());
10461 o->WD("Minimum", hp.minimum);
10462 o->WD("Maximum", hp.maximum);
10463 o->WB("Zero ylow", hp.zero_ylow);
10464 o->WB("Log axis", hp.log_axis);
10465 o->WB("Show run markers", hp.show_run_markers);
10466 o->WB("Show values", hp.show_values);
10467 o->WB("Show fill", hp.show_fill);
10468 o->WB("Show factor and offset", hp.show_factor);
10469 //o->WB("Enable factor and offset", hp.enable_factor);
10470
10471 std::vector<std::string> hist_vars;
10472 std::vector<std::string> hist_formula;
10473 std::vector<std::string> hist_colour;
10474 std::vector<std::string> hist_label;
10475 std::vector<bool> hist_show_raw_value;
10476 std::vector<double> hist_factor;
10477 std::vector<double> hist_offset;
10478 std::vector<double> hist_voffset;
10479
10480 for (size_t i=0; i<hp.vars.size(); i++) {
10481 hist_vars.push_back(hp.vars[i].event_name + ":" + hp.vars[i].tag_name);
10482 hist_formula.push_back(hp.vars[i].formula);
10483 hist_colour.push_back(hp.vars[i].colour);
10484 hist_label.push_back(hp.vars[i].label);
10485 hist_show_raw_value.push_back(hp.vars[i].show_raw_value);
10486 hist_factor.push_back(hp.vars[i].factor);
10487 hist_offset.push_back(hp.vars[i].offset);
10488 hist_voffset.push_back(hp.vars[i].voffset);
10489 }
10490
10491 if (hp.vars.size() > 0) {
10492 o->WSA("Variables", hist_vars, 64);
10493 o->WSA("Formula", hist_formula, 64);
10494 o->WSA("Colour", hist_colour, NAME_LENGTH);
10495 o->WSA("Label", hist_label, NAME_LENGTH);
10496 o->WBA("Show raw value", hist_show_raw_value);
10497 o->WDA("Factor", hist_factor);
10498 o->WDA("Offset", hist_offset);
10499 o->WDA("VOffset", hist_voffset);
10500 } else {
10501 o->Delete("Variables");
10502 o->Delete("Formula");
10503 o->Delete("Colour");
10504 o->Delete("Label");
10505 o->Delete("Show raw value");
10506 o->Delete("Factor");
10507 o->Delete("Offset");
10508 o->Delete("VOffset");
10509 }
10510
10511 delete o;
10512}
10513
10515{
10516 /* delete variables according to "hist_order" */
10517
10518 while (1) {
10519 bool something_deleted = false;
10520 for (unsigned i=0; i<hp.vars.size(); i++) {
10521 if (hp.vars[i].order <= 0) {
10522 hp.vars.erase(hp.vars.begin() + i);
10523 something_deleted = true;
10524 }
10525 }
10526 if (!something_deleted)
10527 break;
10528 }
10529}
10530
10532{
10533 /* sort variables according to "hist_order" */
10534
10535 bool need_sort = false;
10536 for (size_t i=1; i<hp.vars.size(); i++) {
10537 if (hp.vars[i-1].order >= hp.vars[i].order) {
10538 need_sort = true;
10539 }
10540 }
10541
10542 if (need_sort) {
10543 /* sort variables by order */
10544 std::sort(hp.vars.begin(), hp.vars.end(), cmp_vars);
10545
10546 /* renumber the variables according to the new sorted order */
10547 for (size_t index=0; index<hp.vars.size(); index++)
10548 hp.vars[index].order = (index+1)*10;
10549 }
10550}
10551
10552void show_hist_config_page(MVOdb* odb, Param* p, Return* r, const char *hgroup, const char *hpanel)
10553{
10554 int status;
10555 int max_display_events = 20;
10556 int max_display_tags = 200;
10557 char str[256], hcmd[256];
10558
10559 odb->RI("History/MaxDisplayEvents", &max_display_events, true);
10560 odb->RI("History/MaxDisplayTags", &max_display_tags, true);
10561
10562 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
10563
10564 if (equal_ustring(hcmd, "Clear history cache")) {
10565 //printf("clear history cache!\n");
10566 strcpy(hcmd, "Refresh");
10568 if (mh)
10569 mh->hs_clear_cache();
10570 }
10571
10572 //printf("cmd [%s]\n", cmd);
10573 //printf("cmdx [%s]\n", p->getparam("cmdx"));
10574
10575 HistPlot hp;
10576
10577 if (equal_ustring(hcmd, "refresh") || equal_ustring(hcmd, "save")) {
10578 LoadHistPlotFromParam(&hp, p);
10580 } else {
10581 LoadHistPlotFromOdb(odb, &hp, hgroup, hpanel);
10582 }
10583
10584 SortHistPlotVars(hp);
10585
10586 if (strlen(p->getparam("seln")) > 0)
10588
10589 //hp->Print();
10590
10591 if (hcmd[0] && equal_ustring(hcmd, "save")) {
10592 SaveHistPlotToOdb(odb, hp, hgroup, hpanel);
10593
10594 if (p->getparam("redir") && *p->getparam("redir"))
10595 redirect(r, p->getparam("redir"));
10596 else {
10597 sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
10598 redirect(r, str);
10599 }
10600 return;
10601 }
10602
10603 show_header(r, "History Config", "GET", "", 0);
10604 r->rsprintf("</table>"); //close header table
10605
10606 r->rsprintf("<table class=\"mtable\">"); //open main table
10607
10608 r->rsprintf("<tr><th colspan=11 class=\"subStatusTitle\">History Panel \"%s\" / \"%s\"</th></tr>\n", hgroup, hpanel);
10609
10610 /* menu buttons */
10611 r->rsprintf("<tr><td colspan=11>\n");
10612
10613 r->rsprintf("<input type=button value=Refresh ");
10614 r->rsprintf("onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">\n");
10615
10616 r->rsprintf("<input type=button value=Save ");
10617 r->rsprintf("onclick=\"document.form1.hcmd.value='Save';document.form1.submit()\">\n");
10618
10619 {
10620 r->rsprintf("<input type=button value=Cancel ");
10621 std::string url = "?cmd=oldhistory&group=";
10622 url += hgroup;
10623 url += "&panel=";
10624 url += hpanel;
10625 url += "&hcmd=Cancel";
10626 if (p->getparam("redir")) {
10627 url += "&redir=";
10628 url += urlEncode(p->getparam("redir"));
10629 }
10630 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10631 }
10632 {
10633 r->rsprintf("<input type=button value=\"Edit in ODB\"");
10634 std::string url = "?cmd=odb&odb_path=";
10635 url += "/History/Display/";
10636 url += urlEncode(hgroup);
10637 url += "/";
10638 url += urlEncode(hpanel);
10639 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10640 }
10641 {
10642 r->rsprintf("<input type=button value=\"Edit in new editor\"");
10643 std::string url = "?cmd=hs_edit";
10644 url += "&group=";
10645 url += urlEncode(hgroup);
10646 url += "&panel=";
10647 url += urlEncode(hpanel);
10648 if (p->getparam("redir")) {
10649 url += "&redir=";
10650 url += urlEncode(p->getparam("redir"));
10651 }
10652 r->rsprintf("onclick=\"window.location.search='%s'\">\n", url.c_str());
10653 }
10654 r->rsprintf("<input type=button value=\"Clear history cache\"");
10655 r->rsprintf("onclick=\"document.form1.hcmd.value='Clear history cache';document.form1.submit()\">\n");
10656 r->rsprintf("<input type=button value=\"Delete panel\"");
10657 r->rsprintf("onclick=\"window.location.search='?cmd=oldhistory&group=%s&panel=%s&hcmd=Delete%%20panel'\">\n", hgroup, hpanel);
10658 r->rsprintf("</td></tr>\n");
10659
10660 r->rsprintf("<tr><td colspan=11>\n");
10661
10662 /* sort_vars */
10663 int sort_vars = *p->getparam("sort_vars");
10664 r->rsprintf("<input type=checkbox %s name=sort_vars value=1 onclick=\"this.form.submit();\">Sort variable names", sort_vars?"checked":"");
10665
10666 /* old_vars */
10667 int old_vars = *p->getparam("old_vars");
10668 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":"");
10669
10670 if (hp.show_factor)
10671 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10672 else
10673 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_factor value=1 onclick=\"document.form1.hcmd.value='Refresh';document.form1.submit()\">");
10674 r->rsprintf("Show&nbsp;factor&nbsp;and&nbsp;offset\n");
10675
10676 /* hidden command for refresh */
10677 r->rsprintf("<input type=hidden name=cmd value=Oldhistory>\n");
10678 r->rsprintf("<input type=hidden name=hcmd value=Refresh>\n");
10679 r->rsprintf("<input type=hidden name=panel value=\"%s\">\n", hpanel);
10680 r->rsprintf("<input type=hidden name=group value=\"%s\">\n", hgroup);
10681
10682 if (p->getparam("redir") && *p->getparam("redir"))
10683 r->rsprintf("<input type=hidden name=redir value=\"%s\">\n", p->getparam("redir"));
10684
10685 r->rsprintf("</td></tr>\n");
10686
10687 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Time scale (in units 'm', 'h', 'd'):</td>\n");
10688 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());
10689
10690 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Minimum (set to '-inf' for autoscale):</td>\n");
10691 r->rsprintf("<td colspan=3><input type=text size=12 name=minimum value=%f></td><td colspan=4></td></tr>\n", hp.minimum);
10692
10693 r->rsprintf("<tr><td colspan=4 style='text-align:right'>Maximum (set to 'inf' for autoscale):</td>\n");
10694 r->rsprintf("<td colspan=3><input type=text size=12 name=maximum value=%f></td><td colspan=4></td></tr>\n", hp.maximum);
10695
10696 r->rsprintf("<tr><td colspan=11>");
10697
10698 if (hp.zero_ylow)
10699 r->rsprintf("<input type=checkbox checked name=zero_ylow value=1>");
10700 else
10701 r->rsprintf("<input type=checkbox name=zero_ylow value=1>");
10702 r->rsprintf("Zero&nbsp;Y;&nbsp;axis\n");
10703
10704 if (hp.log_axis)
10705 r->rsprintf("<input type=checkbox checked name=log_axis value=1>");
10706 else
10707 r->rsprintf("<input type=checkbox name=log_axis value=1>");
10708 r->rsprintf("Logarithmic&nbsp;Y&nbsp;axis\n");
10709
10710 if (hp.show_run_markers)
10711 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=run_markers value=1>");
10712 else
10713 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=run_markers value=1>");
10714 r->rsprintf("Show&nbsp;run&nbsp;markers\n");
10715
10716 if (hp.show_values)
10717 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_values value=1>");
10718 else
10719 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_values value=1>");
10720 r->rsprintf("Show&nbsp;values&nbsp;of&nbsp;variables\n");
10721
10722 if (hp.show_fill)
10723 r->rsprintf("&nbsp;&nbsp;<input type=checkbox checked name=show_fill value=1>");
10724 else
10725 r->rsprintf("&nbsp;&nbsp;<input type=checkbox name=show_fill value=1>");
10726 r->rsprintf("Show&nbsp;graph&nbsp;fill\n");
10727
10728 r->rsprintf("</td></tr>\n");
10729
10730 /*---- events and variables ----*/
10731
10732 /* get display event name */
10733
10735 if (mh == NULL) {
10736 r->rsprintf(str, "History is not configured\n");
10737 return;
10738 }
10739
10740 time_t t = time(NULL);
10741
10742 if (old_vars)
10743 t = 0;
10744
10745 std::vector<std::string> events;
10746
10747 if (!old_vars)
10748 hs_read_event_list(&events);
10749
10750 if (events.size() == 0)
10751 mh->hs_get_events(t, &events);
10752
10753#if 0
10754 for (unsigned i=0; i<events.size(); i++)
10755 printf("event %d: \"%s\"\n", i, events[i].c_str());
10756#endif
10757
10758 // has to be sorted or equipment name code below would not work
10759 //std::sort(events.begin(), events.end(), cmp_events);
10760 std::sort(events.begin(), events.end(), cmp_events1);
10761
10762 if (strlen(p->getparam("cmdx")) > 0) {
10763 r->rsprintf("<tr><th colspan=8 class=\"subStatusTitle\">List of available history variables</th></tr>\n");
10764 r->rsprintf("<tr><th colspan=1>Sel<th colspan=1>Equipment<th colspan=1>Event<th colspan=1>Variable</tr>\n");
10765
10766 std::string cmdx = p->xgetparam("cmdx");
10767 std::string xeqname;
10768
10769 int i=0;
10770 for (unsigned e=0; e<events.size(); e++) {
10771 std::string eqname;
10772 eqname = events[e].substr(0, events[e].find("/"));
10773
10774 if (eqname.length() < 1)
10775 eqname = events[e];
10776
10777 bool once = false;
10778 if (eqname != xeqname)
10779 once = true;
10780
10781 std::string qcmd = "Expand " + eqname;
10782
10783 //printf("param [%s] is [%s]\n", qcmd.c_str(), p->getparam(qcmd.c_str()));
10784
10785 bool collapsed = true;
10786
10787 if (cmdx == qcmd)
10788 collapsed = false;
10789
10790 if (strlen(p->getparam(qcmd.c_str())) > 0)
10791 collapsed = false;
10792
10793 if (collapsed) {
10794 if (eqname == xeqname)
10795 continue;
10796
10797 r->rsprintf("<tr align=left>\n");
10798 r->rsprintf("<td></td>\n");
10799 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10800 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", qcmd.c_str());
10801 r->rsprintf("<td>%s</td>\n", "");
10802 r->rsprintf("</tr>\n");
10803 xeqname = eqname;
10804 continue;
10805 }
10806
10807 if (once)
10808 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", qcmd.c_str(), 1);
10809
10810 std::string rcmd = "Expand " + events[e];
10811
10812 //printf("param [%s] is [%s]\n", rcmd.c_str(), p->getparam(rcmd.c_str()));
10813
10814 collapsed = true;
10815
10816 if (cmdx == rcmd)
10817 collapsed = false;
10818
10819 if (strlen(p->getparam(rcmd.c_str())) > 0)
10820 collapsed = false;
10821
10822 if (collapsed) {
10823 r->rsprintf("<tr align=left>\n");
10824 r->rsprintf("<td></td>\n");
10825 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10826 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10827 r->rsprintf("<td><input type=submit name=cmdx value=\"%s\"></td>\n", rcmd.c_str());
10828 r->rsprintf("</tr>\n");
10829 continue;
10830 }
10831
10832 r->rsprintf("<tr><input type=hidden name=\"%s\" value=%d></tr>\n", rcmd.c_str(), 1);
10833
10834 xeqname = eqname;
10835
10836 std::vector<TAG> tags;
10837
10838 status = mh->hs_get_tags(events[e].c_str(), t, &tags);
10839
10840 if (status == HS_SUCCESS && tags.size() > 0) {
10841
10842 if (sort_vars)
10843 std::sort(tags.begin(), tags.end(), cmp_tags);
10844
10845 for (unsigned v=0; v<tags.size(); v++) {
10846
10847 for (unsigned j=0; j<tags[v].n_data; j++) {
10848 char tagname[256];
10849
10850 if (tags[v].n_data == 1)
10851 sprintf(tagname, "%s", tags[v].name);
10852 else
10853 sprintf(tagname, "%s[%d]", tags[v].name, j);
10854
10855 bool checked = false;
10856#if 0
10857 for (int index=0; index<MAX_VARS; index++) {
10858 if (equal_ustring(vars[index].event_name, events[e].c_str()) && equal_ustring(vars[index].var_name, tagname)) {
10859 checked = true;
10860 break;
10861 }
10862 }
10863#endif
10864
10865 r->rsprintf("<tr align=left>\n");
10866 r->rsprintf("<td><input type=checkbox %s name=\"sel%d\" value=\"%s:%s\"></td>\n", checked?"checked":"", i++, events[e].c_str(), tagname);
10867 r->rsprintf("<td>%s</td>\n", eqname.c_str());
10868 r->rsprintf("<td>%s</td>\n", events[e].c_str());
10869 r->rsprintf("<td>%s</td>\n", tagname);
10870 r->rsprintf("</tr>\n");
10871 }
10872 }
10873 }
10874 }
10875
10876 r->rsprintf("<tr>\n");
10877 r->rsprintf("<td></td>\n");
10878 r->rsprintf("<td>\n");
10879 r->rsprintf("<input type=hidden name=seln value=%d>\n", i);
10880 r->rsprintf("<input type=submit value=\"Add Selected\">\n");
10881 r->rsprintf("</td>\n");
10882 r->rsprintf("</tr>\n");
10883 }
10884
10885 r->rsprintf("<tr><td colspan=11 style='text-align:left'>New history: displayed_value = formula(history_value)</td></tr>\n");
10886 r->rsprintf("<tr><td colspan=11 style='text-align:left'>Old history: displayed_value = offset + factor*(history_value - voffset)</td></tr>\n");
10887 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");
10888 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");
10889 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");
10890 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");
10891
10892 r->rsprintf("<tr>\n");
10893 r->rsprintf("<th>Col<th>Event<th>Variable<th>Formula<th>Colour<th>Label<th>Raw<th>Order");
10894 if (hp.show_factor) {
10895 r->rsprintf("<th>Factor<th>Offset<th>VOffset");
10896 }
10897 r->rsprintf("</tr>\n");
10898
10899 //print_vars(vars);
10900
10901 size_t nvars = hp.vars.size();
10902 for (size_t index = 0; index <= nvars; index++) {
10903
10904 r->rsprintf("<tr>");
10905
10906 if (index < nvars) {
10907 if (hp.vars[index].colour.empty())
10908 hp.vars[index].colour = NextHistPlotColour(hp);
10909 r->rsprintf("<td style=\"background-color:%s\">&nbsp;<td>\n", hp.vars[index].colour.c_str());
10910 } else {
10911 r->rsprintf("<td>&nbsp;<td>\n");
10912 }
10913
10914 /* event and variable selection */
10915
10916 r->rsprintf("<select name=\"event%d\" size=1 onChange=\"document.form1.submit()\">\n", (int)index);
10917
10918 /* enumerate events */
10919
10920 /* empty option */
10921 r->rsprintf("<option value=\"/empty\">&lt;empty&gt;\n");
10922
10923 if (index==nvars) { // last "empty" entry
10924 for (unsigned e=0; e<events.size(); e++) {
10925 const char *p = events[e].c_str();
10926 r->rsprintf("<option value=\"%s\">%s\n", p, p);
10927 }
10928 } else if ((int)events.size() > max_display_events) { // too many events
10929 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].event_name.c_str(), hp.vars[index].event_name.c_str());
10930 r->rsprintf("<option>(%d events omitted)\n", (int)events.size());
10931 } else { // show all events
10932 bool found = false;
10933 for (unsigned e=0; e<events.size(); e++) {
10934 const char *s = "";
10935 const char *p = events[e].c_str();
10936 if (equal_ustring(hp.vars[index].event_name.c_str(), p)) {
10937 s = "selected";
10938 found = true;
10939 }
10940 r->rsprintf("<option %s value=\"%s\">%s\n", s, p, p);
10941 }
10942 if (!found) {
10943 const char *p = hp.vars[index].event_name.c_str();
10944 r->rsprintf("<option selected value=\"%s\">%s\n", p, p);
10945 }
10946 }
10947
10948 r->rsprintf("</select></td>\n");
10949
10950 //if (hp.vars[index].order <= 0)
10951 // hp.vars[index].order = (index+1)*10;
10952
10953 if (index < nvars) {
10954 bool found_tag = false;
10955 std::string selected_tag = hp.vars[index].tag_name;
10956
10957 r->rsprintf("<td><select name=\"var%d\">\n", (int)index);
10958
10959 std::vector<TAG> tags;
10960
10961 status = mh->hs_get_tags(hp.vars[index].event_name.c_str(), t, &tags);
10962
10963 if (status == HS_SUCCESS && tags.size() > 0) {
10964
10965 if (/* DISABLES CODE */ (0)) {
10966 printf("Compare %d\n", cmp_names("AAA", "BBB"));
10967 printf("Compare %d\n", cmp_names("BBB", "AAA"));
10968 printf("Compare %d\n", cmp_names("AAA", "AAA"));
10969 printf("Compare %d\n", cmp_names("A", "AAA"));
10970 printf("Compare %d\n", cmp_names("A111", "A1"));
10971 printf("Compare %d\n", cmp_names("A111", "A2"));
10972 printf("Compare %d\n", cmp_names("A111", "A222"));
10973 printf("Compare %d\n", cmp_names("A111a", "A111b"));
10974 }
10975
10976 if (sort_vars)
10977 std::sort(tags.begin(), tags.end(), cmp_tags);
10978
10979 if (/* DISABLES CODE */ (0)) {
10980 printf("Event [%s] %d tags\n", hp.vars[index].event_name.c_str(), (int)tags.size());
10981
10982 for (unsigned v=0; v<tags.size(); v++) {
10983 printf("tag[%d] [%s]\n", v, tags[v].name);
10984 }
10985 }
10986
10987 unsigned count_tags = 0;
10988 for (unsigned v=0; v<tags.size(); v++)
10989 count_tags += tags[v].n_data;
10990
10991 //printf("output %d option tags\n", count_tags);
10992
10993 if ((int)count_tags < max_display_tags) {
10994 for (unsigned v=0; v<tags.size(); v++) {
10995
10996 for (unsigned j=0; j<tags[v].n_data; j++) {
10997 std::string tagname;
10998
10999 if (tags[v].n_data == 1)
11000 tagname = tags[v].name;
11001 else {
11002 char buf[256];
11003 sprintf(buf, "[%d]", j);
11004 tagname = std::string(tags[v].name) + buf;
11005 }
11006
11007 if (equal_ustring(selected_tag.c_str(), tagname.c_str())) {
11008 r->rsprintf("<option selected value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
11009 found_tag = true;
11010 }
11011 else
11012 r->rsprintf("<option value=\"%s\">%s\n", tagname.c_str(), tagname.c_str());
11013
11014 //printf("%d [%s] [%s] [%s][%s] %d\n", (int)index, vars[index].event_name, tagname, vars[index].var_name, selected_var, found_var);
11015 }
11016 }
11017 }
11018 }
11019
11020 if (!found_tag)
11021 if (hp.vars[index].tag_name.length() > 0)
11022 r->rsprintf("<option selected value=\"%s\">%s\n", hp.vars[index].tag_name.c_str(), hp.vars[index].tag_name.c_str());
11023
11024 r->rsprintf("</select></td>\n");
11025 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());
11026 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());
11027 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());
11028 if (hp.vars[index].show_raw_value)
11029 r->rsprintf("<td><input type=checkbox checked name=\"raw%d\" value=1></td>", (int)index);
11030 else
11031 r->rsprintf("<td><input type=checkbox name=\"raw%d\" value=1></td>", (int)index);
11032 r->rsprintf("<td><input type=text size=3 maxlength=32 name=\"ord%d\" value=\"%d\"></td>\n", (int)index, hp.vars[index].order);
11033 if (hp.show_factor) {
11034 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"factor%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].factor);
11035 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"offset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].offset);
11036 r->rsprintf("<td><input type=text size=6 maxlength=32 name=\"voffset%d\" value=\"%g\"></td>\n", (int)index, hp.vars[index].voffset);
11037 } else {
11038 r->rsprintf("<input type=hidden name=\"factor%d\" value=\"%f\">\n", (int)index, hp.vars[index].factor);
11039 r->rsprintf("<input type=hidden name=\"offset%d\" value=\"%f\">\n", (int)index, hp.vars[index].offset);
11040 r->rsprintf("<input type=hidden name=\"voffset%d\" value=\"%f\">\n", (int)index, hp.vars[index].voffset);
11041 }
11042 } else {
11043 r->rsprintf("<td colspan=2><input type=submit name=cmdx value=\"List all variables\"></td>\n");
11044 }
11045
11046 r->rsprintf("</tr>\n");
11047 }
11048
11049 r->rsprintf("</table>\n");
11050 //r->rsprintf("</form>\n");
11051 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11052 r->rsprintf("</form>\n");
11053 r->rsprintf("</body></html>\r\n");
11054}
11055
11056/*------------------------------------------------------------------*/
11057
11058void export_hist(MVOdb* odb, Return* r, const char *group, const char *panel, time_t endtime, int scale, int index, int labels)
11059{
11060 //HNDLE hDB, hkey, hkeypanel;
11061 //int size;
11062 int status;
11063 //char str[256];
11064
11065 int debug = 0;
11066
11067 ss_tzset(); // required for localtime_r()
11068
11069#if 0
11071
11072 /* check panel name in ODB */
11073 sprintf(str, "/History/Display/%s/%s", group, panel);
11074 db_find_key(hDB, 0, str, &hkeypanel);
11075 if (!hkeypanel) {
11076 sprintf(str, "Cannot find /History/Display/%s/%s in ODB\n", group, panel);
11077 show_error(r, str);
11078 return;
11079 }
11080
11081 /* get runmarker flag */
11082 BOOL runmarker = 1;
11083 size = sizeof(runmarker);
11084 db_get_value(hDB, hkeypanel, "Show run markers", &runmarker, &size, TID_BOOL, TRUE);
11085
11086 if (scale == 0) {
11087 /* get timescale */
11088 std::string ts = "1h";
11089 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11090 if (status != DB_SUCCESS) {
11091 /* delete old integer key */
11092 db_delete(hDB, hkeypanel, "Timescale");
11093
11094 ts = "1h";
11095 status = db_get_value_string(hDB, hkeypanel, "Timescale", 0, &ts, TRUE);
11096 }
11097
11098 scale = time_to_sec(ts.c_str());
11099 }
11100#endif
11101
11102 time_t now = ss_time();
11103
11104 if (endtime == 0)
11105 endtime = now;
11106
11107 HistoryData hsxxx;
11108 HistoryData* hsdata = &hsxxx;
11109
11110 HistPlot hp;
11111 LoadHistPlotFromOdb(odb, &hp, group, panel);
11112
11113 time_t starttime = endtime - scale;
11114
11115 //printf("start %.0f, end %.0f, scale %.0f\n", (double)starttime, (double)endtime, (double)scale);
11116
11117 status = read_history(hp, /*hDB, group, panel,*/ index, hp.show_run_markers, starttime, endtime, 0, hsdata);
11118 if (status != HS_SUCCESS) {
11119 char str[256];
11120 sprintf(str, "History error, status %d\n", status);
11121 show_error(r, str);
11122 return;
11123 }
11124
11125 if (debug)
11126 hsdata->Print();
11127
11128 int *i_var = (int *)malloc(sizeof(int)*hsdata->nvars);
11129
11130 assert(i_var != NULL);
11131
11132 for (int i = 0; i < hsdata->nvars; i++)
11133 i_var[i] = -1;
11134
11135 time_t t = 0;
11136
11137 /* find first time where all variables are available */
11138 for (int i = 0; i < hsdata->nvars; i++)
11139 if (hsdata->odb_index[i] >= 0)
11140 if (hsdata->num_entries[i] > 0)
11141 if ((t == 0) || (hsdata->t[i][0] > t))
11142 t = hsdata->t[i][0];
11143
11144 if (t == 0 && hsdata->nvars > 1) {
11145 show_error(r, "No history available for choosen period");
11146 free(i_var);
11147 return;
11148 }
11149
11150 int run_index = -1;
11151 int state_index = -1;
11152 int n_run_number = 0;
11153 time_t* t_run_number = NULL;
11154 if (hp.show_run_markers)
11155 for (int i = 0; i < hsdata->nvars; i++) {
11156 if (hsdata->odb_index[i] == -2) {
11157 n_run_number = hsdata->num_entries[i];
11158 t_run_number = hsdata->t[i];
11159 run_index = i;
11160 } else if (hsdata->odb_index[i] == -1) {
11161 state_index = i;
11162 }
11163 }
11164
11165 //printf("runmarker %d, state %d, run %d\n", runmarker, state_index, run_index);
11166
11167 /* header */
11168 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
11169 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
11170 r->rsprintf("Accept-Ranges: bytes\r\n");
11171 r->rsprintf("Cache-control: private, max-age=0, no-cache\r\n");
11172 r->rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n");
11173 r->rsprintf("Content-Type: text/plain\r\n");
11174 r->rsprintf("Content-disposition: attachment; filename=\"export.csv\"\r\n");
11175 r->rsprintf("\r\n");
11176
11177 /* output header line with variable names */
11178 if (hp.show_run_markers && t_run_number)
11179 r->rsprintf("Time, Timestamp, Run, Run State, ");
11180 else
11181 r->rsprintf("Time, Timestamp, ");
11182
11183 for (int i = 0, first = 1; i < hsdata->nvars; i++) {
11184 if (hsdata->odb_index[i] < 0)
11185 continue;
11186 if (hsdata->num_entries[i] <= 0)
11187 continue;
11188 if (!first)
11189 r->rsprintf(", ");
11190 first = 0;
11191 r->rsprintf("%s", hsdata->var_names[i]);
11192 }
11193 r->rsprintf("\n");
11194
11195 int i_run = 0;
11196
11197 do {
11198
11199 if (debug)
11200 printf("hsdata %p, t %d, irun %d\n", hsdata, (int)t, i_run);
11201
11202 /* find run number/state which is valid for t */
11203 if (hp.show_run_markers && t_run_number)
11204 while (i_run < n_run_number-1 && t_run_number[i_run+1] <= t)
11205 i_run++;
11206
11207 //printf("irun %d\n", i_run);
11208
11209 /* find index for all variables which is valid for t */
11210 for (int i = 0; i < hsdata->nvars; i++)
11211 while (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i] - 1 && hsdata->t[i][i_var[i]+1] <= t)
11212 i_var[i]++;
11213
11214 /* finish if last point for all variables reached */
11215 bool done = true;
11216 for (int i = 0 ; i < hsdata->nvars ; i++)
11217 if (hsdata->num_entries[i] > 0 && i_var[i] < hsdata->num_entries[i]) {
11218 done = false;
11219 break;
11220 }
11221
11222 if (debug) {
11223 printf("step to time %d: ", (int)t);
11224 for (int i = 0; i < hsdata->nvars; i++) {
11225 printf(" [%d] %d, ", hsdata->num_entries[i], i_var[i]);
11226 }
11227 printf(" done: %d\n", done);
11228 }
11229
11230 if (done)
11231 break;
11232
11233 struct tm tms;
11234 localtime_r(&t, &tms);
11235
11236 char fmt[256];
11237 //strcpy(fmt, "%c");
11238 strcpy(fmt, "%Y.%m.%d %H:%M:%S");
11239 char str[256];
11240 strftime(str, sizeof(str), fmt, &tms);
11241
11242 if (t_run_number && run_index>=0 && state_index>=0) {
11243 if (t_run_number[i_run] <= t)
11244 r->rsprintf("%s, %d, %.0f, %.0f, ", str, (int)t, hsdata->v[run_index][i_run], hsdata->v[state_index][i_run]);
11245 else
11246 r->rsprintf("%s, %d, N/A, N/A, ", str, (int)t);
11247 } else
11248 r->rsprintf("%s, %d, ", str, (int)t);
11249
11250 if (debug) {
11251 for (int i= 0 ; i < hsdata->nvars ; i++)
11252 printf(" %d (%g)", i_var[i], hsdata->v[i][i_var[i]]);
11253 printf("\n");
11254 }
11255
11256 for (int i=0, first=1 ; i<hsdata->nvars ; i++) {
11257 if (i_var[i] < 0)
11258 continue;
11259 if (hsdata->odb_index[i] < 0)
11260 continue;
11261 if (!first)
11262 r->rsprintf(", ");
11263 first = 0;
11264 //r->rsprintf("(%d %g)", i_var[i], hsdata->v[i][i_var[i]]);
11265 r->rsprintf("%g", hsdata->v[i][i_var[i]]);
11266 }
11267 r->rsprintf("\n");
11268
11269 /* find next t as smallest delta t */
11270 int dt = -1;
11271 for (int i = 0 ; i < hsdata->nvars ; i++)
11272 if (i_var[i]>=0 && hsdata->odb_index[i]>=0 && hsdata->num_entries[i]>0 && i_var[i]<hsdata->num_entries[i]-1) {
11273 int xdt = hsdata->t[i][i_var[i]+1] - t;
11274 if (debug)
11275 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);
11276 if (dt <= 0 || xdt < dt)
11277 dt = xdt;
11278 }
11279
11280 if (debug)
11281 printf("dt %d\n", dt);
11282
11283 if (dt <= 0)
11284 break;
11285
11286 t += dt;
11287
11288 } while (1);
11289
11290 free(i_var);
11291}
11292
11293/*------------------------------------------------------------------*/
11294
11295void show_hist_page(MVOdb* odb, Param* p, Return* r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
11296{
11297 HNDLE hDB, hkey, hikeyp, hkeyp, hkeybutton;
11298 KEY key, ikey;
11299 int i, j, k, scale, index, width, size, status, labels;
11300 char hgroup[256], hpanel[256], hcmd[256];
11301 const char def_button[][NAME_LENGTH] = { "10m", "1h", "3h", "12h", "24h", "3d", "7d" };
11302
11304
11305 hcmd[0] = hgroup[0] = hpanel[0] = 0;
11306
11307 if (p->getparam("group") && *p->getparam("group"))
11308 mstrlcpy(hgroup, p->getparam("group"), sizeof(hgroup));
11309 if (p->getparam("panel") && *p->getparam("panel"))
11310 mstrlcpy(hpanel, p->getparam("panel"), sizeof(hpanel));
11311 if (p->getparam("hcmd") && *p->getparam("hcmd"))
11312 mstrlcpy(hcmd, p->getparam("hcmd"), sizeof(hcmd));
11313
11314 if (equal_ustring(hcmd, "Reset")) {
11315 std::string redir;
11316 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11317 redir += "?cmd=oldhistory&group=";
11318 redir += hgroup;
11319 redir += "&panel=";
11320 redir += hpanel;
11321 redirect(r, redir.c_str());
11322 return;
11323 }
11324
11325 if (equal_ustring(hcmd, "Query")) {
11326 show_query_page(p, r);
11327 return;
11328 }
11329
11330 if (equal_ustring(hcmd, "Cancel")) {
11331 //sprintf(str, "?cmd=oldhistory&group=%s&panel=%s", hgroup, hpanel);
11332 if (p->getparam("redir") && *p->getparam("redir"))
11333 redirect(r, p->getparam("redir"));
11334 else {
11335 std::string redir;
11336 redir += "?cmd=oldhistory&group=";
11337 redir += hgroup;
11338 redir += "&panel=";
11339 redir += hpanel;
11340 redirect(r, redir.c_str());
11341 }
11342 return;
11343 }
11344
11345 if (equal_ustring(hcmd, "Config") ||
11346 equal_ustring(hcmd, "Save")
11347 || equal_ustring(hcmd, "Clear history cache")
11348 || equal_ustring(hcmd, "Refresh")) {
11349
11350 show_hist_config_page(odb, p, r, hgroup, hpanel);
11351 return;
11352 }
11353
11354 if (equal_ustring(hcmd, "New")) {
11355 show_header(r, "History", "GET", "", 0);
11356
11357 r->rsprintf("<table class=\"dialogTable\">");
11358 r->rsprintf("<tr><th class=\"subStatusTitle\" colspan=2>New History Item</th><tr>");
11359 r->rsprintf("<tr><td align=center colspan=2>\n");
11360 r->rsprintf("Select group: &nbsp;&nbsp;");
11361 r->rsprintf("<select id=\"group\" name=\"group\">\n");
11362
11363 /* list existing groups */
11364 db_find_key(hDB, 0, "/History/Display", &hkey);
11365 i = 0;
11366 if (hkey) {
11367 for (i = 0;; i++) {
11368 db_enum_link(hDB, hkey, i, &hkeyp);
11369
11370 if (!hkeyp)
11371 break;
11372
11373 db_get_key(hDB, hkeyp, &key);
11374 if (equal_ustring(hgroup, key.name))
11375 r->rsprintf("<option selected>%s</option>\n", key.name);
11376 else
11377 r->rsprintf("<option>%s</option>\n", key.name);
11378 }
11379 }
11380 if (!hkey || i == 0)
11381 r->rsprintf("<option>Default</option>\n");
11382 r->rsprintf("</select><p>\n");
11383
11384 r->rsprintf("Or enter new group name: &nbsp;&nbsp;");
11385 r->rsprintf("<input type=text size=15 maxlength=31 id=new_group name=new_group>\n");
11386
11387 r->rsprintf("<tr><td align=center colspan=2>\n");
11388 r->rsprintf("<br>Panel name: &nbsp;&nbsp;");
11389 r->rsprintf("<input type=text size=15 maxlength=31 id=panel name=panel><br><br>\n");
11390 r->rsprintf("</td></tr>\n");
11391
11392 r->rsprintf("<tr><td align=center colspan=2>");
11393 std::string str = "?cmd=oldhistory&hcmd=createnew";
11394 str += "&new_group='+document.getElementById('new_group').value+'";
11395 str += "&group='+document.getElementById('group').value+'";
11396 str += "&panel='+document.getElementById('panel').value+'";
11397 r->rsprintf("<input type=button value=Submit onclick=\"window.location.search='%s'\">\n", str.c_str());
11398 r->rsprintf("</td></tr>\n");
11399
11400 r->rsprintf("</table>\r\n");
11401 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11402 r->rsprintf("</form>\n");
11403 r->rsprintf("</body></html>\r\n");
11404 return;
11405 }
11406
11407 if (equal_ustring(hcmd, "Delete Panel")) {
11408 std::string path;
11409 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11410 path += "/History/Display/";
11411 path += hgroup;
11412 path += "/";
11413 path += hpanel;
11414 db_delete(hDB, 0, path.c_str());
11415 redirect(r, "?cmd=oldhistory");
11416 return;
11417 }
11418
11419 if (equal_ustring(hcmd, "createnew")) {
11420
11421 /* strip leading/trailing spaces */
11422 while (hpanel[0] == ' ') {
11423 char str[256];
11424 mstrlcpy(str, hpanel+1, sizeof(str));
11425 mstrlcpy(hpanel, str, sizeof(hpanel));
11426 }
11427 while (strlen(hpanel)> 1 && hpanel[strlen(hpanel)-1] == ' ')
11428 hpanel[strlen(hpanel)-1] = 0;
11429
11430 /* use new group if present */
11431 if (p->isparam("new_group") && *p->getparam("new_group"))
11432 mstrlcpy(hgroup, p->getparam("new_group"), sizeof(hgroup));
11433
11434 /* configure that panel */
11435 show_hist_config_page(odb, p, r, hgroup, hpanel);
11436 return;
11437 }
11438
11439 const char* pscale = p->getparam("scale");
11440 if (pscale == NULL || *pscale == 0)
11441 pscale = p->getparam("hscale");
11442 const char* pwidth = p->getparam("width");
11443 if (pwidth == NULL || *pwidth == 0)
11444 pwidth = p->getparam("hwidth");
11445 const char* pheight = p->getparam("height");
11446 if (pheight == NULL || *pheight == 0)
11447 pheight = p->getparam("hheight");
11448 const char* pindex = p->getparam("index");
11449 if (pindex == NULL || *pindex == 0)
11450 pindex = p->getparam("hindex");
11451
11452 labels = 1;
11453 if (*p->getparam("labels") && atoi(p->getparam("labels")) == 0)
11454 labels = 0;
11455
11456 std::string bgcolor = "FFFFFF";
11457 if (*p->getparam("bgcolor"))
11458 bgcolor = p->xgetparam("bgcolor");
11459
11460 std::string fgcolor = "000000";
11461 if (*p->getparam("fgcolor"))
11462 fgcolor = p->xgetparam("fgcolor");
11463
11464 std::string gridcolor = "A0A0A0";
11465 if (*p->getparam("gcolor"))
11466 gridcolor = p->xgetparam("gcolor");
11467
11468 /* evaluate scale and offset */
11469
11470 time_t endtime = 0;
11471 if (p->isparam("time"))
11472 endtime = string_to_time(p->getparam("time"));
11473 else if (p->isparam("htime"))
11474 endtime = string_to_time(p->getparam("htime"));
11475
11476 if (pscale && *pscale)
11477 scale = time_to_sec(pscale);
11478 else
11479 scale = 0;
11480
11481 index = -1;
11482 if (pindex && *pindex)
11483 index = atoi(pindex);
11484
11485#ifdef BROKEN
11486 if (equal_ustring(hcmd, "Create ELog")) {
11487 // FIXME: This check should use /Elog/External Elog
11488 std::string xurl;
11489 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &xurl, FALSE);
11490 if (status == DB_SUCCESS) {
11491 char url[256];
11492 get_elog_url(url, sizeof(url));
11493
11494 /*---- use external ELOG ----*/
11495 fsize = 100000;
11496 char* fbuffer = (char*)M_MALLOC(fsize);
11497 assert(fbuffer != NULL);
11498
11499 int width = 640;
11500 int height = 400;
11501
11502 if (equal_ustring(pmag, "Large")) {
11503 width = 1024;
11504 height = 768;
11505 } else if (equal_ustring(pmag, "Small")) {
11506 width = 320;
11507 height = 200;
11508 } else if (atoi(pmag) > 0) {
11509 width = atoi(pmag);
11510 height = 200;
11511 }
11512
11513 printf("hereA\n");
11514 generate_hist_graph(odb, r, hgroup, hpanel, fbuffer, &fsize, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11515
11516 /* save temporary file */
11517 std::string dir;
11518 db_get_value_string(hDB, 0, "/Elog/Logbook Dir", 0, &dir, TRUE);
11519 if (dir.length() > 0 && dir[dir.length()-1] != DIR_SEPARATOR)
11520 dir += DIR_SEPARATOR_STR;
11521
11522 time_t now = time(NULL);
11523 localtime_r(&now, &tms);
11524
11525 std::string file_name = msprintf("%02d%02d%02d_%02d%02d%02d_%s.gif",
11526 tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday,
11527 tms.tm_hour, tms.tm_min, tms.tm_sec, hpanel);
11528 std::string fname = dir + file_name;
11529
11530 /* save attachment */
11531 fh = open(fname.c_str(), O_CREAT | O_RDWR | O_BINARY, 0644);
11532 if (fh < 0) {
11533 cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", open() errno %d (%s)", fname.c_str(), errno, strerror(errno));
11534 } else {
11535 int wr = write(fh, fbuffer, fsize);
11536 if (wr != fsize) {
11537 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));
11538 }
11539 close(fh);
11540 }
11541
11542 /* redirect to ELOG */
11543 if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11544 mstrlcat(url, "/", sizeof(url));
11545 mstrlcat(url, "?cmd=New&fa=", sizeof(url));
11546 mstrlcat(url, file_name, sizeof(url));
11547 redirect(r, url);
11548
11549 M_FREE(fbuffer);
11550 return;
11551
11552 } else {
11553 /*---- use internal ELOG ----*/
11554 std::string str = msprintf("\\HS\\%s.gif", hpanel);
11555 if (p->getparam("hscale") && *p->getparam("hscale"))
11556 str += msprintf("?scale=%s", p->getparam("hscale"));
11557 if (p->getparam("htime") && *p->getparam("htime")) {
11558 if (strchr(str.c_str(), '?'))
11559 str += "&";
11560 else
11561 str += "?";
11562 str += msprintf("time=%s", p->getparam("htime"));
11563 }
11564 //if (p->getparam("hoffset") && *p->getparam("hoffset")) {
11565 // if (strchr(str, '?'))
11566 // mstrlcat(str, "&", sizeof(str));
11567 // else
11568 // mstrlcat(str, "?", sizeof(str));
11569 // sprintf(str + strlen(str), "offset=%s", p->getparam("hoffset"));
11570 //}
11571 if (p->getparam("hwidth") && *p->getparam("hwidth")) {
11572 if (strchr(str.c_str(), '?'))
11573 str += "&";
11574 else
11575 str += "?";
11576 str += msprintf("width=%s", p->getparam("hwidth"));
11577 }
11578 if (p->getparam("hindex") && *p->getparam("hindex")) {
11579 if (strchr(str.c_str(), '?'))
11580 str += "&";
11581 else
11582 str += "?";
11583 str += msprintf("index=%s", p->getparam("hindex"));
11584 }
11585
11586 show_elog_new(r, hpanel, NULL, FALSE, str.c_str(), "../../EL/");
11587 return;
11588 }
11589 }
11590#endif
11591
11592 if (equal_ustring(hcmd, "Export")) {
11593 export_hist(odb, r, hgroup, hpanel, endtime, scale, index, labels);
11594 return;
11595 }
11596
11597 if (strstr(dec_path, ".gif")) {
11598 int width = 640;
11599 int height = 400;
11600 if (equal_ustring(pwidth, "Large")) {
11601 width = 1024;
11602 height = 768;
11603 } else if (equal_ustring(pwidth, "Small")) {
11604 width = 320;
11605 height = 200;
11606 } else if (atoi(pwidth) > 0) {
11607 width = atoi(pwidth);
11608 if (atoi(pheight) > 0)
11609 height = atoi(pheight);
11610 else
11611 height = (int)(0.625 * width);
11612 }
11613
11614 //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);
11615
11616 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());
11617
11618 return;
11619 }
11620
11621 if (history_mode && index < 0)
11622 return;
11623
11624 time_t now = time(NULL);
11625
11626 /* evaluate offset shift */
11627 if (equal_ustring(p->getparam("shift"), "leftmaxall")) {
11628 if (endtime == 0)
11629 endtime = now;
11630 time_t last_written = 0;
11631 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 1, &last_written);
11632 if (status == HS_SUCCESS)
11633 endtime = last_written + scale/2;
11634 }
11635
11636 if (equal_ustring(p->getparam("shift"), "leftmax")) {
11637 if (endtime == 0)
11638 endtime = now;
11639 time_t last_written = 0;
11640 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 0, &last_written);
11641 if (status == HS_SUCCESS)
11642 if (last_written != endtime)
11643 endtime = last_written + scale/2;
11644 }
11645
11646 if (equal_ustring(p->getparam("shift"), "left")) {
11647 if (endtime == 0)
11648 endtime = now;
11649 endtime -= scale/2;
11650 //offset -= scale / 2;
11651 }
11652
11653 if (equal_ustring(p->getparam("shift"), "right")) {
11654 if (endtime == 0)
11655 endtime = now;
11656 endtime += scale/2;
11657 if (endtime > now)
11658 endtime = now;
11659 }
11660
11661 if (equal_ustring(p->getparam("shift"), "rightmax")) {
11662 endtime = 0;
11663 }
11664
11665 if (equal_ustring(p->getparam("shift"), "zoomin")) {
11666 if (endtime == 0)
11667 endtime = now;
11668 endtime -= scale / 4;
11669 scale /= 2;
11670 }
11671
11672 if (equal_ustring(p->getparam("shift"), "zoomout")) {
11673 if (endtime == 0)
11674 endtime = now;
11675 endtime += scale / 2;
11676 if (endtime > now)
11677 endtime = now;
11678 scale *= 2;
11679 }
11680
11681 int xrefresh = refresh;
11682 if (endtime != 0)
11683 xrefresh = 0;
11684 show_header(r, hpanel, "GET", "", xrefresh);
11685
11686 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
11687 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
11688 show_navigation_bar(r, "History");
11689
11690 r->rsprintf("<table class=\"mtable\">");
11691 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>History</th></tr>");
11692
11693 {
11694 /* check if panel exists */
11695 std::string path;
11696 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11697 path += "/History/Display/";
11698 path += hgroup;
11699 path += "/";
11700 path += hpanel;
11701 status = db_find_key(hDB, 0, path.c_str(), &hkey);
11702 if (status != DB_SUCCESS && !equal_ustring(hpanel, "All") && !equal_ustring(hpanel,"")) {
11703 r->rsprintf("<h1>Error: History panel \"%s\" in group \"%s\" does not exist</h1>\n", hpanel, hgroup);
11704 r->rsprintf("</table>\r\n");
11705 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11706 r->rsprintf("</form>\n");
11707 r->rsprintf("</body></html>\r\n");
11708 return;
11709 }
11710 }
11711
11712 /* define hidden field for parameters */
11713 if (pscale && *pscale)
11714 r->rsprintf("<input type=hidden name=hscale id=hscale value=%d>\n", scale);
11715 else {
11716 /* if no scale and offset given, get it from default */
11717 if (hpanel[0] && !equal_ustring(hpanel, "All") && hgroup[0]) {
11718 std::string path;
11719 path += "/History/Display/";
11720 path += hgroup;
11721 path += "/";
11722 path += hpanel;
11723 path += "/Timescale";
11724
11725 std::string scalestr = "1h";
11726 status = db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11727 if (status != DB_SUCCESS) {
11728 /* delete old integer key */
11729 db_delete(hDB, 0, path.c_str());
11730 scalestr = "1h";
11731 db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11732 }
11733
11734 r->rsprintf("<input type=hidden name=hscale id=hscale value=%s>\n", scalestr.c_str());
11735 scale = time_to_sec(scalestr.c_str());
11736 }
11737 }
11738
11739 if (endtime != 0)
11740 r->rsprintf("<input type=hidden name=htime id=htime value=%s>\n", time_to_string(endtime).c_str());
11741 if (pwidth && *pwidth)
11742 r->rsprintf("<input type=hidden name=hwidth id=hwidth value=%s>\n", pwidth);
11743 if (pheight && *pheight)
11744 r->rsprintf("<input type=hidden name=hheight id=hheight value=%s>\n", pheight);
11745 if (pindex && *pindex)
11746 r->rsprintf("<input type=hidden name=hindex id=hindex value=%s>\n", pindex);
11747
11748 r->rsprintf("</td></tr>\n");
11749
11750 if (hgroup[0] == 0) {
11751 /* "New" button */
11752 r->rsprintf("<tr><td colspan=2><input type=\"button\" name=\"New\" value=\"New\" ");
11753 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New'\"></td></tr>\n");
11754
11755 /* links for history panels */
11756 r->rsprintf("<tr><td colspan=2 style=\"text-align:left;\">\n");
11757 if (!hpanel[0])
11758 r->rsprintf("<b>Please select panel:</b><br>\n");
11759
11760 /* table for panel selection */
11761 r->rsprintf("<table class=\"historyTable\">");
11762
11763 /* "All" link */
11764 r->rsprintf("<tr><td colspan=2 class=\"titleCell\">\n");
11765 if (equal_ustring(hgroup, "All"))
11766 r->rsprintf("All &nbsp;&nbsp;");
11767 else
11768 r->rsprintf("<a href=\"?cmd=oldhistory&group=All\">ALL</a>\n");
11769 r->rsprintf("</td></tr>\n");
11770
11771 /* Setup History table links */
11772 db_find_key(hDB, 0, "/History/Display", &hkey);
11773 if (!hkey) {
11774 /* create default panel */
11775 char str[256];
11776 strcpy(str, "System:Trigger per sec.");
11777 strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11778 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables", str, 64, 2, TID_STRING);
11779 strcpy(str, "1h");
11780 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale", str, NAME_LENGTH, 1, TID_STRING);
11781
11782 strcpy(str, "1h");
11783 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale", str, NAME_LENGTH, 1, TID_STRING);
11784 i = 1;
11785 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11786 i = 1;
11787 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11788
11789 strcpy(str, "");
11790 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING);
11791 db_set_value_index(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING, FALSE);
11792 }
11793
11794 db_find_key(hDB, 0, "/History/Display", &hkey);
11795 if (hkey) {
11796 for (i = 0;; i++) {
11797 db_enum_link(hDB, hkey, i, &hkeyp);
11798
11799 if (!hkeyp)
11800 break;
11801
11802 // Group key
11803 db_get_key(hDB, hkeyp, &key);
11804
11805 char enc_name[256];
11806 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11807 urlEncode(enc_name, sizeof(enc_name));
11808
11809 if (equal_ustring(hpanel, key.name))
11810 r->rsprintf("<tr><td class=\"titleCell\">%s</td>\n<td>", key.name);
11811 else
11812 r->rsprintf("<tr><td class=\"titleCell\"><a href=\"?cmd=oldhistory&group=%s\">%s</a></td>\n<td>", enc_name, key.name);
11813
11814 for (j = 0;; j++) {
11815 // scan items
11816 db_enum_link(hDB, hkeyp, j, &hikeyp);
11817
11818 if (!hikeyp) {
11819 r->rsprintf("</tr>");
11820 break;
11821 }
11822 // Item key
11823 db_get_key(hDB, hikeyp, &ikey);
11824
11825 char enc_iname[256];
11826 mstrlcpy(enc_iname, ikey.name, sizeof(enc_iname));
11827 urlEncode(enc_iname, sizeof(enc_iname));
11828
11829 if (equal_ustring(hpanel, ikey.name))
11830 r->rsprintf("<small><b>%s</b></small> &nbsp;", ikey.name);
11831 else
11832 r->rsprintf("<small><a href=\"?cmd=oldhistory&group=%s&panel=%s\">%s</a></small> &nbsp;\n", enc_name, enc_iname, ikey.name);
11833 }
11834 }
11835 }
11836
11837 r->rsprintf("</table></tr>\n");
11838
11839 } else {
11840 int found = 0;
11841
11842 /* show drop-down selectors */
11843 r->rsprintf("<tr><td colspan=2>\n");
11844
11845 r->rsprintf("Group:\n");
11846
11847 r->rsprintf("<select title=\"Select group\" id=\"fgroup\" onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value;\">\n");
11848
11849 db_find_key(hDB, 0, "/History/Display", &hkey);
11850 if (hkey) {
11851 hkeyp = 0;
11852 for (i = 0;; i++) {
11853 db_enum_link(hDB, hkey, i, &hikeyp);
11854
11855 if (!hikeyp)
11856 break;
11857
11858 if (i == 0)
11859 hkeyp = hikeyp;
11860
11861 // Group key
11862 db_get_key(hDB, hikeyp, &key);
11863
11864 if (equal_ustring(key.name, hgroup)) {
11865 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11866 hkeyp = hikeyp;
11867 } else
11868 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11869 }
11870
11871 if (equal_ustring("ALL", hgroup)) {
11872 r->rsprintf("<option selected value=\"%s\">%s\n", "ALL", "ALL");
11873 } else {
11874 r->rsprintf("<option value=\"%s\">%s\n", "ALL", "ALL");
11875 }
11876
11877 r->rsprintf("</select>\n");
11878 r->rsprintf("&nbsp;&nbsp;Panel:\n");
11879 r->rsprintf("<select title=\"Select panel\" id=\"fpanel\" ");
11880 r->rsprintf("onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value+");
11881 r->rsprintf("'&panel='+document.getElementById('fpanel').value;\">\n");
11882
11883 found = 0;
11884 if (hkeyp) {
11885 for (i = 0;; i++) {
11886 // scan panels
11887 db_enum_link(hDB, hkeyp, i, &hikeyp);
11888
11889 if (!hikeyp)
11890 break;
11891
11892 // Item key
11893 db_get_key(hDB, hikeyp, &key);
11894
11895 if (equal_ustring(hpanel, key.name)) {
11896 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11897 found = 1;
11898 } else
11899 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11900 }
11901 }
11902
11903 if (found)
11904 r->rsprintf("<option value=\"\">- all -\n");
11905 else
11906 r->rsprintf("<option selected value=\"\">- all -\n");
11907
11908 r->rsprintf("</select>\n");
11909 }
11910
11911 r->rsprintf("<noscript>\n");
11912 r->rsprintf("<input type=submit value=\"Go\">\n");
11913 r->rsprintf("</noscript>\n");
11914
11915 r->rsprintf("&nbsp;&nbsp;<input type=\"button\" name=\"New\" value=\"New\" ");
11916 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New&group=%s'\">\n", hgroup);
11917
11918 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Reset\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Reset&group=%s&panel=%s'\">\n", hgroup, hpanel);
11919
11920 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Query\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Query&group=%s&panel=%s'\">\n", hgroup, hpanel);
11921
11922 double xendtime = endtime;
11923 if (xendtime == 0)
11924 xendtime = now;
11925 double xstarttime = xendtime - scale;
11926
11927 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);
11928
11929 r->rsprintf("</td></tr>\n");
11930 }
11931
11932 //printf("hgroup [%s] hpanel [%s]\n", hgroup, hpanel);
11933
11934 /* check if whole group should be displayed */
11935 if (hgroup[0] && !equal_ustring(hgroup, "ALL") && hpanel[0] == 0) {
11936 std::string strwidth = "Small";
11937 db_get_value_string(hDB, 0, "/History/Display Settings/Width Group", 0, &strwidth, TRUE);
11938
11939 std::string path;
11940 path += "/History/Display/";
11941 path += hgroup;
11942 db_find_key(hDB, 0, path.c_str(), &hkey);
11943 if (hkey) {
11944 for (i = 0 ;; i++) { // scan group
11945 db_enum_link(hDB, hkey, i, &hikeyp);
11946
11947 if (!hikeyp)
11948 break;
11949
11950 db_get_key(hDB, hikeyp, &key);
11951
11952 char enc_name[256];
11953 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11954 urlEncode(enc_name, sizeof(enc_name));
11955
11956 std::string ref;
11957 ref += "graph.gif?width=";
11958 ref += strwidth;
11959 ref += "&cmd=oldhistory&group=";
11960 ref += hgroup;
11961 ref += "&panel=";
11962 ref += enc_name;
11963
11964 std::string ref2;
11965 ref2 += "?cmd=oldhistory&group=";
11966 ref2 += hgroup;
11967 ref2 += "&panel=";
11968 ref2 += enc_name;
11969
11970 if (endtime != 0) {
11971 char tmp[256];
11972 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
11973 ref += "&";
11974 ref += tmp;
11975 ref2 += "?";
11976 ref2 += tmp;
11977 }
11978
11979 if (i % 2 == 0)
11980 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
11981 else
11982 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
11983 }
11984
11985 } else {
11986 r->rsprintf("Group \"%s\" not found", hgroup);
11987 }
11988 }
11989
11990 /* image panel */
11991 else if (hpanel[0] && !equal_ustring(hpanel, "All")) {
11992 /* navigation links */
11993 r->rsprintf("<tr><td>\n");
11994
11995 std::string path;
11996 path += "/History/Display/";
11997 path += hgroup;
11998 path += "/";
11999 path += hpanel;
12000 path += "/Buttons";
12001 db_find_key(hDB, 0, path.c_str(), &hkeybutton);
12002 if (hkeybutton == 0) {
12003 /* create default buttons */
12004 db_create_key(hDB, 0, path.c_str(), TID_STRING);
12005 status = db_find_key(hDB, 0, path.c_str(), &hkeybutton);
12006 if (status != DB_SUCCESS || !hkey) {
12007 cm_msg(MERROR, "show_hist_page", "Cannot create history panel with invalid ODB path \"%s\"", path.c_str());
12008 return;
12009 }
12010 db_set_data(hDB, hkeybutton, def_button, sizeof(def_button), 7, TID_STRING);
12011 }
12012
12013 r->rsprintf("<script>\n");
12014 r->rsprintf("function histDisp(p) {\n");
12015 r->rsprintf(" var params = '?cmd=oldhistory&group=%s&panel=%s';\n", hgroup, hpanel);
12016 r->rsprintf(" params += '&'+p;\n");
12017 r->rsprintf(" if (document.getElementById(\'hscale\') !== null)\n");
12018 r->rsprintf(" params += '&hscale='+document.getElementById(\'hscale\').value;\n");
12019 r->rsprintf(" if (document.getElementById(\'htime\') !== null)\n");
12020 r->rsprintf(" params += '&htime='+document.getElementById(\'htime\').value;\n");
12021 r->rsprintf(" if (document.getElementById(\'hwdith\') !== null)\n");
12022 r->rsprintf(" params += '&hwidth='+document.getElementById(\'hwidth\').value;\n");
12023 r->rsprintf(" if (document.getElementById(\'hindex\') !== null)\n");
12024 r->rsprintf(" params += '&hindex='+document.getElementById(\'hindex\').value;\n");
12025 r->rsprintf(" window.location.search = params;\n");
12026 r->rsprintf("}\n\n");
12027 r->rsprintf("</script>\n");
12028
12029 db_get_key(hDB, hkeybutton, &key);
12030
12031 for (i = 0; i < key.num_values; i++) {
12032 char str[256];
12033 size = sizeof(str);
12034 db_get_data_index(hDB, hkeybutton, str, &size, i, TID_STRING);
12035 r->rsprintf("<input type=\"button\" title=\"display last %s\" value=%s onclick=\"histDisp('scale=%s')\">\n", str, str, str);
12036 }
12037
12038 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')\">");
12039 r->rsprintf("<input type=\"button\" value=\"<<\" title=\"go back in time to last available data\" onclick=\"histDisp('shift=leftmax')\">");
12040 r->rsprintf("<input type=\"button\" value=\"<\" title=\"go back in time\" onclick=\"histDisp('shift=left')\">");
12041
12042 r->rsprintf("<input type=\"button\" value=\" + \" title=\"zoom in\" onclick=\"histDisp('shift=zoomin')\">");
12043 r->rsprintf("<input type=\"button\" value=\" - \" title=\"zoom out\" onclick=\"histDisp('shift=zoomout')\">");
12044
12045 if (endtime != 0) {
12046 r->rsprintf("<input type=\"button\" value=\">\" title=\"go forward in time\" onclick=\"histDisp('shift=right')\">");
12047 r->rsprintf("<input type=\"button\" value=\">>\" title=\"go to currently updated fresh data\" onclick=\"histDisp('shift=rightmax')\">");
12048 }
12049
12050 r->rsprintf("<td>\n");
12051 r->rsprintf("<input type=\"button\" value=\"Large\" title=\"large display\" onclick=\"histDisp('width=Large')\">\n");
12052 r->rsprintf("<input type=\"button\" value=\"Small\" title=\"large display\" onclick=\"histDisp('width=Small')\">\n");
12053 r->rsprintf("<input type=\"button\" value=\"Create Elog\" title=\"large display\" onclick=\"histDisp('hcmd=Create Elog')\">\n");
12054 r->rsprintf("<input type=\"button\" value=\"Config\" title=\"large display\" onclick=\"histDisp('hcmd=Config')\">\n");
12055 r->rsprintf("<input type=\"button\" value=\"Export\" title=\"large display\" onclick=\"histDisp('hcmd=Export')\">\n");
12056 r->rsprintf("</tr>\n");
12057
12058 char paramstr[256];
12059
12060 paramstr[0] = 0;
12061 sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12062 if (endtime != 0)
12063 sprintf(paramstr + strlen(paramstr), "&time=%s", time_to_string(endtime).c_str());
12064 if (pwidth && *pwidth)
12065 sprintf(paramstr + strlen(paramstr), "&width=%s", pwidth);
12066 else {
12067 std::string wi = "640";
12068 db_get_value_string(hDB, 0, "/History/Display Settings/Width Individual", 0, &wi, TRUE);
12069 sprintf(paramstr + strlen(paramstr), "&width=%s", wi.c_str());
12070 }
12071 if (pheight && *pheight)
12072 sprintf(paramstr + strlen(paramstr), "&height=%s", pheight);
12073
12074 /* define image map */
12075 r->rsprintf("<map name=\"%s\">\r\n", hpanel);
12076
12077 if (!(pindex && *pindex)) {
12078 std::string path;
12079 path += "/History/Display/";
12080 path += hgroup;
12081 path += "/";
12082 path += hpanel;
12083 path += "/Variables";
12084 db_find_key(hDB, 0, path.c_str(), &hkey);
12085 if (hkey) {
12086 db_get_key(hDB, hkey, &key);
12087
12088 for (i = 0; i < key.num_values; i++) {
12089 std::string ref;
12090 //if (paramstr[0]) {
12091 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&%s&index=%d", hgroup, hpanel, paramstr, i);
12092 //} else {
12093 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&index=%d", hgroup, hpanel, i);
12094 //}
12095
12096 ref += "?cmd=oldhistory&group=";
12097 ref += hgroup;
12098 ref += "&panel=";
12099 ref += hpanel;
12100 if (paramstr[0]) {
12101 ref += "&";
12102 ref += paramstr;
12103 }
12104 ref += "&index=";
12105 ref += toString(i);
12106
12107 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());
12108 }
12109 }
12110 } else {
12111 std::string ref = "?cmd=oldhistory&group=";
12112 ref += hgroup;
12113 ref += "&panel=";
12114 ref += hpanel;
12115
12116 if (paramstr[0]) {
12117 ref += "&";
12118 ref += paramstr;
12119 }
12120
12121 if (equal_ustring(pwidth, "Large"))
12122 width = 1024;
12123 else if (equal_ustring(pwidth, "Small"))
12124 width = 320;
12125 else if (atoi(pwidth) > 0)
12126 width = atoi(pwidth);
12127 else
12128 width = 640;
12129
12130 r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 0, 0, width, 20, ref.c_str());
12131 }
12132
12133 r->rsprintf("</map>\r\n");
12134
12135 /* Display individual panels */
12136 if (pindex && *pindex)
12137 sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12138
12139 std::string ref;
12140 //sprintf(ref, "graph.gif?cmd=oldhistory&group=%s&panel=%s%s", hgroup, hpanel, paramstr);
12141 ref += "graph.gif?cmd=oldhistory&group=";
12142 ref += hgroup;
12143 ref += "&panel=";
12144 ref += hpanel;
12145 ref += paramstr;
12146
12147 /* put reference to graph */
12148 r->rsprintf("<tr><td colspan=2><img src=\"%s\" usemap=\"#%s\"></tr>\n", ref.c_str(), hpanel);
12149 }
12150
12151 else if (equal_ustring(hgroup, "All")) {
12152 /* Display all panels */
12153 db_find_key(hDB, 0, "/History/Display", &hkey);
12154 if (hkey)
12155 for (i = 0, k = 0;; i++) { // scan Groups
12156 db_enum_link(hDB, hkey, i, &hkeyp);
12157
12158 if (!hkeyp)
12159 break;
12160
12161 db_get_key(hDB, hkeyp, &key);
12162
12163 char enc_group_name[256];
12164 mstrlcpy(enc_group_name, key.name, sizeof(enc_group_name));
12165 urlEncode(enc_group_name, sizeof(enc_group_name));
12166
12167 for (j = 0;; j++, k++) {
12168 // scan items
12169 db_enum_link(hDB, hkeyp, j, &hikeyp);
12170
12171 if (!hikeyp)
12172 break;
12173
12174 db_get_key(hDB, hikeyp, &ikey);
12175
12176 char enc_panel_name[256];
12177 mstrlcpy(enc_panel_name, ikey.name, sizeof(enc_panel_name));
12178 urlEncode(enc_panel_name, sizeof(enc_panel_name));
12179
12180 std::string ref;
12181 ref += "graph.gif?width=Small";
12182 ref += "&cmd=oldhistory&group=";
12183 ref += enc_group_name;
12184 ref += "&panel=";
12185 ref += enc_panel_name;
12186
12187 std::string ref2;
12188 ref2 += "?cmd=oldhistory&group=";
12189 ref2 += enc_group_name;
12190 ref2 += "&panel=";
12191 ref2 += enc_panel_name;
12192
12193 if (endtime != 0) {
12194 char tmp[256];
12195 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
12196 ref += "&";
12197 ref += tmp;
12198 ref2 += "&";
12199 ref2 += tmp;
12200 }
12201
12202 if (k % 2 == 0)
12203 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
12204 else
12205 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
12206 } // items loop
12207 } // Groups loop
12208 } // All
12209 r->rsprintf("</table>\r\n");
12210 r->rsprintf("</div>\n"); // closing for <div id="mmain">
12211 r->rsprintf("</form>\n");
12212 r->rsprintf("</body></html>\r\n");
12213}
12214
12215
12216/*------------------------------------------------------------------*/
12217
12218void send_icon(Return* r, const char *icon)
12219{
12220 int length;
12221 const unsigned char *picon;
12222 char str[256], format[256];
12223 time_t now;
12224
12225 if (strstr(icon, "favicon.ico") != 0) {
12226 length = sizeof(favicon_ico);
12227 picon = favicon_ico;
12228 } else if (strstr(icon, "favicon.png") != 0) {
12229 length = sizeof(favicon_png);
12230 picon = favicon_png;
12231 } else
12232 return;
12233
12234 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
12235 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12236 r->rsprintf("Accept-Ranges: bytes\r\n");
12237
12238 /* set expiration time to one day */
12239 time(&now);
12240 now += (int) (3600 * 24);
12241 struct tm gmt_tms;
12242 gmtime_r(&now, &gmt_tms);
12243 strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12244 strftime(str, sizeof(str), format, &gmt_tms);
12245 r->rsprintf("Expires: %s\r\n", str);
12246
12247 if (equal_ustring(icon, "favicon.ico"))
12248 r->rsprintf("Content-Type: image/x-icon\r\n");
12249 else
12250 r->rsprintf("Content-Type: image/png\r\n");
12251
12252 r->rsprintf("Content-Length: %d\r\n\r\n", length);
12253
12254 r->rmemcpy(picon, length);
12255}
12256
12257/*------------------------------------------------------------------*/
12258
12260{
12261 std::string cookie_pwd;
12262 std::string cookie_wpwd;
12263 std::string cookie_cpwd;
12264 int refresh = 0;
12265 //int expand_equipment = 0;
12266};
12267
12268/*------------------------------------------------------------------*/
12269
12271{
12272 gMutex.lock();
12273 t->fTimeLocked = GetTimeSec();
12274}
12275
12277{
12279 gMutex.unlock();
12280}
12281
12282/*------------------------------------------------------------------*/
12283
12284void interprete(Param* p, Return* r, Attachment* a, const Cookies* c, const char *dec_path, RequestTrace* t)
12285/********************************************************************\
12286
12287 Routine: interprete
12288
12289 Purpose: Main interpreter of web commands
12290
12291 \********************************************************************/
12292{
12293 int status;
12294 HNDLE hkey, hDB;
12295
12296 //printf("dec_path [%s]\n", dec_path);
12297
12298 if (strstr(dec_path, "favicon.ico") != 0 ||
12299 strstr(dec_path, "favicon.png")) {
12300 send_icon(r, dec_path);
12301 return;
12302 }
12303
12304 const char* password = p->getparam("pwd");
12305 const char* wpassword = p->getparam("wpwd");
12306 const char* command = p->getparam("cmd");
12307
12308 //printf("interprete: dec_path [%s], command [%s]\n", dec_path, command);
12309
12311 MVOdb* odb = gOdb;
12312
12313 if (history_mode) {
12314 if (equal_ustring(command, "history")) {
12315 if (equal_ustring(command, "config")) {
12316 return;
12317 }
12318
12319 Lock(t);
12320 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12321 Unlock(t);
12322 return;
12323 }
12324 return;
12325 }
12326
12327 /* check for password */
12328 db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12329 if (!password[0] && hkey) {
12330 char str[256];
12331 int size = sizeof(str);
12332 db_get_data(hDB, hkey, str, &size, TID_STRING);
12333
12334 /* check for excemption */
12335 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12336 if (hkey == 0 && strcmp(c->cookie_pwd.c_str(), str) != 0) {
12337 Lock(t);
12338 show_password_page(r, dec_path, "");
12339 Unlock(t);
12340 return;
12341 }
12342 }
12343
12344 /*---- redirect with cookie if password given --------------------*/
12345
12346 if (password[0]) {
12347 r->rsprintf("HTTP/1.1 302 Found\r\n");
12348 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12349
12350 time_t now;
12351 time(&now);
12352
12353 now += 3600 * 24;
12354
12355 struct tm gmt_tms;
12356 gmtime_r(&now, &gmt_tms);
12357
12358 char str[256];
12359 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12360
12361 r->rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12362 ss_crypt(password, "mi"), str);
12363
12364 r->rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12365 return;
12366 }
12367
12368 if (wpassword[0]) {
12369 /* check if password correct */
12370 if (!check_web_password(r, hDB, dec_path, ss_crypt(wpassword, "mi"), p->getparam("redir")))
12371 return;
12372
12373 r->rsprintf("HTTP/1.1 302 Found\r\n");
12374 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12375
12376 time_t now;
12377 time(&now);
12378
12379 now += 3600 * 24;
12380
12381 struct tm gmt_tms;
12382 gmtime_r(&now, &gmt_tms);
12383
12384 char str[256];
12385 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", &gmt_tms);
12386
12387 r->rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", ss_crypt(wpassword, "mi"), str);
12388
12389 sprintf(str, "./%s", p->getparam("redir"));
12390 r->rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12391 return;
12392 }
12393
12394 /*---- send sound file -------------------------------------------*/
12395
12396 if (strlen(dec_path) > 3 &&
12397 dec_path[strlen(dec_path)-3] == 'm' &&
12398 dec_path[strlen(dec_path)-2] == 'p' &&
12399 dec_path[strlen(dec_path)-1] == '3') {
12400 if (strrchr(dec_path, '/'))
12401 send_resource(r, strrchr(dec_path, '/')+1);
12402 else
12403 send_resource(r, dec_path);
12404 return;
12405 }
12406
12407 /*---- send midas.js and midas.css -------------------------------*/
12408
12409 if (strstr(dec_path, "midas.js")) {
12410 send_resource(r, "midas.js");
12411 return;
12412 }
12413
12414 if (strstr(dec_path, "midas.css")) {
12415 send_resource(r, "midas.css");
12416 return;
12417 }
12418
12419 /*---- send mhttpd.js --------------------------------------------*/
12420
12421 if (strstr(dec_path, "mhttpd.js")) {
12422 send_resource(r, "mhttpd.js");
12423 return;
12424 }
12425
12426 /*---- send obsolete.js ------------------------------------------*/
12427
12428 if (strstr(dec_path, "obsolete.js")) {
12429 send_resource(r, "obsolete.js");
12430 return;
12431 }
12432
12433 /*---- send the obsolete mhttpd.css ------------------------------*/
12434
12435 if (strstr(dec_path, "mhttpd.css")) {
12436 send_resource(r, "mhttpd.css");
12437 return;
12438 }
12439
12440 /*---- send controls.js ------------------------------------------*/
12441
12442 if (strstr(dec_path, "controls.js")) {
12443 send_resource(r, "controls.js");
12444 return;
12445 }
12446
12447 /*---- send example web page -------------------------------------*/
12448
12449 if (equal_ustring(command, "example")) {
12450 send_resource(r, "example.html");
12451 return;
12452 }
12453
12454 /*---- send example custom page -------------------------------------*/
12455
12456 if (equal_ustring(command, "custom_example")) {
12457 send_resource(r, "custom_example.html");
12458 return;
12459 }
12460
12461 if (equal_ustring(command, "plot_example")) {
12462 send_resource(r, "plot_example.html");
12463 return;
12464 }
12465
12466 /*---- script command --------------------------------------------*/
12467
12468 if (p->getparam("script") && *p->getparam("script")) {
12469
12470 std::string str = msprintf("%s?script=%s", dec_path, p->getparam("script"));
12471 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12472 return;
12473
12474 std::string path;
12475 path += "/Script/";
12476 path += p->getparam("script");
12477
12478 Lock(t);
12479
12480 cm_exec_script(path.c_str());
12481
12482 Unlock(t);
12483
12484 if (p->isparam("redir"))
12485 redirect2(r, p->getparam("redir"));
12486 else
12487 redirect2(r, "");
12488
12489 return;
12490 }
12491
12492 /*---- customscript command --------------------------------------*/
12493
12494 if (p->getparam("customscript") && *p->getparam("customscript")) {
12495
12496 std::string str = msprintf("%s?customscript=%s", dec_path, p->getparam("customscript"));
12497 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12498 return;
12499
12500 std::string path;
12501 path += "/CustomScript/";
12502 path += p->getparam("customscript");
12503
12504 Lock(t);
12505
12506 cm_exec_script(path.c_str());
12507
12508 Unlock(t);
12509
12510 if (p->isparam("redir"))
12511 redirect2(r, p->getparam("redir"));
12512 else
12513 redirect2(r, str.c_str());
12514
12515 return;
12516 }
12517
12518 /*---- send the new html pages -----------------------------------*/
12519
12520 if (equal_ustring(command, "start")) {
12521 send_resource(r, "start.html");
12522 return;
12523 }
12524
12525 if ((equal_ustring(command, "") || equal_ustring(command, "status")) && strlen(dec_path) == 0) {
12526 if (midas::odb::exists("/Custom/Status")) {
12527 midas::odb custom("/Custom");
12528
12529 std::string filename = custom["Status"];
12530 filename = add_custom_path(filename);
12531
12532 // if custom file exists, send it (like normal web server)
12533 if (ss_file_exist(filename.c_str())) {
12534 send_file(r, filename);
12535 return;
12536 }
12537 } else
12538 send_resource(r, "status.html");
12539 return;
12540 }
12541
12542 if (equal_ustring(command, "eqtable")) {
12543 send_resource(r, "eqtable.html");
12544 return;
12545 }
12546
12547 if (equal_ustring(command, "newODB")) {
12548 send_resource(r, "odb.html");
12549 return;
12550 }
12551
12552 if (equal_ustring(command, "programs")) {
12553 send_resource(r, "programs.html");
12554 return;
12555 }
12556
12557 if (equal_ustring(command, "alarms")) {
12558 send_resource(r, "alarms.html");
12559 return;
12560 }
12561
12562 if (equal_ustring(command, "transition")) {
12563 send_resource(r, "transition.html");
12564 return;
12565 }
12566
12567 if (equal_ustring(command, "messages")) {
12568 send_resource(r, "messages.html");
12569 return;
12570 }
12571
12572 if (equal_ustring(command, "config") &&
12573 !(dec_path[0] == 'H' && dec_path[1] == 'S' && dec_path[2] == '/')) {
12574 send_resource(r, "config.html");
12575 return;
12576 }
12577
12578 if (equal_ustring(command, "chat")) {
12579 send_resource(r, "chat.html");
12580 return;
12581 }
12582
12583 if (equal_ustring(command, "buffers")) {
12584 send_resource(r, "buffers.html");
12585 return;
12586 }
12587
12588 if (equal_ustring(command, "Show elog")) {
12589 send_resource(r, "elog_show.html");
12590 return;
12591 }
12592
12593 if (equal_ustring(command, "Query elog")) {
12594 send_resource(r, "elog_query_form.html");
12595 return;
12596 }
12597
12598 if (equal_ustring(command, "New elog")) {
12599 send_resource(r, "elog_edit.html");
12600 return;
12601 }
12602
12603 if (equal_ustring(command, "Edit elog")) {
12604 send_resource(r, "elog_edit.html");
12605 return;
12606 }
12607
12608 if (equal_ustring(command, "Reply Elog")) {
12609 send_resource(r, "elog_edit.html");
12610 return;
12611 }
12612
12613 if (equal_ustring(command, "Last elog")) {
12614 send_resource(r, "elog_show.html");
12615 return;
12616 }
12617
12618 if (equal_ustring(command, "Submit Query")) {
12619 send_resource(r, "elog_query.html");
12620 return;
12621 }
12622
12623 if (equal_ustring(dec_path, "spinning-wheel.gif")) {
12624 send_resource(r, "spinning-wheel.gif");
12625 return;
12626 }
12627
12628 /*---- java script commands --------------------------------------*/
12629
12630 if (equal_ustring(command, "jset") ||
12631 equal_ustring(command, "jget") ||
12632 equal_ustring(command, "jcopy") ||
12633 equal_ustring(command, "jpaste") ||
12634 equal_ustring(command, "jkey") ||
12635 equal_ustring(command, "jcreate") ||
12636 equal_ustring(command, "jresize") ||
12637 equal_ustring(command, "jlink") ||
12638 equal_ustring(command, "jrename") ||
12639 equal_ustring(command, "jreorder") ||
12640 equal_ustring(command, "jdelete") ||
12641 equal_ustring(command, "jmsg") ||
12642 equal_ustring(command, "jalm") ||
12643 equal_ustring(command, "jgenmsg") ||
12644 equal_ustring(command, "jrpc_rev0") ||
12645 equal_ustring(command, "jrpc_rev1") ||
12646 equal_ustring(command, "jrpc")) {
12647 Lock(t);
12648 javascript_commands(p, r, c->cookie_cpwd.c_str());
12649 Unlock(t);
12650 return;
12651 }
12652
12653 /*---- history editord -------------------------------------------*/
12654
12655 if (equal_ustring(command, "hs_edit")) {
12656 send_resource(r, "hs_edit.html");
12657 return;
12658 }
12659
12660 /*---- history command -------------------------------------------*/
12661
12662 if (equal_ustring(command, "oldhistory")) {
12663 Lock(t);
12664 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12665 Unlock(t);
12666 return;
12667 }
12668
12669 if (equal_ustring(command, "history")) {
12670 send_resource(r, "history.html");
12671 return;
12672 }
12673
12674 /*---- MSCB command ----------------------------------------------*/
12675
12676 if (equal_ustring(command, "MSCB")) {
12677 if (equal_ustring(command, "set")) {
12678 std::string str;
12679 str += dec_path;
12680 str += "?";
12681 str += add_param_to_url("cmd", command);
12682 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12683 return;
12684 }
12685
12686 Lock(t);
12687
12688#ifdef HAVE_MSCB
12689 show_mscb_page(p, r, c->refresh);
12690#else
12691 show_error(r, "MSCB support not compiled into this version of mhttpd");
12692#endif
12693
12694 Unlock(t);
12695 return;
12696 }
12697
12698 /*---- help command ----------------------------------------------*/
12699
12700 if (equal_ustring(command, "help")) {
12701 Lock(t);
12702 show_help_page(r, dec_path);
12703 Unlock(t);
12704 return;
12705 }
12706
12707 /*---- trigger equipment readout ---------------------------*/
12708
12709 if (strncmp(command, "Trigger", 7) == 0) {
12710 std::string cmd;
12711 cmd += "?cmd=";
12712 cmd += command;
12713 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), cmd.c_str())) {
12714 return;
12715 }
12716
12717 Lock(t);
12718
12719 /* extract equipment name */
12720 char eq_name[NAME_LENGTH];
12721
12722 mstrlcpy(eq_name, command + 8, sizeof(eq_name));
12723 if (strchr(eq_name, ' '))
12724 *strchr(eq_name, ' ') = 0;
12725
12726 /* get frontend name */
12727 std::string path;
12728 path += "/Equipment/";
12729 path += eq_name;
12730 path += "/Common/Frontend name";
12731 char fe_name[NAME_LENGTH];
12732 int size = NAME_LENGTH;
12733 db_get_value(hDB, 0, path.c_str(), fe_name, &size, TID_STRING, TRUE);
12734
12735 /* and ID */
12736 path = "";
12737 path += "/Equipment/";
12738 path += eq_name;
12739 path += "/Common/Event ID";
12740 WORD event_id = 0;
12741 size = sizeof(event_id);
12742 db_get_value(hDB, 0, path.c_str(), &event_id, &size, TID_WORD, TRUE);
12743
12744 if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12745 std::string str;
12746 str += "Frontend \"";
12747 str += fe_name;
12748 str += "\" not running!";
12749 show_error(r, str.c_str());
12750 } else {
12751 HNDLE hconn;
12752 status = cm_connect_client(fe_name, &hconn);
12753 if (status != RPC_SUCCESS) {
12754 std::string str;
12755 str += "Cannot connect to frontend \"";
12756 str += fe_name;
12757 str +="\" !";
12758 show_error(r, str.c_str());
12759 } else {
12761 if (status != CM_SUCCESS)
12762 show_error(r, "Error triggering event");
12763 else
12764 redirect(r, "");
12765
12766 //cm_disconnect_client(hconn, FALSE);
12767 }
12768 }
12769
12770 Unlock(t);
12771
12772 return;
12773 }
12774
12775 /*---- switch to next subrun -------------------------------------*/
12776
12777 if (strncmp(command, "Next Subrun", 11) == 0) {
12778 int i = TRUE;
12779 db_set_value(hDB, 0, "/Logger/Next subrun", &i, sizeof(i), 1, TID_BOOL);
12780 redirect(r, "");
12781 return;
12782 }
12783
12784 /*---- cancel command --------------------------------------------*/
12785
12786 if (equal_ustring(command, "cancel")) {
12787 if (p->isparam("redir"))
12788 redirect(r, p->getparam("redir"));
12789 else
12790 redirect(r, "");
12791 return;
12792 }
12793
12794 /*---- set command -----------------------------------------------*/
12795
12796 if (equal_ustring(command, "set")) {
12797 char str[256];
12798 mstrlcpy(str, "?cmd=set", sizeof(str));
12799 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str))
12800 return;
12801
12802 const char* group = p->getparam("group");
12803 int index = atoi(p->getparam("index"));
12804 const char* value = p->getparam("value");
12805
12806 Lock(t);
12807 show_set_page(p, r, group, index, value);
12808 Unlock(t);
12809 return;
12810 }
12811
12812 /*---- find command ----------------------------------------------*/
12813
12814 if (equal_ustring(command, "find")) {
12815 const char* value = p->getparam("value");
12816 Lock(t);
12818 Unlock(t);
12819 return;
12820 }
12821
12822 /*---- CAMAC CNAF command ----------------------------------------*/
12823
12824 if (equal_ustring(command, "CNAF") || strncmp(dec_path, "CNAF", 4) == 0) {
12825 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), "?cmd=CNAF"))
12826 return;
12827
12828 Lock(t);
12829 show_cnaf_page(p, r);
12830 Unlock(t);
12831 return;
12832 }
12833
12834 /*---- ELog command ----------------------------------------------*/
12835
12836 if (equal_ustring(command, "elog")) {
12837 /* redirect to external ELOG if URL present */
12839 BOOL external_elog = FALSE;
12840 std::string external_elog_url;
12841 int size = sizeof(external_elog);
12842 status = db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
12843 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
12844 if (external_elog && (external_elog_url.length() > 0)) {
12845 redirect(r, external_elog_url.c_str());
12846 return;
12847 }
12848 send_resource(r, "elog_show.html");
12849 return;
12850 }
12851
12852 // special processing for "Elog last 7d", etc
12853
12854 char cmdx[32];
12855 mstrlcpy(cmdx, command, sizeof(cmdx));
12856 cmdx[9] = 0;
12857
12858 if (equal_ustring(cmdx, "Elog last")) {
12859 // "Elog last 7d", etc
12860 send_resource(r, "elog_query.html");
12861 return;
12862 }
12863
12864 if (equal_ustring(command, "Create ELog from this page")) {
12865 std::string redir;
12866 redir += "?cmd=New+elog";
12867 redir += "&odb_path=";
12868 redir += p->getparam("odb_path");
12869 redirect(r, redir.c_str());
12870 return;
12871 }
12872
12873 if (equal_ustring(command, "Submit elog")) {
12874 Lock(t);
12875 submit_elog(odb, p, r, a);
12876 Unlock(t);
12877 return;
12878 }
12879
12880 if (equal_ustring(command, "elog_att")) {
12881 Lock(t);
12882 show_elog_attachment(p, r, dec_path);
12883 Unlock(t);
12884 return;
12885 }
12886
12887 /*---- accept command --------------------------------------------*/
12888
12889 if (equal_ustring(command, "accept")) {
12890 int refresh = atoi(p->getparam("refr"));
12891
12892 /* redirect with cookie */
12893 r->rsprintf("HTTP/1.1 302 Found\r\n");
12894 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12895 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
12896
12897 time_t now;
12898 time(&now);
12899
12900 now += 3600 * 24 * 365;
12901
12902 struct tm gmt_tms;
12903 gmtime_r(&now, &gmt_tms);
12904
12905 char str[256];
12906 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12907
12908 r->rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
12909 r->rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
12910
12911 return;
12912 }
12913
12914#ifdef OBSOLETE
12915 /*---- slow control display --------------------------------------*/
12916
12917 if (equal_ustring(command, "eqtable")) {
12918 Lock(t);
12919 show_eqtable_page(p, r, c->refresh);
12920 Unlock(t);
12921 return;
12922 }
12923#endif
12924
12925 /*---- sequencer page --------------------------------------------*/
12926
12927 if (equal_ustring(command, "Sequencer")) {
12928 send_resource(r, "sequencer.html");
12929 return;
12930 }
12931
12932 // obsolete
12933 if (equal_ustring(command, "seq")) {
12934 send_resource(r, "sequencer.html");
12935 return;
12936 }
12937
12938 if (equal_ustring(command, "start_script")) {
12939 send_resource(r, "start_script.html");
12940 return;
12941 }
12942
12943 if (equal_ustring(command, "load_script")) {
12944 send_resource(r, "load_script.html");
12945 return;
12946 }
12947
12948 if (equal_ustring(command, "edit_script")) {
12949 send_resource(r, "edit_script.html");
12950 return;
12951 }
12952
12953 /*---- show ODB --------------------------------------------------*/
12954
12955 if (equal_ustring(command, "oldOdb")) {
12956 int write_access = TRUE;
12957 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
12958 if (hkey) {
12959 char str[256];
12960 int size = sizeof(str);
12961 db_get_data(hDB, hkey, str, &size, TID_STRING);
12962 if (strcmp(c->cookie_wpwd.c_str(), str) == 0)
12963 write_access = TRUE;
12964 else
12965 write_access = FALSE;
12966 }
12967
12968 std::string odb_path;
12969 if (p->getparam("odb_path") && *p->getparam("odb_path"))
12970 odb_path = p->getparam("odb_path");
12971
12972 Lock(t);
12973 show_odb_page(p, r, odb_path.c_str(), write_access);
12974 Unlock(t);
12975 return;
12976 }
12977
12978 /*---- New ODB browser --------------------------------------------*/
12979
12980 if (equal_ustring(command, "odb")) {
12981 send_resource(r, "odb.html");
12982 return;
12983 }
12984
12985 /*---- ODB show open records --------------------------------------*/
12986
12987 if (equal_ustring(command, "odb_sor")) {
12988 send_resource(r, "odb_sor.html");
12989 return;
12990 }
12991
12992 /*---- ODB show clients -------------------------------------------*/
12993
12994 if (equal_ustring(command, "odb_scl")) {
12995 send_resource(r, "odb_scl.html");
12996 return;
12997 }
12998
12999 /*---- old ODB path ----------------------------------------------*/
13000
13001 if ((command[0]==0) && dec_path[0]) {
13002 if (equal_ustring(dec_path, "root")) {
13003 std::string new_url = "./?cmd=odb";
13004 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13005 redirect_307(r, new_url.c_str());
13006 return;
13007 }
13008 }
13009
13010 if ((command[0]==0) && dec_path[0]) {
13011 HNDLE hkey;
13012 status = db_find_key(hDB, 0, dec_path, &hkey);
13013 //printf("try odb path [%s], status %d\n", dec_path, status);
13014 if (status == DB_SUCCESS) {
13015 int level = 0;
13016 for (const char* s = dec_path; *s; s++) {
13017 if (*s == '/')
13018 level++;
13019 }
13020 std::string new_url;
13021 if (level == 0) {
13022 // Top-level directory like /Logger, (which appears in dec_path as "Logger")
13023 new_url += "./";
13024 } else {
13025 for (int i=0; i<level; i++) {
13026 if (i>0)
13027 new_url += "/";
13028 new_url += "..";
13029 }
13030 }
13031 new_url += "?cmd=odb";
13032 new_url += "&odb_path=";
13033 new_url += urlEncode(dec_path);
13034 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13035 redirect_307(r, new_url.c_str());
13036 return;
13037 }
13038 }
13039
13040 /*---- event dump ------------------------------------------------*/
13041
13042 if (equal_ustring(command, "event dump")) {
13043 send_resource(r, "event_dump.html");
13044 return;
13045 }
13046
13047 /*---- custom page -----------------------------------------------*/
13048
13049 if (equal_ustring(command, "custom")) {
13050 Lock(t);
13051 show_custom_page(p, r, c->cookie_cpwd.c_str());
13052 Unlock(t);
13053 return;
13054 }
13055
13056 /*---- custom page accessed by direct URL that used to be under /CS/... ----*/
13057
13058 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13059 std::string odb_path;
13060 std::string value;
13061 int status;
13062
13063 odb_path = "";
13064 odb_path += "/Custom/Images/";
13065 odb_path += dec_path;
13066 odb_path += "/Background";
13067
13068 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13069
13070 //printf("Try custom gif [%s] status %d\n", odb_path.c_str(), status);
13071
13072 if (status == DB_SUCCESS) {
13073 if (strstr(dec_path, "..")) {
13074 std::string str;
13075 str += "Invalid custom gif name \'";
13076 str += dec_path;
13077 str += "\' contains \'..\'";
13078 show_error_404(r, str.c_str());
13079 return;
13080 }
13081
13082 Lock(t);
13083 show_custom_gif(r, dec_path);
13084 Unlock(t);
13085 return;
13086 }
13087
13088 bool found_custom = false;
13089
13090 odb_path = "";
13091 odb_path += "/Custom/";
13092 odb_path += dec_path;
13093
13094 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13095
13096 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13097
13098 if (status == DB_SUCCESS) {
13099 found_custom = true;
13100 } else {
13101 odb_path = "";
13102 odb_path += "/Custom/";
13103 odb_path += dec_path;
13104 odb_path += "&";
13105
13106 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13107
13108 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13109
13110 if (status == DB_SUCCESS) {
13111 found_custom = true;
13112 } else {
13113 odb_path = "";
13114 odb_path += "/Custom/";
13115 odb_path += dec_path;
13116 odb_path += "!";
13117
13118 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13119
13120 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13121
13122 if (status == DB_SUCCESS) {
13123 found_custom = true;
13124 }
13125 }
13126 }
13127
13128 if (found_custom) {
13129 //printf("custom file: serving [%s] value [%s]\n", dec_path, value.c_str());
13130 if (strstr(dec_path, "..")) {
13131 std::string str;
13132 str += "Invalid custom page name \'";
13133 str += dec_path;
13134 str += "\' contains \'..\'";
13135 show_error_404(r, str.c_str());
13136 return;
13137 }
13138
13139 p->setparam("page", dec_path);
13140 Lock(t);
13141 show_custom_page(p, r, c->cookie_cpwd.c_str());
13142 Unlock(t);
13143 return;
13144 }
13145 }
13146
13147 /* new custom pages */
13148 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13149 std::string custom_path;
13150 status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
13151 if ((status == DB_SUCCESS) && (custom_path.length() > 0)) {
13152 if (strstr(dec_path, "..")) {
13153 std::string str;
13154 str += "Invalid custom file name \'";
13155 str += dec_path;
13156 str += "\' contains \'..\'";
13157 show_error_404(r, str.c_str());
13158 return;
13159 }
13160
13161 std::string full_filename = add_custom_path(dec_path);
13162
13163 // if custom file exists, send it (like normal web server)
13164 if (ss_file_exist(full_filename.c_str())) {
13165 send_file(r, full_filename);
13166 return;
13167 }
13168 }
13169 }
13170
13171 /*---- redirect if web page --------------------------------------*/
13172
13173 //if (strlen(command) > 0) {
13174 // if (send_resource(r, std::string(command) + ".html", false))
13175 // return;
13176 //}
13177
13178 /*---- serve url as a resource file ------------------------------*/
13179
13180 if (strlen(p->getparam("path")) > 0) {
13181 if (send_resource(r, p->getparam("path"), false)) {
13182 return;
13183 }
13184 }
13185
13186 /*---- show status -----------------------------------------------*/
13187
13188 if (elog_mode) {
13189 redirect(r, "EL/");
13190 return;
13191 }
13192
13193 /* header */
13194 r->rsprintf("HTTP/1.1 400 Bad Request\r\n");
13195 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
13196 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
13197 r->rsprintf("\r\n");
13198 r->rsprintf("Error: Invalid URL \"%s\" or query \"%s\" or command \"%s\"\n", p->getparam("path"), p->getparam("query"), command);
13199}
13200
13201/*------------------------------------------------------------------*/
13202
13203void decode_query(Param* pp, const char *query_string)
13204{
13205 int len = strlen(query_string);
13206 char *buf = (char *)malloc(len+1);
13207 assert(buf != NULL);
13208 memcpy(buf, query_string, len+1);
13209 char* p = buf;
13210 p = strtok(p, "&");
13211 while (p != NULL) {
13212 char *pitem = p;
13213 p = strchr(p, '=');
13214 if (p != NULL) {
13215 *p++ = 0;
13216 urlDecode(pitem); // parameter name
13217 if (!equal_ustring(pitem, "format"))
13218 urlDecode(p); // parameter value
13219
13220 pp->setparam(pitem, p); // decoded query parameters
13221
13222 p = strtok(NULL, "&");
13223 }
13224 }
13225 free(buf);
13226}
13227
13228void decode_get(Return* rr, char *string, const Cookies* c, const char* url, const char* query_string, RequestTrace* t)
13229{
13230 char path[256];
13231
13232 //printf("decode_get: string [%s], decode_url %d, url [%s], query_string [%s]\n", string, decode_url, url, query_string);
13233
13234 Param* param = new Param();
13235
13236 param->initparam();
13237
13238 if (url)
13239 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13240 else {
13241 mstrlcpy(path, string + 1, sizeof(path)); /* strip leading '/' */
13242
13243 if (strchr(path, '?'))
13244 *strchr(path, '?') = 0;
13245 }
13246
13247 param->setparam("path", path);
13248
13249 assert(query_string != NULL);
13250
13251 decode_query(param, query_string);
13252
13253 param->setparam("query", query_string);
13254
13255 char dec_path[256];
13256 mstrlcpy(dec_path, path, sizeof(dec_path));
13257
13258 interprete(param, rr, NULL, c, dec_path, t);
13259
13260 param->freeparam();
13261 delete param;
13262}
13263
13264/*------------------------------------------------------------------*/
13265
13266void decode_post(Return* rr, const char *header, const char *string, const char *boundary, int length, const Cookies* c, const char* url, RequestTrace* t)
13267{
13268 bool debug_decode_post = false;
13269
13270 Param* param = new Param;
13271
13272 param->initparam();
13273
13274 char path[256];
13275
13276 if (url)
13277 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13278 else {
13279 mstrlcpy(path, header + 1, sizeof(path)); /* strip leading '/' */
13280 if (strchr(path, '?'))
13281 *strchr(path, '?') = 0;
13282 if (strchr(path, ' '))
13283 *strchr(path, ' ') = 0;
13284 }
13285 param->setparam("path", path); // undecoded path
13286
13287 Attachment* a = new Attachment;
13288
13289 const char* pinit = string;
13290
13291 /* return if no boundary defined */
13292 if (!boundary[0])
13293 return;
13294
13295 if (strstr(string, boundary))
13296 string = strstr(string, boundary) + strlen(boundary);
13297
13298 if (debug_decode_post)
13299 printf("decode_post: -->[%s]<--\n", string);
13300
13301 do {
13302 //printf("decode_post: [%s]\n", string);
13303 if (strstr(string, "name=")) {
13304 const char* pitem = strstr(string, "name=") + 5;
13305 if (*pitem == '\"')
13306 pitem++;
13307
13308 //printf("decode_post: pitem [%s]\n", pitem);
13309
13310 if (strncmp(pitem, "attfile", 7) == 0) {
13311 int n = pitem[7] - '1';
13312
13313 char file_name[256];
13314 file_name[0] = 0;
13315
13316 /* evaluate file attachment */
13317 if (strstr(pitem, "filename=")) {
13318 const char* p = strstr(pitem, "filename=") + 9;
13319 if (*p == '\"')
13320 p++;
13321 if (strstr(p, "\r\n\r\n"))
13322 string = strstr(p, "\r\n\r\n") + 4;
13323 else if (strstr(p, "\r\r\n\r\r\n"))
13324 string = strstr(p, "\r\r\n\r\r\n") + 6;
13325
13326 mstrlcpy(file_name, p, sizeof(file_name));
13327
13328 char* pp = file_name;
13329 if (strchr(pp, '\"'))
13330 *strchr(pp, '\"') = 0;
13331
13332 /* set attachment filename */
13333 char str[256];
13334 sprintf(str, "attachment%d", n);
13335 if (debug_decode_post)
13336 printf("decode_post: [%s] = [%s]\n", str, file_name);
13337 param->setparam(str, file_name); // file_name should be decoded?
13338 }
13339
13340 /* find next boundary */
13341 const char* ptmp = string;
13342 const char* p = NULL;
13343 do {
13344 while (*ptmp != '-')
13345 ptmp++;
13346
13347 p = strstr(ptmp, boundary);
13348 if (p != NULL) {
13349 p--;
13350 while (*p == '-')
13351 p--;
13352 if (*p == 10)
13353 p--;
13354 if (*p == 13)
13355 p--;
13356 p++;
13357 break;
13358 } else
13359 ptmp += strlen(ptmp);
13360
13361 } while (TRUE);
13362
13363 /* save pointer to file */
13364 if (file_name[0]) {
13365 size_t size = (POINTER_T) p - (POINTER_T) string;
13366 char* buf = (char*)malloc(size+1);
13367 if (!buf) {
13368 return;
13369 }
13370 memcpy(buf, string, size);
13371 buf[size] = 0; // make sure string is NUL terminated
13372 a->attachment_buffer[n] = buf;
13373 a->attachment_size[n] = size;
13374 if (debug_decode_post)
13375 printf("decode_post: attachment[%d] size %d data --->[%s]<---\n", n, (int)a->attachment_size[n], a->attachment_buffer[n]);
13376 }
13377
13378 string = strstr(p, boundary) + strlen(boundary);
13379 } else {
13380 const char* p = pitem;
13381 if (strstr(p, "\r\n\r\n"))
13382 p = strstr(p, "\r\n\r\n") + 4;
13383 else if (strstr(p, "\r\r\n\r\r\n"))
13384 p = strstr(p, "\r\r\n\r\r\n") + 6;
13385
13386 char* ppitem = (char*)strchr(pitem, '\"'); // NB: defeat "const char* string"
13387 if (ppitem)
13388 *ppitem = 0;
13389
13390 char* pb = (char*)(strstr(p, boundary)); // NB: defeat "const char* string"
13391 if (pb) {
13392 string = pb + strlen(boundary);
13393 *pb = 0;
13394 char* ptmp = (char*)(p + (strlen(p) - 1)); // NB: defeat "const char* string"
13395 while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13396 *ptmp-- = 0;
13397 } else {
13398 show_error(rr, "Invalid POST request");
13399 return;
13400 }
13401 if (debug_decode_post)
13402 printf("decode_post: [%s] = [%s]\n", pitem, p);
13403 param->setparam(pitem, p); // in decode_post()
13404 }
13405
13406 while (*string == '-' || *string == '\n' || *string == '\r')
13407 string++;
13408 }
13409
13410 } while ((POINTER_T) string - (POINTER_T) pinit < length);
13411
13412 char dec_path[256];
13413 mstrlcpy(dec_path, path, sizeof(dec_path));
13414
13415 interprete(param, rr, a, c, dec_path, t);
13416
13417 delete a;
13418 delete param;
13419}
13420
13421/*------------------------------------------------------------------*/
13422
13424{
13425 HNDLE hDB, hKeyEq, hKey;
13426 RUNINFO_STR(runinfo_str);
13427 int i, status;
13428 KEY key;
13429
13430 /* check /Runinfo structure */
13432 assert(status == DB_SUCCESS);
13433
13434 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), FALSE);
13435 if (status == DB_STRUCT_MISMATCH) {
13436 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), TRUE);
13437 if (status == DB_SUCCESS) {
13438 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo corrected successfully");
13439 } else {
13440 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13441 return 0;
13442 }
13443 } else if (status == DB_NO_KEY) {
13444 cm_msg(MERROR, "check_odb_records", "ODB subtree /Runinfo does not exist");
13445 status = db_create_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str());
13446 if (status == DB_SUCCESS) {
13447 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo created successfully");
13448 } else {
13449 cm_msg(MERROR, "check_odb_records", "Cannot create ODB subtree /Runinfo, db_create_record() status %d", status);
13450 return 0;
13451 }
13452 } else if (status != DB_SUCCESS) {
13453 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13454 return 0;
13455 }
13456
13457 /* check /Equipment/<name>/Common structures */
13458 if (db_find_key(hDB, 0, "/equipment", &hKeyEq) == DB_SUCCESS) {
13459 for (i = 0 ;; i++) {
13460 db_enum_key(hDB, hKeyEq, i, &hKey);
13461 if (!hKey)
13462 break;
13463 db_get_key(hDB, hKey, &key);
13464
13466 if (status == DB_STRUCT_MISMATCH) {
13468 if (status == DB_SUCCESS) {
13469 cm_msg(MINFO, "check_odb_records", "ODB subtree /Equipment/%s/Common corrected successfully", key.name);
13470 } else {
13471 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13472 }
13473 } else if (status != DB_SUCCESS) {
13474 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13475 }
13476 }
13477 }
13478
13479 return CM_SUCCESS;
13480}
13481
13482
13483/*------------------------------------------------------------------*/
13484
13485std::atomic_bool _abort{false};
13486
13487void ctrlc_handler(int sig)
13488{
13489 _abort = true;
13490}
13491
13492/*------------------------------------------------------------------*/
13493
13494#ifdef HAVE_MONGOOSE6
13495static std::vector<std::string> gUserAllowedHosts;
13496#endif
13497static std::vector<std::string> gAllowedHosts;
13498#ifdef HAVE_MONGOOSE6
13499static const std::string gOdbAllowedHosts = "/Experiment/Security/mhttpd hosts/Allowed hosts";
13500#endif
13501
13502#ifdef HAVE_MONGOOSE6
13503static void load_allowed_hosts(HNDLE hDB, HNDLE hKey, int index, void* info)
13504{
13505 if (hKey != 0)
13506 cm_msg(MINFO, "load_allowed_hosts", "Reloading mhttpd hosts access control list via hotlink callback");
13507
13508 gAllowedHosts.clear();
13509
13510 // copy the user allowed hosts
13511 for (unsigned int i=0; i<gUserAllowedHosts.size(); i++)
13512 gAllowedHosts.push_back(gUserAllowedHosts[i]);
13513
13514 int total = 0;
13515 int last = 0;
13516 for (int i=0; ; i++) {
13517 std::string s;
13518 int status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), i, &s, FALSE);
13519 //printf("get %d, status %d, string [%s]\n", i, status, s.c_str());
13520 if (status != DB_SUCCESS) {
13521 total = i;
13522 break;
13523 }
13524
13525 if (s.length() < 1) // skip emties
13526 continue;
13527
13528 if (s[0] == '#') // skip commented-out entries
13529 continue;
13530
13531 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
13532 gAllowedHosts.push_back(s);
13533 last = i;
13534 }
13535
13536 //printf("total %d, last %d\n", total, last);
13537
13538 if (total - last < 5) {
13539 int new_size = last + 10;
13540 //printf("new size %d\n", new_size);
13541 int status = db_resize_string(hDB, 0, gOdbAllowedHosts.c_str(), new_size, 256);
13542 if (status != DB_SUCCESS) {
13543 cm_msg(MERROR, "load_allowed_hosts", "Cannot resize the allowed hosts access control list, db_resize_string(%d) status %d", new_size, status);
13544 }
13545 }
13546}
13547
13548static int init_allowed_hosts()
13549{
13550 HNDLE hDB;
13551 HNDLE hKey;
13552 int status;
13553
13555
13556 // create "allowed hosts" so we can watch it
13557
13558 std::string s;
13559 status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), 0, &s, TRUE);
13560
13561 if (status != DB_SUCCESS) {
13562 cm_msg(MERROR, "init_allowed_hosts", "Cannot create the mhttpd hosts access control list, db_get_value_string() status %d", status);
13563 return status;
13564 }
13565
13566 status = db_find_key(hDB, 0, gOdbAllowedHosts.c_str(), &hKey);
13567
13568 if (status != DB_SUCCESS || hKey == 0) {
13569 cm_msg(MERROR, "init_allowed_hosts", "Cannot find the mhttpd hosts access control list, db_find_key() status %d", status);
13570 return status;
13571 }
13572
13573 load_allowed_hosts(hDB, 0, 0, NULL);
13574
13575 status = db_watch(hDB, hKey, load_allowed_hosts, NULL);
13576
13577 if (status != DB_SUCCESS) {
13578 cm_msg(MERROR, "init_allowed_hosts", "Cannot watch the mhttpd hosts access control list, db_watch() status %d", status);
13579 return status;
13580 }
13581
13582 return SUCCESS;
13583}
13584
13585 int check_midas_acl(const struct sockaddr *sa, int len) {
13586 // access control list is empty?
13587 if (gAllowedHosts.size() == 0)
13588 return 1;
13589
13590 char hname[NI_MAXHOST];
13591 hname[0] = 0;
13592
13593 int status;
13594 const char* status_string = "success";
13595
13596 status = getnameinfo(sa, len, hname, sizeof(hname), NULL, 0, 0);
13597
13598 if (status)
13599 status_string = gai_strerror(status);
13600
13601 //printf("connection from [%s], status %d (%s)\n", hname, status, status_string);
13602
13603 if (status != 0) {
13604 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, status, status_string);
13605 return 0;
13606 }
13607
13608 /* always permit localhost */
13609 if (strcmp(hname, "localhost.localdomain") == 0)
13610 return 1;
13611 if (strcmp(hname, "localhost") == 0)
13612 return 1;
13613
13614 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++)
13615 if (gAllowedHosts[i] == hname) {
13616 return 1;
13617 }
13618
13619 printf("Rejecting connection from \'%s\'\n", hname);
13620 return 0;
13621 }
13622
13623int open_listening_socket(int port)
13624{
13625 int status;
13626 struct sockaddr_in bind_addr;
13627
13628 /* create a new socket */
13629 int lsock = socket(AF_INET, SOCK_STREAM, 0);
13630
13631 if (lsock == -1) {
13632 printf("Cannot create socket, socket() errno %d (%s)\n", errno, strerror(errno));
13633 return -1;
13634 }
13635
13636 /* bind local node name and port to socket */
13637 memset(&bind_addr, 0, sizeof(bind_addr));
13638 bind_addr.sin_family = AF_INET;
13639 bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13640 bind_addr.sin_port = htons((short) port);
13641
13642 /* try reusing address */
13643 int flag = 1;
13644 status = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13645
13646 if (status < 0) {
13647 printf("Cannot setsockopt(SOL_SOCKET, SO_REUSEADDR), errno %d (%s)\n", errno, strerror(errno));
13648 return -1;
13649 }
13650
13651 status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13652
13653 if (status < 0) {
13654 printf("Cannot bind() to port %d, bind() errno %d (%s)\n", port, errno, strerror(errno));
13655 return -1;
13656 }
13657
13658 /* listen for connection */
13659 status = listen(lsock, SOMAXCONN);
13660 if (status < 0) {
13661 printf("Cannot listen() on port %d, errno %d (%s), bye!\n", port, errno, strerror(errno));
13662 return -1;
13663 }
13664
13665 printf("mhttpd is listening on port %d\n", port);
13666
13667 return lsock;
13668}
13669#endif
13670
13671/*------------------------------------------------------------------*/
13672
13673int try_file_mg(const char* try_dir, const char* filename, std::string& path, FILE** fpp, bool trace)
13674{
13675 if (fpp)
13676 *fpp = NULL;
13677 if (!try_dir)
13678 return SS_FILE_ERROR;
13679 if (strlen(try_dir) < 1)
13680 return SS_FILE_ERROR;
13681
13682 path = try_dir;
13683 if (path[path.length()-1] != DIR_SEPARATOR)
13684 path += DIR_SEPARATOR_STR;
13685 path += filename;
13686
13687 FILE* fp = fopen(path.c_str(), "r");
13688
13689 if (trace) {
13690 if (fp)
13691 printf("file \"%s\": OK!\n", path.c_str());
13692 else
13693 printf("file \"%s\": not found.\n", path.c_str());
13694 }
13695
13696 if (!fp)
13697 return SS_FILE_ERROR;
13698 else if (fpp)
13699 *fpp = fp;
13700 else
13701 fclose(fp);
13702
13703 return SUCCESS;
13704}
13705
13706int find_file_mg(const char* filename, std::string& path, FILE** fpp, bool trace)
13707{
13708 std::string exptdir = cm_get_path();
13709
13710 if (try_file_mg(".", filename, path, fpp, trace) == SUCCESS)
13711 return SUCCESS;
13712
13713 if (try_file_mg(getenv("MIDAS_DIR"), filename, path, fpp, trace) == SUCCESS)
13714 return SUCCESS;
13715
13716 if (try_file_mg(exptdir.c_str(), filename, path, fpp, trace) == SUCCESS)
13717 return SUCCESS;
13718
13719 if (try_file_mg(getenv("MIDASSYS"), filename, path, fpp, trace) == SUCCESS)
13720 return SUCCESS;
13721
13722 // setup default filename
13723 try_file_mg(exptdir.c_str(), filename, path, NULL, false);
13724 return SS_FILE_ERROR;
13725}
13726
13727#ifdef HAVE_MONGOOSE6
13728#include "mongoose6.h"
13729#endif
13730
13731#ifdef HAVE_MONGOOSE616
13732#undef closesocket
13733#include "mongoose616.h"
13734// cs_md5() in not in mongoose.h
13735extern void cs_md5(char buf[33], ...);
13736#endif
13737
13738static bool verbose_mg = false;
13739static bool trace_mg = false;
13740static bool trace_mg_recv = false;
13741static bool trace_mg_send = false;
13742static bool trace_mg_verbose = false;
13743#ifdef HAVE_MONGOOSE616
13744static bool multithread_mg = true;
13745#endif
13746
13747#ifdef HAVE_MONGOOSE6
13748static struct mg_mgr mgr_mg;
13749#endif
13750
13752 std::string username;
13753 std::string realm;
13754 std::string password;
13755};
13756
13757class Auth {
13758public:
13759 std::string realm;
13760 std::string passwd_filename;
13761 std::vector<AuthEntry> passwords;
13762public:
13763 int Init();
13764};
13765
13766static bool read_passwords(Auth* auth);
13767
13769{
13770 std::string exptname = cm_get_experiment_name();
13771
13772 if (!exptname.empty())
13773 realm = exptname;
13774 else
13775 realm = "midas";
13776
13777 bool ok = read_passwords(this);
13778 if (!ok) {
13779 cm_msg(MERROR, "mongoose", "mongoose web server password file \"%s\" has no passwords for realm \"%s\"", passwd_filename.c_str(), realm.c_str());
13780 cm_msg(MERROR, "mongoose", "please add passwords by running: htdigest %s %s midas", passwd_filename.c_str(), realm.c_str());
13781 return SS_FILE_ERROR;
13782 }
13783
13784 return SUCCESS;
13785}
13786
13787static Auth *gAuthMg = NULL;
13788
13789static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri,
13790 size_t uri_len, const char *ha1, size_t ha1_len,
13791 const char *nonce, size_t nonce_len, const char *nc,
13792 size_t nc_len, const char *cnonce, size_t cnonce_len,
13793 const char *qop, size_t qop_len, char *resp) {
13794 static const char colon[] = ":";
13795 static const size_t one = 1;
13796 char ha2[33];
13797
13798 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
13799 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
13800 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
13801 colon, one, ha2, sizeof(ha2) - 1, NULL);
13802}
13803
13804/*
13805 * Check for authentication timeout.
13806 * Clients send time stamp encoded in nonce. Make sure it is not too old,
13807 * to prevent replay attacks.
13808 * Assumption: nonce is a hexadecimal number of seconds since 1970.
13809 */
13810static int xmg_check_nonce(const char *nonce) {
13811 unsigned long now = (unsigned long) time(NULL);
13812 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
13813 return now < val || now - val < 3600;
13814}
13815
13816/*
13817 * Authenticate HTTP request against opened passwords file.
13818 * Returns 1 if authenticated, 0 otherwise.
13819 */
13820
13822 const char *domain) {
13823 mg_printf(c,
13824 "HTTP/1.1 401 Unauthorized\r\n"
13825 "WWW-Authenticate: Digest qop=\"auth\", "
13826 "realm=\"%s\", nonce=\"%lu\"\r\n"
13827 "Content-Length: 0\r\n\r\n",
13828 domain, (unsigned long) time(NULL));
13829}
13830
13831static bool read_passwords(Auth* auth)
13832{
13833 std::string path;
13834 FILE *fp;
13835 int status = find_file_mg("htpasswd.txt", path, &fp, trace_mg||verbose_mg);
13836
13837 auth->passwd_filename = path;
13838 auth->passwords.clear();
13839
13840 if (status != SUCCESS || fp == NULL) {
13841 cm_msg(MERROR, "mongoose", "mongoose web server cannot find password file \"%s\"", path.c_str());
13842 cm_msg(MERROR, "mongoose", "please create password file: touch %s", path.c_str());
13843 return false;
13844 }
13845
13846 bool have_realm = false;
13847 char buf[256];
13848
13849 /*
13850 * Read passwords file line by line. If should have htdigest format,
13851 * i.e. each line should be a colon-separated sequence:
13852 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
13853 */
13854 while (fgets(buf, sizeof(buf), fp) != NULL) {
13855 char f_user[256];
13856 char f_domain[256];
13857 char f_ha1[256];
13858
13859 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3) {
13860 AuthEntry e;
13861 e.realm = f_domain;
13862 e.username = f_user;
13863 e.password = f_ha1;
13864
13865 if (e.realm == auth->realm) {
13866 have_realm = true;
13867 auth->passwords.push_back(e);
13868 }
13869 }
13870 }
13871
13872 fclose(fp);
13873
13874 return have_realm;
13875}
13876
13877#ifdef HAVE_MONGOOSE6
13878std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13879{
13880 assert(!"this code is untested!");
13881
13882 char* buf = NULL;
13883 int buf_size = 0;
13884
13885 while (1) {
13886 if (buf_size == 0) {
13887 buf_size = 256;
13888 buf = (char*)malloc(buf_size);
13889 assert(buf != NULL);
13890 }
13891
13892 int size = mg_http_parse_header(hdr, var_name, buf, buf_size);
13893
13894 if (size <= 0) {
13895 free(buf);
13896 return "";
13897 }
13898
13899 if (size < buf_size) {
13900 std::string s = buf;
13901 free(buf);
13902 return s;
13903 }
13904
13905 buf_size = buf_size*2 + 16;
13906 buf = (char*)realloc(buf, buf_size);
13907 assert(buf != NULL);
13908 }
13909}
13910#endif
13911
13912#ifdef HAVE_MONGOOSE616
13913std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13914{
13915 char* buf = NULL;
13916 int buf_size = 0;
13917 int size = mg_http_parse_header2(hdr, var_name, &buf, buf_size);
13918 if (size <= 0)
13919 return "";
13920 assert(buf != NULL);
13921 std::string s = buf;
13922 free(buf);
13923 return s;
13924}
13925#endif
13926
13927static std::string check_digest_auth(struct http_message *hm, Auth* auth)
13928{
13929 char expected_response[33];
13930
13931 //printf("HereA!\n");
13932
13933 /* Parse "Authorization:" header, fail fast on parse error */
13934 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
13935
13936 if (!hdr)
13937 return "";
13938
13939 //printf("HereB!\n");
13940
13941 std::string user = find_var_mg(hdr, "username");
13942 std::string cnonce = find_var_mg(hdr, "cnonce");
13943 std::string response = find_var_mg(hdr, "response");
13944 std::string uri = find_var_mg(hdr, "uri");
13945 std::string qop = find_var_mg(hdr, "qop");
13946 std::string nc = find_var_mg(hdr, "nc");
13947 std::string nonce = find_var_mg(hdr, "nonce");
13948
13949 if (user.length()<1) return "";
13950 if (cnonce.length()<1) return "";
13951 if (response.length()<1) return "";
13952 if (uri.length()<1) return "";
13953 if (qop.length()<1) return "";
13954 if (nc.length()<1) return "";
13955 if (nonce.length()<1) return "";
13956
13957 if (xmg_check_nonce(nonce.c_str()) == 0) return "";
13958 //printf("HereB8!\n");
13959
13960 //printf("HereC!\n");
13961
13962 const char* uri_end = strchr(hm->uri.p, ' ');
13963 if (!uri_end) return "";
13964
13965 size_t uri_length = uri_end - hm->uri.p;
13966
13967 if (uri_length != uri.length())
13968 return "";
13969
13970 int cmp = strncmp(hm->uri.p, uri.c_str(), uri_length);
13971
13972 //printf("check URI: message %d %d [%d] authorization [%s]\n", (int)hm->uri.len, uri_length, cmp, uri);
13973
13974 if (cmp != 0)
13975 return "";
13976
13977 for (unsigned i=0; i<auth->passwords.size(); i++) {
13978 AuthEntry* e = &auth->passwords[i];
13979 if (e->username != user)
13980 continue;
13981 if (e->realm != auth->realm)
13982 continue;
13983 const char* f_ha1 = e->password.c_str();
13984 int uri_len = hm->uri.len;
13985 if (hm->uri.p[uri_len] == '?')
13986 uri_len += hm->query_string.len + 1; // "+1" accounts for the "?" character
13987 xmg_mkmd5resp(hm->method.p, hm->method.len,
13988 hm->uri.p, uri_len,
13989 f_ha1, strlen(f_ha1),
13990 nonce.c_str(), nonce.length(),
13991 nc.c_str(), nc.length(),
13992 cnonce.c_str(), cnonce.length(),
13993 qop.c_str(), qop.length(),
13994 expected_response);
13995 int cmp = strcasecmp(response.c_str(), expected_response);
13996 //printf("digest_auth: expected %s, got %s, cmp %d\n", expected_response, response.c_str(), cmp);
13997 if (cmp == 0) {
13998 return e->username;
13999 }
14000 }
14001
14002 return "";
14003}
14004
14005#ifdef HAVE_MONGOOSE616
14006
14007struct HostlistCacheEntry
14008{
14009 time_t time_created = 0;
14010 time_t time_last_used = 0;
14011 int count_used = 0;
14012 bool ipv4 = false;
14013 bool ipv6 = false;
14014 uint32_t ipv4addr = 0;
14015 struct in6_addr ipv6addr;
14016 std::string hostname;
14017 int gai_status = 0;
14018 std::string gai_strerror;
14019 bool ok = false;
14020};
14021
14022static std::vector<HostlistCacheEntry*> gHostlistCache;
14023
14024static void print_hostlist_cache()
14025{
14026 time_t now = time(NULL);
14027
14028 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14029 HostlistCacheEntry* e = gHostlistCache[i];
14030 if (!e) {
14031 // empty slot
14032 continue;
14033 }
14034
14035 printf("%3d: %s \"%s\", ok %d, count_used %d, age created: %d, last_used %d",
14036 i,
14037 e->ipv4?"IPv4":(e->ipv6?"IPv6":"????"),
14038 e->hostname.c_str(),
14039 e->ok,
14040 e->count_used,
14041 (int)(now - e->time_created),
14042 (int)(now - e->time_last_used));
14043
14044 if (e->gai_status) {
14045 printf(", getnameinfo() status %d (%s)", e->gai_status, e->gai_strerror.c_str());
14046 }
14047
14048 printf("\n");
14049 }
14050}
14051
14052static bool mongoose_check_hostlist(const union socket_address *sa)
14053{
14054 time_t now = time(NULL);
14055 bool ipv4 = false;
14056 bool ipv6 = false;
14057 uint32_t ipv4addr = 0;
14058 struct in6_addr ipv6addr;
14059
14060 if (sa->sa.sa_family == AF_INET) {
14061 ipv4 = true;
14062 ipv4addr = sa->sin.sin_addr.s_addr;
14063 } else if (sa->sa.sa_family == AF_INET6) {
14064 ipv6 = true;
14065 memcpy(&ipv6addr, &sa->sin6.sin6_addr, sizeof(ipv6addr));
14066 } else {
14067 printf("Rejecting connection from unknown address family %d (AF_xxx)\n", sa->sa.sa_family);
14068 return false;
14069 }
14070
14071 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14072 HostlistCacheEntry* e = gHostlistCache[i];
14073 if (!e) {
14074 // empty slot
14075 continue;
14076 }
14077
14078 if ((ipv4 == e->ipv4) && (ipv4addr == e->ipv4addr)) {
14079 // IPv4 address match
14080 e->time_last_used = now;
14081 e->count_used++;
14082 return e->ok;
14083 }
14084
14085 if ((ipv6 == e->ipv6) && (memcmp(&ipv6addr, &e->ipv6addr, sizeof(ipv6addr)) == 0)) {
14086 // IPv6 address match
14087 e->time_last_used = now;
14088 e->count_used++;
14089 return e->ok;
14090 }
14091
14092 // not this one. maybe expire old entries?
14093
14094 if (e->time_last_used < now - 24*60*60) {
14095 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);
14096 gHostlistCache[i] = NULL;
14097 delete e;
14098 }
14099 }
14100
14101 // not found in cache
14102
14103 assert(ipv4 || ipv6);
14104
14105 HostlistCacheEntry* e = new HostlistCacheEntry;
14106
14107 bool found = false;
14108 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14109 if (gHostlistCache[i] == NULL) {
14110 gHostlistCache[i] = e;
14111 found = true;
14112 }
14113 }
14114 if (!found) {
14115 gHostlistCache.push_back(e);
14116 }
14117
14118 e->time_created = now;
14119 e->time_last_used = now;
14120 e->count_used = 1;
14121 e->ipv4 = ipv4;
14122 e->ipv6 = ipv6;
14123 if (ipv4)
14124 e->ipv4addr = ipv4addr;
14125 if (ipv6)
14126 memcpy(&e->ipv6addr, &ipv6addr, sizeof(ipv6addr));
14127 e->ok = false;
14128
14129 char hname[NI_MAXHOST];
14130 hname[0] = 0;
14131
14132 e->gai_status = getnameinfo(&sa->sa, sizeof(*sa), hname, sizeof(hname), NULL, 0, 0);
14133
14134 if (e->gai_status) {
14135 e->gai_strerror = gai_strerror(e->gai_status);
14136
14137 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, e->gai_status, e->gai_strerror.c_str());
14138
14139 e->ok = false;
14140 return e->ok;
14141 }
14142
14143 printf("connection from \"%s\"\n", hname);
14144
14145 e->hostname = hname;
14146
14147 /* always permit localhost */
14148 if (e->hostname == "localhost.localdomain")
14149 e->ok = true;
14150 else if (e->hostname == "localhost")
14151 e->ok = true;
14152 else {
14153 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++) {
14154 if (e->hostname == gAllowedHosts[i]) {
14155 e->ok = true;
14156 }
14157 }
14158 }
14159
14160 if (!e->ok) {
14161 printf("Rejecting connection from \'%s\'\n", hname);
14162 }
14163
14164 print_hostlist_cache();
14165
14166 return e->ok;
14167}
14168
14169#endif
14170
14171static std::string mgstr(const mg_str* s)
14172{
14173 return std::string(s->p, s->len);
14174}
14175
14176static const std::string find_header_mg(const struct http_message *msg, const char* name)
14177{
14178 size_t nlen = strlen(name);
14179 for (int i=0; i<MG_MAX_HTTP_HEADERS; i++) {
14180 if (msg->header_names[i].len != nlen)
14181 continue;
14182 if (strncmp(msg->header_names[i].p, name, nlen) != 0)
14183 continue;
14184 return mgstr(&msg->header_values[i]);
14185 }
14186 return "";
14187}
14188
14189static const std::string find_cookie_mg(const struct http_message *msg, const char* cookie_name)
14190{
14191 const std::string cookies = find_header_mg(msg, "Cookie");
14192 if (cookies.length() < 1)
14193 return "";
14194 const char* p = strstr(cookies.c_str(), cookie_name);
14195 if (!p)
14196 return "";
14197 const char* v = p+strlen(cookie_name);
14198 if (*v != '=')
14199 return "";
14200 v++;
14201 //printf("cookie [%s] value [%s]\n", cookie_name, v);
14202 return v;
14203}
14204
14205// Generic event handler
14206
14207static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
14208{
14209 struct mbuf *io = &nc->recv_mbuf;
14210 switch (ev) {
14211 case MG_EV_POLL: // periodic call from loop_mg() via mg_mgr_poll()
14212 break;
14213 case MG_EV_ACCEPT:
14214 if (trace_mg)
14215 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> accept\n", nc, ev, ev_data);
14216 break;
14217 case MG_EV_RECV:
14218 if (trace_mg)
14219 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);
14220#if 0
14221 // This event handler implements simple TCP echo server
14222 mg_send(nc, io->buf, io->len); // Echo received data back
14223 mbuf_remove(io, io->len); // Discard data from recv buffer
14224#endif
14225 break;
14226 case MG_EV_SEND:
14227 if (trace_mg)
14228 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> send %d bytes\n", nc, ev, ev_data, *(int*)ev_data);
14229 break;
14230 case MG_EV_CLOSE:
14231 if (trace_mg)
14232 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> close\n", nc, ev, ev_data);
14233 break;
14234 default:
14235 if (trace_mg)
14236 printf("handle_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
14237 break;
14238 }
14239}
14240
14242{
14243 // extract password cookies
14244
14245 char cookie_pwd[256]; // general access password
14246 char cookie_wpwd[256]; // "write mode" password
14247 char cookie_cpwd[256]; // custom page and javascript password
14248
14249 cookie_pwd[0] = 0;
14250 cookie_wpwd[0] = 0;
14251 cookie_cpwd[0] = 0;
14252
14253 std::string s = find_cookie_mg(msg, "midas_pwd");
14254 if (s.length() > 0) {
14255 mstrlcpy(cookie_pwd, s.c_str(), sizeof(cookie_pwd));
14256 cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
14257 }
14258
14259 s = find_cookie_mg(msg, "midas_wpwd");
14260 if (s.length()) {
14261 mstrlcpy(cookie_wpwd, s.c_str(), sizeof(cookie_pwd));
14262 cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
14263 }
14264
14265 s = find_cookie_mg(msg, "cpwd");
14266 if (s.length()) {
14267 mstrlcpy(cookie_cpwd, s.c_str(), sizeof(cookie_pwd));
14268 cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
14269 }
14270
14271 // extract refresh rate
14272 c->refresh = DEFAULT_REFRESH;
14273 s = find_cookie_mg(msg, "midas_refr");
14274 if (s.length() > 0)
14275 c->refresh = atoi(s.c_str());
14276
14277 // extract equipment expand flag
14278 //c->expand_equipment = 0;
14279 //s = find_cookie_mg(msg, "midas_expeq");
14280 //if (s.length() > 0)
14281 // c->expand_equipment = atoi(s.c_str());
14282
14283 c->cookie_pwd = cookie_pwd;
14284 c->cookie_wpwd = cookie_wpwd;
14285 c->cookie_cpwd = cookie_cpwd;
14286}
14287
14288#define RESPONSE_SENT 1
14289#define RESPONSE_QUEUED 2
14290#define RESPONSE_501 3
14291
14292static int handle_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14293{
14294 Cookies cookies;
14295
14296 decode_cookies(&cookies, msg);
14297
14298 // lock shared structures
14299
14300#ifdef HAVE_MONGOOSE6
14301 int status = ss_mutex_wait_for(request_mutex, 0);
14302 assert(status == SS_SUCCESS);
14303#endif
14304
14305 //t->fTimeLocked = GetTimeSec();
14306
14307 // prepare return buffer
14308
14309 Return *rr = new Return();
14310
14311 rr->zero();
14312
14313 // call midas
14314
14315 decode_get(rr, NULL, &cookies, uri, query_string, t);
14316
14317 if (trace_mg)
14318 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14319
14321
14322 if (rr->return_length == -1) {
14323 delete rr;
14324#ifdef HAVE_MONGOOSE6
14325 //t->fTimeUnlocked = GetTimeSec();
14326 ss_mutex_release(request_mutex);
14327#endif
14328 return RESPONSE_501;
14329 }
14330
14331 if (rr->return_length == 0)
14332 rr->return_length = strlen(rr->return_buffer);
14333
14334 //t->fTimeUnlocked = GetTimeSec();
14335
14336#ifdef HAVE_MONGOOSE6
14337 ss_mutex_release(request_mutex);
14338#endif
14339
14340 mg_send(nc, rr->return_buffer, rr->return_length);
14341
14342 if (!strstr(rr->return_buffer, "Content-Length")) {
14343 // cannot do pipelined http if response generated by mhttpd
14344 // decode_get() has no Content-Length header.
14345 // must close the connection.
14347 }
14348
14349 t->fTimeSent = GetTimeSec();
14350
14351 delete rr;
14352
14353 return RESPONSE_SENT;
14354}
14355
14356#ifdef HAVE_MONGOOSE616
14357
14358static uint32_t s_ncseqno = 1;
14359
14360struct MongooseNcUserData
14361{
14362 uint32_t ncseqno = 0;
14363
14364 MongooseNcUserData() // ctor
14365 {
14366 ncseqno = s_ncseqno++;
14367 //printf("MongooseNcUserData::ctor! ncseqno %d\n", ncseqno);
14368 }
14369
14370 ~MongooseNcUserData() // ctor
14371 {
14372 //printf("MongooseNcUserData::dtor! ncseqno %d\n", ncseqno);
14373 }
14374};
14375
14376static uint32_t GetNcSeqno(const mg_connection* nc)
14377{
14378 if (nc == NULL)
14379 return 0;
14380 if (nc->user_data == NULL)
14381 return 0;
14382 const MongooseNcUserData* ncud = (const MongooseNcUserData*)nc->user_data;
14383 return ncud->ncseqno;
14384}
14385
14386static uint32_t s_wseqno = 1;
14387
14388struct MongooseWorkObject
14389{
14390 uint32_t wseqno = 0;
14391 mg_connection* nc = NULL;
14392 uint32_t wncseqno = 0;
14393 bool http_get = false;
14394 bool http_post = false;
14395 bool mjsonrpc = false;
14396 Cookies cookies;
14397 std::string origin;
14398 std::string uri;
14399 std::string query_string;
14400 std::string post_body;
14401 std::string post_boundary;
14402 RequestTrace* t = NULL;
14403 bool send_done = false;
14404
14405 MongooseWorkObject(mg_connection* xnc) // ctor
14406 {
14407 wseqno = s_wseqno++;
14408 nc = xnc;
14409 wncseqno = GetNcSeqno(nc);
14410
14411 //printf("MongooseWorkObject::ctor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14412 }
14413
14414 ~MongooseWorkObject() // dtor
14415 {
14416 //printf("MongooseWorkObject::dtor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14417
14418 // poison pointers
14419 nc = NULL;
14420 t = NULL;
14421 }
14422};
14423
14424struct MongooseThreadObject
14425{
14426 std::atomic_bool fIsRunning{false};
14427 std::thread* fThread = NULL; // thread
14428 void* fNc = NULL; // thread is attached to this network connection
14429 std::mutex fMutex;
14430 std::deque<MongooseWorkObject*> fQueue;
14431 std::condition_variable fNotify;
14432
14433 //MongooseThreadObject() // ctor
14434 //{
14435 // printf("MongooseThreadObject %p created!\n", this);
14436 //}
14437
14438 //~MongooseThreadObject() // dtor
14439 //{
14440 // printf("MongooseThreadObject %p destroyed!\n", this);
14441 //}
14442};
14443
14444static std::vector<MongooseThreadObject*> gMongooseThreads;
14445
14446static void mongoose_thread(MongooseThreadObject*);
14447
14448MongooseThreadObject* FindThread(void* nc)
14449{
14450 //printf("FindThread: nc %p, thread %s\n", nc, ss_tid_to_string(ss_gettid()).c_str());
14451
14452 MongooseThreadObject* last_not_connected = NULL;
14453
14454 for (auto it : gMongooseThreads) {
14455 MongooseThreadObject* to = it;
14456 if (to->fNc == nc) {
14457 //printf("to %p, nc %p: found thread\n", to, nc);
14458 return to;
14459 }
14460 if (to->fNc == NULL) {
14461 last_not_connected = to;
14462 }
14463 }
14464
14465 if (last_not_connected) {
14466 MongooseThreadObject* to = last_not_connected;
14467 to->fNc = nc;
14468 //printf("to %p, nc %p: reusing thread\n", to, nc);
14469 return to;
14470 }
14471
14472 MongooseThreadObject* to = new MongooseThreadObject();
14473
14474 to->fNc = nc;
14475
14476 //printf("to %p, nc %p: new thread\n", to, nc);
14477
14478 gMongooseThreads.push_back(to);
14479
14480 printf("Mongoose web server is using %d threads \r", (int)gMongooseThreads.size());
14481 fflush(stdout);
14482
14483 to->fThread = new std::thread(mongoose_thread, to);
14484
14485 return to;
14486}
14487
14488void FreeThread(void* nc)
14489{
14490 //printf("FreeThread, nc %p\n", nc);
14491
14492 for (auto it : gMongooseThreads) {
14493 MongooseThreadObject* to = it;
14494 if (to->fNc == nc) {
14495 //printf("to %p, nc %p: connection closed\n", to, nc);
14496 to->fNc = NULL;
14497 return;
14498 }
14499 }
14500
14501 //printf("to %p, nc %p: connection closed, but no thread\n", nullptr, nc);
14502}
14503
14504static void mongoose_queue(mg_connection* nc, MongooseWorkObject* w)
14505{
14506 w->nc = nc;
14507 MongooseThreadObject* to = FindThread(nc);
14508 assert(to->fNc == nc);
14509 to->fMutex.lock();
14510 to->fQueue.push_back(w);
14511 to->fMutex.unlock();
14512 to->fNotify.notify_one();
14513}
14514
14515static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag = false);
14516
14517static int queue_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14518{
14519 MongooseWorkObject* w = new MongooseWorkObject(nc);
14520 w->http_get = true;
14521 decode_cookies(&w->cookies, msg);
14522 w->uri = uri;
14523 w->query_string = query_string;
14524 w->t = t;
14525
14526 mongoose_queue(nc, w);
14527
14528 return RESPONSE_QUEUED;
14529}
14530
14531static int queue_decode_post(struct mg_connection *nc, const http_message* msg, const char* boundary, const char* uri, const char* query_string, RequestTrace* t)
14532{
14533 MongooseWorkObject* w = new MongooseWorkObject(nc);
14534 w->http_post = true;
14535 decode_cookies(&w->cookies, msg);
14536 w->uri = uri;
14537 w->query_string = query_string;
14538 w->post_body = mgstr(&msg->body);
14539 w->post_boundary = boundary;
14540 w->t = t;
14541
14542 mongoose_queue(nc, w);
14543
14544 return RESPONSE_QUEUED;
14545}
14546
14547static int queue_mjsonrpc(struct mg_connection *nc, const std::string& origin, const std::string& post_body, RequestTrace* t)
14548{
14549 MongooseWorkObject* w = new MongooseWorkObject(nc);
14550 w->mjsonrpc = true;
14551 w->origin = origin;
14552 w->post_body = post_body;
14553 w->t = t;
14554
14555 mongoose_queue(nc, w);
14556
14557 return RESPONSE_QUEUED;
14558}
14559
14560static int thread_http_get(mg_connection *nc, MongooseWorkObject *w)
14561{
14562 // lock shared structures
14563
14564 //int status = ss_mutex_wait_for(request_mutex, 0);
14565 //assert(status == SS_SUCCESS);
14566
14567 //w->t->fTimeLocked = GetTimeSec();
14568
14569 // prepare return buffer
14570
14571 Return *rr = new Return();
14572
14573 rr->zero();
14574
14575 // call midas
14576
14577 decode_get(rr, NULL, &w->cookies, w->uri.c_str(), w->query_string.c_str(), w->t);
14578
14579 if (trace_mg)
14580 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14581
14582 w->t->fTimeProcessed = GetTimeSec();
14583
14584 if (rr->return_length == -1) {
14585 delete rr;
14586 //w->t->fTimeUnlocked = GetTimeSec();
14587 //ss_mutex_release(request_mutex);
14588 return RESPONSE_501;
14589 }
14590
14591 if (rr->return_length == 0)
14592 rr->return_length = strlen(rr->return_buffer);
14593
14594 //w->t->fTimeUnlocked = GetTimeSec();
14595
14596 //ss_mutex_release(request_mutex);
14597
14598 bool close_flag = false;
14599
14600 if (!strstr(rr->return_buffer, "Content-Length")) {
14601 // cannot do pipelined http if response generated by mhttpd
14602 // decode_get() has no Content-Length header.
14603 // must close the connection.
14604 close_flag = true;
14605 }
14606
14607 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14608
14609 w->t->fTimeSent = GetTimeSec();
14610
14611 delete rr;
14612
14613 return RESPONSE_SENT;
14614}
14615
14616static int thread_http_post(mg_connection *nc, MongooseWorkObject *w)
14617{
14618 const char* post_data = w->post_body.c_str();
14619 int post_data_len = w->post_body.length();
14620
14621 // lock shared strctures
14622
14623 //int status = ss_mutex_wait_for(request_mutex, 0);
14624 //assert(status == SS_SUCCESS);
14625
14626 // prepare return buffer
14627
14628 Return* rr = new Return;
14629
14630 rr->zero();
14631
14632 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14633
14634 decode_post(rr, NULL, (char*)post_data, w->post_boundary.c_str(), post_data_len, &w->cookies, w->uri.c_str(), w->t);
14635
14636 if (trace_mg)
14637 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14638
14639 if (rr->return_length == -1) {
14640 //ss_mutex_release(request_mutex);
14641 delete rr;
14642 return RESPONSE_501;
14643 }
14644
14645 if (rr->return_length == 0)
14646 rr->return_length = strlen(rr->return_buffer);
14647
14648 //ss_mutex_release(request_mutex);
14649
14650 bool close_flag = false;
14651 if (!strstr(rr->return_buffer, "Content-Length")) {
14652 // cannot do pipelined http if response generated by mhttpd
14653 // decode_get() has no Content-Length header.
14654 // must close the connection.
14655 close_flag = true;
14656 }
14657
14658 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14659
14660 delete rr;
14661
14662 return RESPONSE_SENT;
14663
14664}
14665
14666static int thread_mjsonrpc(mg_connection *nc, MongooseWorkObject *w)
14667{
14668 w->t->fRPC = w->post_body;
14669
14670 //int status = ss_mutex_wait_for(request_mutex, 0);
14671 //assert(status == SS_SUCCESS);
14672
14673 //gMutex.lock();
14674 //w->t->fTimeLocked = GetTimeSec();
14675
14676 MJsonNode* reply = mjsonrpc_decode_post_data(w->post_body.c_str());
14677
14678 //w->t->fTimeUnlocked = GetTimeSec();
14679 //gMutex.unlock();
14680
14681 //ss_mutex_release(request_mutex);
14682
14683 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14684 const char* ptr;
14685 size_t size;
14686 reply->GetArrayBuffer(&ptr, &size);
14687
14688 std::string headers;
14689 headers += "HTTP/1.1 200 OK\n";
14690 if (w->origin.length() > 0)
14691 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14692 else
14693 headers += "Access-Control-Allow-Origin: *\n";
14694 headers += "Access-Control-Allow-Credentials: true\n";
14695 headers += "Content-Length: " + toString(size) + "\n";
14696 headers += "Content-Type: application/octet-stream\n";
14697 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14698
14699 //printf("sending headers: %s\n", headers.c_str());
14700 //printf("sending reply: %s\n", reply_string.c_str());
14701
14702 std::string send = headers + "\n";
14703
14704 w->t->fTimeProcessed = GetTimeSec();
14705
14706 mongoose_send(nc, w, send.c_str(), send.length(), ptr, size);
14707
14708 w->t->fTimeSent = GetTimeSec();
14709
14710 delete reply;
14711
14712 return RESPONSE_SENT;
14713 }
14714
14715 std::string reply_string = reply->Stringify();
14716 int reply_length = reply_string.length();
14717
14718 std::string headers;
14719 headers += "HTTP/1.1 200 OK\n";
14720 if (w->origin.length() > 0)
14721 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14722 else
14723 headers += "Access-Control-Allow-Origin: *\n";
14724 headers += "Access-Control-Allow-Credentials: true\n";
14725 headers += "Content-Length: " + toString(reply_length) + "\n";
14726 headers += "Content-Type: application/json\n";
14727 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14728
14729 if (trace_mg_verbose) {
14730 printf("-----------------------\nSending headers: %s", headers.c_str());
14731 std::string r = reply_string.substr(0, 128);
14732 printf("-----------------------\nSending reply (%d bytes): %s\n\n\n", (int)reply_string.size(), r.c_str());
14733 }
14734
14735 std::string send = headers + "\n" + reply_string;
14736
14737 w->t->fTimeProcessed = GetTimeSec();
14738
14739 mongoose_send(nc, w, send.c_str(), send.length(), NULL, 0);
14740
14741 w->t->fTimeSent = GetTimeSec();
14742
14743 delete reply;
14744
14745 return RESPONSE_SENT;
14746}
14747
14748static int thread_work_function(mg_connection *nc, MongooseWorkObject *w)
14749{
14750 if (w->http_get)
14751 return thread_http_get(nc, w);
14752 else if (w->http_post)
14753 return thread_http_post(nc, w);
14754 else if (w->mjsonrpc)
14755 return thread_mjsonrpc(nc, w);
14756 else
14757 return RESPONSE_501;
14758}
14759
14760#endif
14761
14762static int handle_decode_post(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14763{
14764
14765 char boundary[256];
14766 boundary[0] = 0;
14767 const std::string ct = find_header_mg(msg, "Content-Type");
14768 if (ct.length() > 0) {
14769 const char* s = strstr(ct.c_str(), "boundary=");
14770 if (s)
14771 mstrlcpy(boundary, s+9, sizeof(boundary));
14772 }
14773
14774#ifdef HAVE_MONGOOSE616
14775 if (multithread_mg)
14776 return queue_decode_post(nc, msg, boundary, uri, query_string, t);
14777#endif
14778
14779 Cookies cookies;
14780
14781 decode_cookies(&cookies, msg);
14782
14783 const char* post_data = msg->body.p;
14784 int post_data_len = msg->body.len;
14785
14786 // lock shared strctures
14787
14788#ifdef HAVE_MONGOOSE6
14789 int status = ss_mutex_wait_for(request_mutex, 0);
14790 assert(status == SS_SUCCESS);
14791#endif
14792
14793 // prepare return buffer
14794
14795 Return* rr = new Return;
14796
14797 rr->zero();
14798
14799 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14800
14801 decode_post(rr, NULL, (char*)post_data, boundary, post_data_len, &cookies, uri, t);
14802
14803 if (trace_mg)
14804 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14805
14806 if (rr->return_length == -1) {
14807#ifdef HAVE_MONGOOSE6
14808 ss_mutex_release(request_mutex);
14809#endif
14810 delete rr;
14811 return RESPONSE_501;
14812 }
14813
14814 if (rr->return_length == 0)
14815 rr->return_length = strlen(rr->return_buffer);
14816
14817#ifdef HAVE_MONGOOSE6
14818 ss_mutex_release(request_mutex);
14819#endif
14820
14821 mg_send(nc, rr->return_buffer, rr->return_length);
14822
14823 if (!strstr(rr->return_buffer, "Content-Length")) {
14824 // cannot do pipelined http if response generated by mhttpd
14825 // decode_get() has no Content-Length header.
14826 // must close the connection.
14828 }
14829
14830 delete rr;
14831
14832 return RESPONSE_SENT;
14833}
14834
14835static int handle_http_get(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14836{
14837 std::string query_string = mgstr(&msg->query_string);
14838
14839 if (trace_mg||verbose_mg)
14840 printf("handle_http_get: uri [%s], query [%s]\n", uri, query_string.c_str());
14841
14842 if (query_string == "mjsonrpc_schema") {
14843 MJsonNode* s = mjsonrpc_get_schema();
14844 std::string reply = s->Stringify();
14845 delete s;
14846
14847 int reply_length = reply.length();
14848
14849 const std::string origin_header = find_header_mg(msg, "Origin");
14850
14851 std::string headers;
14852 headers += "HTTP/1.1 200 OK\n";
14853 if (origin_header.length() > 0)
14854 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14855 else
14856 headers += "Access-Control-Allow-Origin: *\n";
14857 headers += "Access-Control-Allow-Credentials: true\n";
14858 headers += "Content-Length: " + toString(reply_length) + "\n";
14859 headers += "Content-Type: application/json\n";
14860 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14861
14862 //printf("sending headers: %s\n", headers.c_str());
14863 //printf("sending reply: %s\n", reply.c_str());
14864
14865 std::string send = headers + "\n" + reply;
14866
14868
14869 mg_send(nc, send.c_str(), send.length());
14870
14871 t->fTimeSent = GetTimeSec();
14872
14873 return RESPONSE_SENT;
14874 }
14875
14876 if (query_string == "mjsonrpc_schema_text") {
14877 MJsonNode* s = mjsonrpc_get_schema();
14878 std::string reply = mjsonrpc_schema_to_text(s);
14879 delete s;
14880
14881 int reply_length = reply.length();
14882
14883 const std::string origin_header = find_header_mg(msg, "Origin");
14884
14885 std::string headers;
14886 headers += "HTTP/1.1 200 OK\n";
14887 if (origin_header.length() > 0)
14888 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14889 else
14890 headers += "Access-Control-Allow-Origin: *\n";
14891 headers += "Access-Control-Allow-Credentials: true\n";
14892 headers += "Content-Length: " + toString(reply_length) + "\n";
14893 headers += "Content-Type: text/plain\n";
14894 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14895
14896 //printf("sending headers: %s\n", headers.c_str());
14897 //printf("sending reply: %s\n", reply.c_str());
14898
14899 std::string send = headers + "\n" + reply;
14900
14902
14903 mg_send(nc, send.c_str(), send.length());
14904
14905 t->fTimeSent = GetTimeSec();
14906
14907 return RESPONSE_SENT;
14908 }
14909
14910#ifdef HAVE_MONGOOSE616
14911 if (multithread_mg)
14912 return queue_decode_get(nc, msg, uri, query_string.c_str(), t);
14913#endif
14914
14915 return handle_decode_get(nc, msg, uri, query_string.c_str(), t);
14916}
14917
14918static int handle_http_post(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14919{
14920 std::string query_string = mgstr(&msg->query_string);
14921 std::string post_data = mgstr(&msg->body);
14922
14923 if (trace_mg||verbose_mg)
14924 printf("handle_http_post: uri [%s], query [%s], post data %d bytes\n", uri, query_string.c_str(), (int)post_data.length());
14925 if (trace_mg_verbose)
14926 printf("handle_http_post: post data = \n%s\n", post_data.c_str());
14927
14928 if (query_string.substr(0, 8) == "mjsonrpc") { // ignore any parameter after "mjsonrpc"
14929 const std::string origin_header = find_header_mg(msg, "Origin");
14930 const std::string ctype_header = find_header_mg(msg, "Content-Type");
14931
14932 if (strstr(ctype_header.c_str(), "application/json") == NULL) {
14933 std::string headers;
14934 headers += "HTTP/1.1 415 Unsupported Media Type\n";
14935 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14936
14937 //printf("sending headers: %s\n", headers.c_str());
14938 //printf("sending reply: %s\n", reply.c_str());
14939
14940 if (trace_mg_verbose)
14941 printf("handle_http_post: unsupported media type \"%s\"\n", ctype_header.c_str());
14942
14943 std::string send = headers + "\n";
14944
14946
14947 mg_send(nc, send.c_str(), send.length());
14948
14949 t->fTimeSent = GetTimeSec();
14950
14951 return RESPONSE_SENT;
14952 }
14953
14954#ifdef HAVE_MONGOOSE616
14955 if (multithread_mg)
14956 return queue_mjsonrpc(nc, origin_header, post_data, t);
14957#endif
14958
14959 //printf("post body: %s\n", post_data.c_str());
14960
14961 t->fRPC = post_data;
14962
14963#ifdef HAVE_MONGOOSE6
14964 int status = ss_mutex_wait_for(request_mutex, 0);
14965 assert(status == SS_SUCCESS);
14966#endif
14967
14968 //t->fTimeLocked = GetTimeSec();
14969
14970 MJsonNode* reply = mjsonrpc_decode_post_data(post_data.c_str());
14971
14972 //t->fTimeUnlocked = GetTimeSec();
14973
14974#ifdef HAVE_MONGOOSE6
14975 ss_mutex_release(request_mutex);
14976#endif
14977
14978 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14979 const char* ptr;
14980 size_t size;
14981 reply->GetArrayBuffer(&ptr, &size);
14982
14983 std::string headers;
14984 headers += "HTTP/1.1 200 OK\n";
14985 if (origin_header.length() > 0)
14986 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14987 else
14988 headers += "Access-Control-Allow-Origin: *\n";
14989 headers += "Access-Control-Allow-Credentials: true\n";
14990 headers += "Content-Length: " + toString(size) + "\n";
14991 headers += "Content-Type: application/octet-stream\n";
14992 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14993
14994 //printf("sending headers: %s\n", headers.c_str());
14995 //printf("sending reply: %s\n", reply_string.c_str());
14996
14997 std::string send = headers + "\n";
14998
15000
15001 mg_send(nc, send.c_str(), send.length());
15002 mg_send(nc, ptr, size);
15003
15004 t->fTimeSent = GetTimeSec();
15005
15006 delete reply;
15007
15008 return RESPONSE_SENT;
15009 }
15010
15011 std::string reply_string = reply->Stringify();
15012 int reply_length = reply_string.length();
15013
15014 std::string headers;
15015 headers += "HTTP/1.1 200 OK\n";
15016 if (origin_header.length() > 0)
15017 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
15018 else
15019 headers += "Access-Control-Allow-Origin: *\n";
15020 headers += "Access-Control-Allow-Credentials: true\n";
15021 headers += "Content-Length: " + toString(reply_length) + "\n";
15022 headers += "Content-Type: application/json\n";
15023 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15024
15025 //printf("sending headers: %s\n", headers.c_str());
15026 //printf("sending reply: %s\n", reply_string.c_str());
15027
15028 std::string send = headers + "\n" + reply_string;
15029
15031
15032 mg_send(nc, send.c_str(), send.length());
15033
15034 t->fTimeSent = GetTimeSec();
15035
15036 delete reply;
15037
15038 return RESPONSE_SENT;
15039 }
15040
15041 return handle_decode_post(nc, msg, uri, query_string.c_str(), t);
15042}
15043
15045{
15046 //
15047 // JSON-RPC CORS pre-flight request, see
15048 // https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
15049 //
15050 // OPTIONS /resources/post-here/ HTTP/1.1
15051 // Host: bar.other
15052 // User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
15053 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
15054 // Accept-Language: en-us,en;q=0.5
15055 // Accept-Encoding: gzip,deflate
15056 // Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
15057 // Connection: keep-alive
15058 // Origin: http://foo.example
15059 // Access-Control-Request-Method: POST
15060 // Access-Control-Request-Headers: X-PINGOTHER
15061 //
15062 // HTTP/1.1 200 OK
15063 // Date: Mon, 01 Dec 2008 01:15:39 GMT
15064 // Server: Apache/2.0.61 (Unix)
15065 // Access-Control-Allow-Origin: http://foo.example
15066 // Access-Control-Allow-Methods: POST, GET, OPTIONS
15067 // Access-Control-Allow-Headers: X-PINGOTHER
15068 // Access-Control-Max-Age: 1728000
15069 // Vary: Accept-Encoding, Origin
15070 // Content-Encoding: gzip
15071 // Content-Length: 0
15072 // Keep-Alive: timeout=2, max=100
15073 // Connection: Keep-Alive
15074 // Content-Type: text/plain
15075 //
15076
15077 const std::string origin_header = find_header_mg(msg, "Origin");
15078
15079 if (trace_mg||verbose_mg)
15080 printf("handle_http_options_cors: origin [%s]\n", origin_header.c_str());
15081
15082 std::string headers;
15083 headers += "HTTP/1.1 200 OK\n";
15084 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15085 if (origin_header.length() > 0)
15086 headers += "Access-Control-Allow-Origin: " + origin_header + "\n";
15087 else
15088 headers += "Access-Control-Allow-Origin: *\n";
15089 headers += "Access-Control-Allow-Headers: Content-Type\n";
15090 headers += "Access-Control-Allow-Credentials: true\n";
15091 headers += "Access-Control-Max-Age: 120\n";
15092 headers += "Content-Length: 0\n";
15093 headers += "Content-Type: text/plain\n";
15094 //printf("sending headers: %s\n", headers.c_str());
15095 //printf("sending reply: %s\n", reply.c_str());
15096
15097 std::string send = headers + "\n";
15098
15100
15101 mg_send(nc, send.c_str(), send.length());
15102
15103 t->fTimeSent = GetTimeSec();
15104}
15105
15106// HTTP event handler
15107
15108static bool mongoose_passwords_enabled(const struct mg_connection *nc);
15109
15110#ifdef HAVE_MONGOOSE616
15111static MVOdb* gProxyOdb = NULL;
15112#endif
15113
15115{
15116 std::string method = mgstr(&msg->method);
15117 std::string query_string = mgstr(&msg->query_string);
15118 std::string uri_encoded = mgstr(&msg->uri);
15119 std::string uri = UrlDecode(uri_encoded.c_str());
15120 mg_str* user_mg_str = mg_get_http_header(msg, "X-Remote-User");
15121 std::string user;
15122
15123 if (user_mg_str)
15124 user = mgstr(user_mg_str);
15125
15126 if (trace_mg)
15127 printf("handle_http_message: method [%s] uri [%s] proto [%s] user [%s]\n", method.c_str(), uri.c_str(), mgstr(&msg->proto).c_str(), user.c_str());
15128
15129 RequestTrace* t = new RequestTrace;
15131 t->fMethod = method;
15132 t->fUri = uri;
15133 t->fQuery = query_string;
15134
15135 // process OPTIONS for Cross-origin (CORS) preflight request
15136 // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
15137 if (method == "OPTIONS" && query_string == "mjsonrpc" && mg_get_http_header(msg, "Access-Control-Request-Method") != NULL) {
15138 handle_http_options_cors(nc, msg, t);
15139 t->fCompleted = true;
15141 return;
15142 }
15143
15145 std::string username = check_digest_auth(msg, gAuthMg);
15146
15147 // Cannot re-read the password file - it is not thread safe to do so
15148 // unless I lock gAuthMg for each call check_digest_auth() and if I do so,
15149 // I will serialize (single-thread) all the http requests and defeat
15150 // the whole point of multithreading the web server. K.O.
15151 //
15153 //if (username.length() < 1) {
15154 // bool ok = read_passwords(&gAuthMg);
15155 // if (ok)
15156 // username = check_digest_auth(msg, &gAuthMg);
15157 //}
15158
15159 if (trace_mg)
15160 printf("handle_http_message: auth user: \"%s\"\n", username.c_str());
15161
15162 if (username.length() == 0) {
15163 if (trace_mg||verbose_mg)
15164 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());
15165
15167 t->fCompleted = true;
15169 return;
15170 }
15171 t->fAuthOk = true;
15172 } else {
15173 t->fAuthOk = true;
15174 }
15175
15176#ifdef HAVE_MONGOOSE616
15177 if (gProxyOdb && starts_with(uri, "/proxy/")) {
15178 std::string::size_type p1 = uri.find("/", 1);
15179 if (p1 == uri.length()-1) {
15180 std::string response = "404 Not Found (Proxy name is missing)";
15181 mg_send_head(nc, 404, response.length(), NULL);
15182 mg_send(nc, response.c_str(), response.length());
15183 delete t;
15184 return;
15185 }
15186 std::string::size_type p2 = uri.find("/", p1+1);
15187 if (p2 == std::string::npos) {
15188 std::string response = "404 Not Found (Proxy URL should end with a slash)";
15189 mg_send_head(nc, 404, response.length(), NULL);
15190 mg_send(nc, response.c_str(), response.length());
15191 delete t;
15192 return;
15193 }
15194 std::string p = uri.substr(p1+1, p2-p1-1);
15195 //printf("uri [%s], p1: %d, p2: %d, substr: [%s]\n", uri.c_str(), (int)p1, (int)p2, p.c_str());
15196 if (p.length() < 1) {
15197 std::string response = "404 Not Found (Double-slash or Proxy name is too short)";
15198 mg_send_head(nc, 404, response.length(), NULL);
15199 mg_send(nc, response.c_str(), response.length());
15200 delete t;
15201 return;
15202 }
15203 std::string destination;
15204 gProxyOdb->RS(p.c_str(), &destination);
15205 if (destination.length() < 1) {
15206 std::string response = "404 Not Found (Proxy not found in ODB)";
15207 mg_send_head(nc, 404, response.length(), NULL);
15208 mg_send(nc, response.c_str(), response.length());
15209 delete t;
15210 return;
15211 } else if (destination[0] == '#') {
15212 std::string response = "404 Not Found (Proxy commented-out in ODB)";
15213 mg_send_head(nc, 404, response.length(), NULL);
15214 mg_send(nc, response.c_str(), response.length());
15215 delete t;
15216 return;
15217 } else if (ends_with_char(destination, '/')) {
15218 std::string response = "404 Not Found (Proxy address should not end with a slash)";
15219 mg_send_head(nc, 404, response.length(), NULL);
15220 mg_send(nc, response.c_str(), response.length());
15221 delete t;
15222 return;
15223 } else if (!starts_with(destination, "http")) {
15224 std::string response = "404 Not Found (Proxy address does not start with http";
15225 mg_send_head(nc, 404, response.length(), NULL);
15226 mg_send(nc, response.c_str(), response.length());
15227 delete t;
15228 return;
15229 } else {
15230 std::string m;
15231 m += "/proxy";
15232 m += "/";
15233 m += p;
15234 mg_str mount = mg_mk_str(m.c_str());
15235 mg_str upstream = mg_mk_str(destination.c_str());
15236 if (verbose_mg||trace_mg) {
15237 printf("proxy: uri [%s] mount [%s] upstream [%s]\n", uri.c_str(), mgstr(&mount).c_str(), mgstr(&upstream).c_str());
15238 }
15239 mg_http_reverse_proxy(nc, msg, mount, upstream);
15240 delete t;
15241 return;
15242 }
15243 }
15244#endif
15245
15246 int response = RESPONSE_501;
15247
15248 if (method == "GET")
15249 response = handle_http_get(nc, msg, uri.c_str(), t);
15250 else if (method == "POST")
15251 response = handle_http_post(nc, msg, uri.c_str(), t);
15252
15253 if (response == RESPONSE_501) {
15254 if (trace_mg||verbose_mg)
15255 printf("handle_http_message: sending 501 Not Implemented error\n");
15256
15257 std::string response = "501 Not Implemented";
15258 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15259 mg_send(nc, response.c_str(), response.length());
15260 }
15261
15262 if (response != RESPONSE_QUEUED) {
15263 t->fCompleted = true;
15265 }
15266}
15267
15268#ifdef HAVE_MONGOOSE6
15269
15270static void handle_http_event_mg(struct mg_connection *nc, int ev, void *ev_data)
15271{
15272 switch (ev) {
15273 case MG_EV_HTTP_REQUEST:
15274 if (trace_mg)
15275 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15276 handle_http_message(nc, (http_message*)ev_data);
15277 break;
15278 default:
15279 if (trace_mg)
15280 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15281 break;
15282 }
15283}
15284
15285static void handle_http_redirect(struct mg_connection *nc, int ev, void *ev_data)
15286{
15287 switch (ev) {
15288 case MG_EV_HTTP_REQUEST:
15289 {
15290 http_message* msg = (http_message*)ev_data;
15291 if (trace_mg)
15292 printf("handle_http_redirect: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15293
15294 mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: https://%s%s\r\n\r\n",
15295 ((std::string*)(nc->user_data))->c_str(),
15296 mgstr(&msg->uri).c_str());
15298 }
15299 break;
15300 default:
15301 if (trace_mg)
15302 printf("handle_http_redirect: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15303 }
15304}
15305
15306#endif
15307
15308#ifdef HAVE_MONGOOSE616
15309
15310// from mongoose examples/multithreaded/multithreaded.c
15311
15312//static sock_t s_sock[2];
15313static std::atomic_bool s_shutdown{false};
15314static struct mg_mgr s_mgr;
15315static std::atomic_int s_rseqno{1};
15316static std::mutex s_mg_broadcast_mutex;
15317
15318#if 0
15319// This info is passed to the worker thread
15320struct work_request {
15321 void* nc;
15322 MongooseWorkObject* w;
15323};
15324#endif
15325
15326// This info is passed by the worker thread to mg_broadcast
15327struct work_result {
15328 mg_connection* nc = NULL;
15329 uint32_t check = 0x12345678;
15330 int rseqno = 0;
15331 MongooseWorkObject* w = NULL;
15332 const char* p1 = NULL;
15333 size_t s1 = 0;
15334 const char* p2 = NULL;
15335 size_t s2 = 0;
15336 bool close_flag = false;
15337 bool send_501 = false;
15338};
15339
15340#if 0
15341static void mongoose_queue(void *nc, MongooseWorkObject *w)
15342{
15343 struct work_request req = {nc, w};
15344
15345 //printf("nc: %p: wseqno: %d, queue work object!\n", nc, w->wseqno);
15346
15347 if (write(s_sock[0], &req, sizeof(req)) < 0) {
15348 fprintf(stderr, "mongoose_queue: Error: write(s_sock(0)) error %d (%s)\n", errno, strerror(errno));
15349 abort();
15350 }
15351}
15352#endif
15353
15354static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data)
15355{
15356 (void) ev;
15357 struct work_result *res = (struct work_result *)ev_data;
15358
15359 assert(res != NULL);
15360 assert(res->w != NULL);
15361
15362 //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);
15363
15364 // check for correct connection, note that nc objects are reused and after a socket is closed
15365 // and a new one is opened, the same nc address and the same nc->sock can now refer to a completely
15366 // different tcp connection. So we check ncseqno instead of nc. K.O.
15367
15368 //if (res->nc != nc)
15369 //return;
15370
15371 if (GetNcSeqno(nc) != res->w->wncseqno)
15372 return;
15373
15374 //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);
15375
15376 if (res->send_501) {
15377 std::string response = "501 Not Implemented";
15378 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15379 mg_send(nc, response.c_str(), response.length());
15380 }
15381
15382 if (res->s1 > 0)
15383 mg_send(nc, res->p1, res->s1);
15384
15385 if (res->s2 > 0)
15386 mg_send(nc, res->p2, res->s2);
15387
15388 if (res->close_flag) {
15389 // cannot do pipelined http if response generated by mhttpd
15390 // decode_get() has no Content-Length header.
15391 // must close the connection.
15393 }
15394
15395 res->w->send_done = true;
15396}
15397
15398static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag)
15399{
15400 //printf("nc: %p: send %d and %d\n", nc, (int)s1, (int)s2);
15401 struct work_result res;
15402 res.nc = nc;
15403 res.w = w;
15404 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15405 res.p1 = p1;
15406 res.s1 = s1;
15407 res.p2 = p2;
15408 res.s2 = s2;
15409 res.close_flag = close_flag;
15410 res.send_501 = false;
15411 //printf("nc: %p: call mg_broadcast()\n", nc);
15412
15413 // NB: mg_broadcast() is advertised as thread-safe, but it is not.
15414 //
15415 // in mongoose 6.16, mg_brodacast() and mg_mgr_handle_ctl_sock() have several problems:
15416 //
15417 // a) "wrong thread" read from mgr->ctl[0], defeating the handshake
15418 //
15419 // b) "lost messages". if more than one message is written to mgr->ctl[0], the second message
15420 // will be "eaten" by mg_mgr_handle_ctl_sock() because of mistatch between number of bytes read and written
15421 // in the two functions. mg_mgr_handle_ctl_sock() always reads about 8000 bytes while mg_broadcast()
15422 // writes 8 bytes per message, (per examples/multithreaded/multithreaded.c. mhttpd messages are a bit longer).
15423 // So if multiple messages are present in the msg->ctl[0] pipe, the read call (of about 8000 bytes)
15424 // in mg_mgr_handle_ctl_sock() will return several messages (last message may be truncated)
15425 // but only the first message will be processed by the code. any additional messages are ignored.
15426 //
15427 // Problems (a) and (b) are easy to fix by using a mutex to serialize mg_broadcast().
15428 //
15429 // c) if the mg_broadcast() message contains pointers to the data buffer to be sent out,
15430 // the caller of mg_broadcast() should not free these data buffers until mg_send() is called
15431 // in "on_work_complete()". In theory, the caller of mg_broadcast() could wait until on_work_complete()
15432 // sets a "done" flag. In practice, if the corresponding network connection is closed before
15433 // mg_mgr_handle_ctl_sock() has looped over it, on_work_complete() will never run
15434 // and the "done" flag will never be set. (Of course, network connections are permitted to close
15435 // at any time without warning, but) the firefox browser closes the network connections "a lot"
15436 // especially when user pressed the "page reload" button at the moment when HTTP transations
15437 // are "in flight". (google-chrome tends to permit these "lame duck" transactions to complete and mongoose
15438 // does not see unexpected socket closures, at least not as many).
15439 //
15440 // To fix problem (c) I need to know when mg_mgr_handle_ctl_sock()'s loop over network connections
15441 // has completed (two cases: (a) my on_work_complete() was hopefully called and finished,
15442 // and (b) the "right" network connection was already closed (for whatever reason) and my on_work_complete()
15443 // was never called).
15444 //
15445 // My solution is to change the handshake between mg_broadcast() and mg_mgr_handle_ctl_sock() by sending
15446 // the handshake reply after looping over the network connections instead of after reading the message
15447 // from msg->ctl[1].
15448 //
15449 // This requires a modification to the code in mongoose.c. If this change is lost/undone, nothing will work.
15450 //
15451
15452 s_mg_broadcast_mutex.lock();
15453 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15454 s_mg_broadcast_mutex.unlock();
15455}
15456
15457static void mongoose_send_501(mg_connection* nc, MongooseWorkObject* w)
15458{
15459 struct work_result res;
15460 res.nc = nc;
15461 res.w = w;
15462 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15463 res.p1 = 0;
15464 res.s1 = 0;
15465 res.p2 = 0;
15466 res.s2 = 0;
15467 res.close_flag = false;
15468 res.send_501 = true;
15469 //printf("nc: %p, call mg_broadcast()\n", nc);
15470
15471 s_mg_broadcast_mutex.lock();
15472 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15473 s_mg_broadcast_mutex.unlock();
15474}
15475
15476#if 0
15477void *worker_thread_proc(void *param)
15478{
15479 //struct mg_mgr *mgr = (struct mg_mgr *) param;
15480 struct work_request req = {0};
15481
15482 while ((! _abort) && (! s_shutdown)) {
15483 int rd = read(s_sock[1], &req, sizeof(req));
15484 if (rd == 0) {
15485 // socket closed, shutdown the thread
15486 break;
15487 }
15488 if (rd < 0) {
15489 if (_abort || s_shutdown) {
15490 return NULL;
15491 }
15492 fprintf(stderr, "worker_thread_proc: Error: read(s_sock(1)) returned %d, error %d (%s)\n", rd, errno, strerror(errno));
15493 abort();
15494 return NULL;
15495 }
15496
15497 //printf("nc: %p: received request!\n", req.nc);
15498
15499 int response = thread_work_function(req.nc, req.w);
15500
15501 if (response == RESPONSE_501) {
15502 if (trace_mg||verbose_mg)
15503 printf("handle_http_message: sending 501 Not Implemented error\n");
15504 mongoose_send_501(req.nc, req.w);
15505 }
15506
15507 req.w->t->fCompleted = true;
15508 gTraceBuf->AddTraceMTS(req.w->t);
15509
15510 //printf("nc: %p: wseqno: %d, delete work object!\n", req.nc, req.w->wseqno);
15511
15512 delete req.w;
15513 req.w = NULL;
15514 }
15515 return NULL;
15516}
15517#endif
15518
15519static void mongoose_thread(MongooseThreadObject* to)
15520{
15521 //printf("to %p, nc %p: thread %p started!\n", to, to->fNc, to->fThread);
15522
15523 std::unique_lock<std::mutex> ulm(to->fMutex, std::defer_lock);
15524
15525 to->fIsRunning = true;
15526
15527 while ((! _abort) && (! s_shutdown)) {
15528 MongooseWorkObject *w = NULL;
15529
15530 ulm.lock();
15531 while (to->fQueue.empty()) {
15532 //printf("to %p, nc %p, thread %p: waiting!\n", to, to->fNc, to->fThread);
15533 to->fNotify.wait(ulm);
15534 if (_abort || s_shutdown) {
15535 break;
15536 }
15537 }
15538
15539 if (_abort || s_shutdown) {
15540 break;
15541 }
15542
15543 w = to->fQueue.front();
15544 to->fQueue.pop_front();
15545 ulm.unlock();
15546
15547 //printf("to %p, nc %p: wseqno: %d, received request!\n", to, w->nc, w->wseqno);
15548
15549 int response = thread_work_function(w->nc, w);
15550
15551 if (response == RESPONSE_501) {
15552 if (trace_mg||verbose_mg)
15553 printf("handle_http_message: sending 501 Not Implemented error\n");
15554 mongoose_send_501(w->nc, w);
15555 }
15556
15557 // mg_broadcast() called on_work_complete() on the main thread and waited until it finished
15558
15559 if (!w->send_done) {
15560 // NB: careful here, if connection nc was closed, pointer nc points to nowhere! do not dereference it!
15561 // NB: stay quiet about it, nothing special about network connctions closing and opening as they wish.
15562 //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);
15563 }
15564
15565 w->t->fCompleted = true;
15566 gTraceBuf->AddTraceMTS(w->t);
15567
15568 //printf("nc: %p: wseqno: %d, delete work object!\n", w->nc, w->wseqno);
15569
15570 delete w;
15571 }
15572
15573 to->fIsRunning = false;
15574
15575 //printf("to %p, nc %p: thread %p finished!\n", to, to->fNc, to->fThread);
15576}
15577
15578static bool mongoose_hostlist_enabled(const struct mg_connection *nc);
15579
15580static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
15581{
15582 (void) nc;
15583 (void) ev_data;
15584
15585 //if (trace_mg && ev != 0) {
15586 // printf("ev_handler: connection %p, event %d\n", nc, ev);
15587 //}
15588
15589 switch (ev) {
15590 case 0:
15591 break;
15592 default: {
15593 if (trace_mg) {
15594 printf("ev_handler: connection %p, event %d\n", nc, ev);
15595 }
15596 break;
15597 }
15598 case MG_EV_ACCEPT:
15599 assert(nc->user_data == NULL);
15600 nc->user_data = new MongooseNcUserData();
15601
15602 if (trace_mg) {
15603 printf("ev_handler: connection %p, MG_EV_ACCEPT, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15604 }
15605 if (s_shutdown) {
15606 //printf("XXX nc %p!\n", nc);
15608 } else if (mongoose_hostlist_enabled(nc)) {
15609 if (!mongoose_check_hostlist(&nc->sa)) {
15611 }
15612 }
15613 break;
15614 case MG_EV_RECV:
15615 if (trace_mg_recv) {
15616 printf("ev_handler: connection %p, MG_EV_RECV, %d bytes\n", nc, *(int*)ev_data);
15617 }
15618 if (s_shutdown) {
15619 //printf("RRR nc %p!\n", nc);
15621 }
15622 break;
15623 case MG_EV_SEND:
15624 if (trace_mg_send) {
15625 printf("ev_handler: connection %p, MG_EV_SEND, %d bytes\n", nc, *(int*)ev_data);
15626 }
15627 break;
15628 case MG_EV_HTTP_CHUNK: {
15629 if (trace_mg) {
15630 printf("ev_handler: connection %p, MG_EV_HTTP_CHUNK\n", nc);
15631 }
15632 if (s_shutdown) {
15633 //printf("RRR1 nc %p!\n", nc);
15635 }
15636 break;
15637 }
15638 case MG_EV_HTTP_REQUEST: {
15639 struct http_message* msg = (struct http_message*)ev_data;
15640 if (trace_mg) {
15641 printf("ev_handler: connection %p, MG_EV_HTTP_REQUEST \"%s\" \"%s\"\n", nc, mgstr(&msg->method).c_str(), mgstr(&msg->uri).c_str());
15642 }
15643 if (s_shutdown) {
15644 //printf("RRR2 nc %p!\n", nc);
15646 } else {
15647 handle_http_message(nc, msg);
15648 }
15649 break;
15650 }
15651 case MG_EV_CLOSE: {
15652 if (trace_mg) {
15653 printf("ev_handler: connection %p, MG_EV_CLOSE, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15654 }
15655 //printf("CCC nc %p!\n", nc);
15656 FreeThread(nc);
15657 if (nc->user_data) {
15658 MongooseNcUserData* ncud = (MongooseNcUserData*)nc->user_data;
15659 nc->user_data = NULL;
15660 delete ncud;
15661 ncud = NULL;
15662 }
15663 }
15664 }
15665}
15666
15667#define FLAG_HTTPS MG_F_USER_1
15668#define FLAG_PASSWORDS MG_F_USER_2
15669#define FLAG_HOSTLIST MG_F_USER_3
15670
15671static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15672{
15673 int flags = 0;
15674 if (nc && nc->listener) {
15675 flags = nc->listener->flags;
15676 }
15677 //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);
15678 return flags & FLAG_PASSWORDS;
15679}
15680
15681static bool mongoose_hostlist_enabled(const struct mg_connection *nc)
15682{
15683 int flags = 0;
15684 if (nc && nc->listener) {
15685 flags = nc->listener->flags;
15686 }
15687 //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);
15688 return flags & FLAG_HOSTLIST;
15689}
15690
15691static int mongoose_listen(const char* address, int flags)
15692{
15693#if MG_ENABLE_SSL
15694#else
15695 if (flags & FLAG_HTTPS) {
15696 cm_msg(MERROR, "mongoose_listen", "https port \"%s\" requested, but mhttpd compiled without MG_ENABLE_SSL", address);
15697 return SS_SOCKET_ERROR;
15698 }
15699#endif
15700
15701 struct mg_connection *nc = mg_bind(&s_mgr, address, ev_handler);
15702 if (nc == NULL) {
15703 cm_msg(MERROR, "mongoose_listen", "Cannot mg_bind address \"%s\"", address);
15704 return SS_SOCKET_ERROR;
15705 }
15706
15707 if (flags & FLAG_HTTPS) {
15708#if MG_ENABLE_SSL
15709 std::string cert_file;
15710
15711 int status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
15712
15713 if (status != SUCCESS) {
15714 cm_msg(MERROR, "mongoose_listen", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
15715 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");
15716 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");
15717 return SS_FILE_ERROR;
15718 }
15719
15720 printf("Mongoose web server will use https certificate file \"%s\"\n", cert_file.c_str());
15721
15722 const char* errmsg = mg_set_ssl(nc, cert_file.c_str(), NULL);
15723 if (errmsg) {
15724 cm_msg(MERROR, "mongoose_listen", "Cannot enable https with certificate file \"%s\", error: %s", cert_file.c_str(), errmsg);
15725 return SS_SOCKET_ERROR;
15726 }
15727
15728 // NB: where is the warning that the SSL certificate has expired?!? K.O.
15729#else
15730 abort(); // cannot happen!
15731#endif
15732 }
15733
15735
15736 nc->flags |= flags;
15737
15738 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");
15739
15740 return SUCCESS;
15741}
15742
15743static int mongoose_init(MVOdb* odb, bool no_passwords, bool no_hostlist, const std::vector<std::string>& user_hostlist)
15744{
15745 bool enable_localhost_port = true;
15746 int localhost_port = 8080;
15747 bool localhost_port_passwords = false;
15748
15749 bool enable_insecure_port = false;
15750 int insecure_port = 8081;
15751 bool insecure_port_passwords = true;
15752 bool insecure_port_hostlist = true;
15753
15754 bool enable_https_port = false;
15755 int https_port = 8443;
15756 bool https_port_passwords = true;
15757 bool https_port_hostlist = false;
15758
15759 std::vector<std::string> hostlist;
15760 hostlist.push_back("localhost");
15761
15762 bool enable_ipv6 = true;
15763
15764 odb->RB("Enable localhost port", &enable_localhost_port, true);
15765 odb->RI("localhost port", &localhost_port, true);
15766 odb->RB("localhost port passwords", &localhost_port_passwords, true);
15767 odb->RB("Enable insecure port", &enable_insecure_port, true);
15768 odb->RI("insecure port", &insecure_port, true);
15769 odb->RB("insecure port passwords", &insecure_port_passwords, true);
15770 odb->RB("insecure port host list", &insecure_port_hostlist, true);
15771 odb->RB("Enable https port", &enable_https_port, true);
15772 odb->RI("https port", &https_port, true);
15773 odb->RB("https port passwords", &https_port_passwords, true);
15774 odb->RB("https port host list", &https_port_hostlist, true);
15775 odb->RSA("Host list", &hostlist, true, 10, 256);
15776 odb->RB("Enable IPv6", &enable_ipv6, true);
15777
15778 // populate the MIME.types table
15779 gProxyOdb = odb->Chdir("Proxy", true);
15780 std::string proxy_example = "#http://localhost:8080";
15781 gProxyOdb->RS("example", &proxy_example, true);
15782
15783 // populate the MIME.types table
15784 SaveMimetypes(odb->Chdir("mime.types", true));
15785
15786 if (!no_passwords
15787 && ((enable_localhost_port && localhost_port_passwords)
15788 || (enable_insecure_port && insecure_port_passwords)
15789 || (enable_https_port && https_port_passwords))) {
15790 gAuthMg = new Auth();
15791 int status = gAuthMg->Init();
15792 if (status != SUCCESS) {
15793 printf("mongoose_init: Error: Cannot initialize authorization object!\n");
15794 return status;
15795 }
15796 printf("HTTP Digest authentication with realm \"%s\" and password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
15797 } else {
15798 printf("Password protection is off\n");
15799 }
15800
15801 if (!no_hostlist
15802 && ((enable_insecure_port && insecure_port_hostlist)
15803 || (enable_https_port && https_port_hostlist))) {
15804 gAllowedHosts.clear();
15805
15806 // copy the user allowed hosts
15807 for (unsigned int i=0; i<user_hostlist.size(); i++)
15808 gAllowedHosts.push_back(user_hostlist[i]);
15809
15810 for (unsigned i=0; i<hostlist.size(); i++) {
15811 std::string s = hostlist[i];
15812 if (s.length() < 1) // skip emties
15813 continue;
15814
15815 if (s[0] == '#') // skip commented-out entries
15816 continue;
15817
15818 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
15819 gAllowedHosts.push_back(s);
15820 }
15821
15822 printf("Hostlist active, connections will be accepted only from: ");
15823 for (unsigned i=0; i<gAllowedHosts.size(); i++) {
15824 if (i>0)
15825 printf(", ");
15826 printf("%s", gAllowedHosts[i].c_str());
15827 }
15828 printf("\n");
15829 } else {
15830 printf("Hostlist off, connections from anywhere will be accepted\n");
15831 }
15832
15833 mg_mgr_init(&s_mgr, NULL);
15834
15835 bool listen_failed = false;
15836
15837 if (enable_localhost_port) {
15838 char str[256];
15839 sprintf(str, "localhost:%d", localhost_port);
15840 int status = mongoose_listen(str, 0);
15841 if (status != SUCCESS)
15842 listen_failed = true;
15843 if (enable_ipv6) {
15844 sprintf(str, "[::1]:%d", localhost_port);
15845 status = mongoose_listen(str, 0);
15846 if (status != SUCCESS)
15847 listen_failed = true;
15848 }
15849 }
15850
15851 if (enable_insecure_port) {
15852 char str[256];
15853 int flags = 0;
15854 if (insecure_port_passwords)
15855 flags |= FLAG_PASSWORDS;
15856 if (insecure_port_hostlist)
15857 flags |= FLAG_HOSTLIST;
15858 if (enable_ipv6) {
15859 sprintf(str, "[::]:%d", insecure_port);
15860 int status = mongoose_listen(str, flags);
15861 if (status != SUCCESS)
15862 listen_failed = true;
15863 } else {
15864 sprintf(str, "%d", insecure_port);
15865 int status = mongoose_listen(str, flags);
15866 if (status != SUCCESS)
15867 listen_failed = true;
15868 }
15869 }
15870
15871 if (enable_https_port) {
15872 char str[256];
15873 int flags = 0;
15874 if (https_port_passwords)
15875 flags |= FLAG_PASSWORDS;
15876 if (https_port_hostlist)
15877 flags |= FLAG_HOSTLIST;
15878 flags |= FLAG_HTTPS;
15879 if (enable_ipv6) {
15880 sprintf(str, "[::]:%d", https_port);
15881 int status = mongoose_listen(str, flags);
15882 if (status != SUCCESS)
15883 listen_failed = true;
15884 } else {
15885 sprintf(str, "%d", https_port);
15886 int status = mongoose_listen(str, flags);
15887 if (status != SUCCESS)
15888 listen_failed = true;
15889 }
15890 }
15891
15892 if (listen_failed) {
15893 cm_msg(MERROR, "mongoose_init", "Failed to listen on a TCP port enabled in ODB /WebServer");
15894 return SS_SOCKET_ERROR;
15895 }
15896
15897 return SUCCESS;
15898}
15899
15900static void mongoose_poll(int msec = 200)
15901{
15902 mg_mgr_poll(&s_mgr, msec);
15903}
15904
15905static void mongoose_cleanup()
15906{
15907 printf("Mongoose web server shutting down\n");
15908
15909 s_shutdown = true;
15910
15911 // close listener sockets
15912 if (s_mgr.active_connections) {
15913 struct mg_connection* nc = s_mgr.active_connections;
15914 while (nc) {
15915 //printf("nc %p, next %p, user_data %p, listener %p, flags %lu\n", nc, nc->next, nc->user_data, nc->listener, nc->flags);
15916 if (nc->flags & MG_F_LISTENING) {
15918 }
15919 nc = nc->next;
15920 }
15921 }
15922
15923 // tell threads to shut down
15924 for (auto it : gMongooseThreads) {
15925 MongooseThreadObject* to = it;
15926 to->fNotify.notify_one();
15927 }
15928
15929 // wait until all threads stop
15930 for (int i=0; i<10; i++) {
15931 int count_running = 0;
15932 for (auto it : gMongooseThreads) {
15933 MongooseThreadObject* to = it;
15934 //printf("AAA6C %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15935 if (to->fIsRunning) {
15936 count_running++;
15937 }
15938 }
15939 printf("Mongoose web server shutting down, %d threads still running\n", count_running);
15940 if (count_running == 0)
15941 break;
15942 mongoose_poll(1000);
15943 }
15944
15945 // delete thread objects
15946 for (auto it : gMongooseThreads) {
15947 MongooseThreadObject* to = it;
15948 //printf("AAA7B %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15949 if (to->fIsRunning) {
15950 cm_msg(MERROR, "mongoose", "thread failed to shut down");
15951 continue;
15952 }
15953 to->fThread->join();
15954 delete to->fThread;
15955 delete to;
15956 }
15957 gMongooseThreads.clear();
15958
15959 mg_mgr_free(&s_mgr);
15960
15961 //closesocket(s_sock[0]);
15962 //closesocket(s_sock[1]);
15963
15964 // make leak sanitizer happy!
15965 for (auto e : gHostlistCache) {
15966 delete e;
15967 }
15968 gHostlistCache.clear();
15969 if (gProxyOdb) {
15970 delete gProxyOdb;
15971 gProxyOdb = NULL;
15972 }
15973 if (gMimeTypesOdb) {
15974 delete gMimeTypesOdb;
15975 gMimeTypesOdb = NULL;
15976 }
15977
15978 printf("Mongoose web server shut down\n");
15979}
15980
15981#endif
15982
15983#ifdef HAVE_MONGOOSE6
15984
15985static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15986{
15987 return true;
15988}
15989
15990int start_mg(int user_http_port, int user_https_port, int socket_priviledged_port, int verbose)
15991{
15992 HNDLE hDB;
15993 int size;
15994 int status;
15995
15996 //if (verbose)
15997 // trace_mg = true;
15998
15999 if (verbose)
16000 verbose_mg = true;
16001
16003 assert(status == CM_SUCCESS);
16004
16005 int http_port = 8080;
16006 int https_port = 8443;
16007 int http_redirect_to_https = 1;
16008
16009 size = sizeof(http_port);
16010 db_get_value(hDB, 0, "/Experiment/midas http port", &http_port, &size, TID_INT, TRUE);
16011
16012 size = sizeof(https_port);
16013 db_get_value(hDB, 0, "/Experiment/midas https port", &https_port, &size, TID_INT, TRUE);
16014
16015 size = sizeof(http_redirect_to_https);
16016 db_get_value(hDB, 0, "/Experiment/http redirect to https", &http_redirect_to_https, &size, TID_BOOL, TRUE);
16017
16018 bool need_cert_file = false;
16019 bool need_password_file = false;
16020
16021 if (user_http_port)
16022 http_port = user_http_port;
16023
16024 if (user_https_port)
16025 https_port = user_https_port;
16026
16027 if (https_port) {
16028 need_cert_file = true;
16029 need_password_file = true;
16030 }
16031
16032 if (!https_port)
16033 http_redirect_to_https = 0;
16034
16035 if (http_port && !http_redirect_to_https) {
16036 // no passwords serving over http unless
16037 // http is just a redict to https
16038 need_password_file = false;
16039 }
16040
16041 if (socket_priviledged_port >= 0) {
16042 // no passwords if serving unencrypted http on port 80
16043 need_password_file = false;
16044 printf("Mongoose web server password portection is disabled: serving unencrypted http on port 80\n");
16045 }
16046
16047 bool have_at_least_one_port = false;
16048
16049 std::string cert_file;
16050
16051 if (need_cert_file) {
16052 status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
16053
16054 if (status != SUCCESS) {
16055 cm_msg(MERROR, "mongoose", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
16056 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");
16057 return SS_FILE_ERROR;
16058 }
16059
16060 printf("Mongoose web server will use SSL certificate file \"%s\"\n", cert_file.c_str());
16061 }
16062
16063 if (need_password_file) {
16064 gAuthMg = new Auth();
16065 status = gAuthMg->Init();
16066 if (status != SUCCESS) {
16067 printf("Error: Cannot initialize authorization object!\n");
16068 return status;
16069 }
16070 printf("Mongoose web server will use authentication realm \"%s\", password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
16071 } else {
16072 printf("Mongoose web server will not use password protection\n");
16073 }
16074
16075 if (trace_mg)
16076 printf("start_mg!\n");
16077
16078#ifndef OS_WINNT
16079 signal(SIGPIPE, SIG_IGN);
16080#endif
16081
16082 if (!gTraceBuf) {
16084 }
16085
16086 if (!request_mutex) {
16087 status = ss_mutex_create(&request_mutex, FALSE);
16088 assert(status==SS_SUCCESS || status==SS_CREATED);
16089 }
16090
16091 mg_mgr_init(&mgr_mg, NULL);
16092
16093 // use socket bound to priviledged port (setuid-mode)
16094 if (socket_priviledged_port >= 0) {
16095 struct mg_connection* nc = mg_add_sock(&mgr_mg, socket_priviledged_port, handle_event_mg);
16096 if (nc == NULL) {
16097 cm_msg(MERROR, "mongoose", "Cannot create mg_connection for set-uid-root privileged port");
16098 return SS_SOCKET_ERROR;
16099 }
16100
16101 nc->flags |= MG_F_LISTENING;
16102#ifdef MG_ENABLE_THREADS
16104#endif
16106 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16107
16108 have_at_least_one_port = true;
16109 printf("mongoose web server is listening on the set-uid-root privileged port\n");
16110 }
16111
16112 if (http_port != 80) { // port 80 is already handled by socket_priviledged_port
16113 char str[256];
16114 sprintf(str, "%d", http_port);
16115 struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16116 if (nc == NULL) {
16117 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", http_port);
16118 return SS_SOCKET_ERROR;
16119 }
16120
16121#ifdef MG_ENABLE_THREADS
16123#endif
16125
16126 if (http_redirect_to_https) {
16127 std::string hostname = ss_gethostname();
16128 char str[256];
16129 sprintf(str, "%d", https_port);
16130 std::string s = hostname + ":" + std::string(str);
16131 nc->user_data = new std::string(s);
16132 mg_register_http_endpoint(nc, "/", handle_http_redirect);
16133 printf("mongoose web server is redirecting HTTP port %d to https://%s\n", http_port, s.c_str());
16134 } else {
16135 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16136 }
16137
16138 have_at_least_one_port = true;
16139 printf("mongoose web server is listening on the HTTP port %d\n", http_port);
16140 }
16141
16142 if (https_port) {
16143#ifdef MG_ENABLE_SSL
16144 char str[256];
16145 sprintf(str, "%d", https_port);
16146 struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16147 if (nc == NULL) {
16148 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", https_port);
16149 return SS_SOCKET_ERROR;
16150 }
16151
16152 mg_set_ssl(nc, cert_file.c_str(), NULL);
16153#ifdef MG_ENABLE_THREADS
16155#endif
16157 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16158
16159 have_at_least_one_port = true;
16160 printf("mongoose web server is listening on the HTTPS port %d\n", https_port);
16161#else
16162 cm_msg(MERROR, "mongoose", "https port %d requested, but mhttpd compiled without MG_ENABLE_SSL", https_port);
16163 return SS_SOCKET_ERROR;
16164#endif
16165 }
16166
16167 if (!have_at_least_one_port) {
16168 cm_msg(MERROR, "mongoose", "cannot start: no ports defined");
16169 return SS_FILE_ERROR;
16170 }
16171
16172 return SUCCESS;
16173}
16174
16175int stop_mg()
16176{
16177 if (trace_mg)
16178 printf("stop_mg!\n");
16179
16180 // Stop the server.
16181 mg_mgr_free(&mgr_mg);
16182
16183 if (trace_mg)
16184 printf("stop_mg done!\n");
16185 return SUCCESS;
16186}
16187
16188int loop_mg()
16189{
16190 int status = SUCCESS;
16191
16192 /* establish Ctrl-C handler - will set _abort to TRUE */
16194
16195 while (!_abort) {
16196
16197 /* cm_yield() is not thread safe, need to take a lock */
16198
16199#ifdef HAVE_MONGOOSE6
16200 status = ss_mutex_wait_for(request_mutex, 0);
16201#endif
16202 gMutex.lock();
16203
16204 /* check for shutdown message */
16205 status = cm_yield(0);
16206 if (status == RPC_SHUTDOWN)
16207 break;
16208
16209 gMutex.unlock();
16210#ifdef HAVE_MONGOOSE6
16211 status = ss_mutex_release(request_mutex);
16212#endif
16213
16214 //ss_sleep(10);
16215
16216 mg_mgr_poll(&mgr_mg, 10);
16217 }
16218
16219 return status;
16220}
16221#endif
16222
16223static MJsonNode* get_http_trace(const MJsonNode* params)
16224{
16225 if (!params) {
16226 MJSO *doc = MJSO::I();
16227 doc->D("get current value of mhttpd http_trace");
16228 doc->P(NULL, 0, "there are no input parameters");
16229 doc->R(NULL, MJSON_INT, "current value of http_trace");
16230 return doc;
16231 }
16232
16233 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16234}
16235
16236static MJsonNode* set_http_trace(const MJsonNode* params)
16237{
16238 if (!params) {
16239 MJSO* doc = MJSO::I();
16240 doc->D("set new value of mhttpd http_trace");
16241 doc->P(NULL, MJSON_INT, "new value of http_trace");
16242 doc->R(NULL, MJSON_INT, "new value of http_trace");
16243 return doc;
16244 }
16245
16246 http_trace = params->GetInt();
16247 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16248}
16249
16251{
16252 mjsonrpc_add_handler("set_http_trace", set_http_trace);
16253 mjsonrpc_add_handler("get_http_trace", get_http_trace);
16254}
16255
16256/*------------------------------------------------------------------*/
16257
16258int main(int argc, const char *argv[])
16259{
16260 int status;
16261 int daemon = FALSE;
16262#ifdef HAVE_MONGOOSE6
16263 int user_http_port = 0;
16264 int user_https_port = 0;
16265#endif
16266#ifdef HAVE_MONGOOSE616
16267 bool no_passwords = false;
16268 bool no_hostlist = false;
16269#endif
16270 const char *myname = "mhttpd";
16271
16272 setbuf(stdout, NULL);
16273 setbuf(stderr, NULL);
16274#ifdef SIGPIPE
16275 /* avoid getting killed by "Broken pipe" signals */
16276 signal(SIGPIPE, SIG_IGN);
16277#endif
16278
16279#ifdef HAVE_MONGOOSE6
16280 //
16281 // if running setuid-root, unconditionally bind to port 80.
16282 //
16283
16284 int socket_priviledged_port = -1;
16285
16286#ifdef OS_UNIX
16287 // in setuid-root mode bind to priviledged port
16288 if (getuid() != geteuid()) {
16289 int port80 = 80;
16290
16291 printf("mhttpd is running in setuid-root mode.\n");
16292
16293 socket_priviledged_port = open_listening_socket(port80);
16294 if (socket_priviledged_port < 0) {
16295 printf("Cannot open listening socket on TCP port %d, aborting.\n", port80);
16296 exit(1);
16297 }
16298
16299 // give up root privilege
16300 status = setuid(getuid());
16301 if (status != 0) {
16302 printf("Cannot give up root privelege, aborting.\n");
16303 exit(1);
16304 }
16305 status = setuid(getuid());
16306 if (status != 0) {
16307 printf("Cannot give up root privelege, aborting.\n");
16308 exit(1);
16309 }
16310 }
16311#endif
16312#endif
16313
16314 char midas_hostname[256];
16315 char midas_expt[256];
16316 std::string expdir;
16317
16318 /* get default from environment */
16319 cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
16320
16321 /* parse command line parameters */
16322#ifdef HAVE_MONGOOSE6
16323 gUserAllowedHosts.clear();
16324#else
16325 std::vector<std::string> user_hostlist;
16326#endif
16327 for (int i = 1; i < argc; i++) {
16328 if (argv[i][0] == '-' && argv[i][1] == 'D')
16329 daemon = TRUE;
16330 else if (argv[i][0] == '-' && argv[i][1] == 'v')
16331 verbose = TRUE;
16332 else if (argv[i][0] == '-' && argv[i][1] == 'E')
16333 elog_mode = TRUE;
16334 else if (argv[i][0] == '-' && argv[i][1] == 'H') {
16336#ifdef HAVE_MONGOOSE6
16337 } else if (strcmp(argv[i], "--http") == 0) {
16338 if (argv[i+1]) {
16339 user_http_port = atoi(argv[i+1]);
16340 }
16341 } else if (strcmp(argv[i], "--https") == 0) {
16342 if (argv[i+1]) {
16343 user_https_port = atoi(argv[i+1]);
16344 }
16345#endif
16346 } else if (strcmp(argv[i], "--trace-mg") == 0) {
16347 trace_mg = true;
16348 trace_mg_recv = true;
16349 trace_mg_send = true;
16350 } else if (strcmp(argv[i], "--trace-mg-verbose") == 0) {
16351 trace_mg_verbose = true;
16352 } else if (strcmp(argv[i], "--no-trace-mg-recv") == 0) {
16353 trace_mg_recv = false;
16354 } else if (strcmp(argv[i], "--no-trace-mg-send") == 0) {
16355 trace_mg_send = false;
16356 } else if (strcmp(argv[i], "--verbose-mg") == 0) {
16357 verbose_mg = true;
16358#ifdef HAVE_MONGOOSE616
16359 } else if (strcmp(argv[i], "--no-multithread") == 0) {
16360 multithread_mg = false;
16361 } else if (strcmp(argv[i], "--no-passwords") == 0) {
16362 no_passwords = true;
16363 } else if (strcmp(argv[i], "--no-hostlist") == 0) {
16364 no_hostlist = true;
16365#endif
16366 } else if (strcmp(argv[i], "--expdir") == 0) {
16367 expdir = argv[i+1];
16368 i++;
16369 } else if (argv[i][0] == '-') {
16370 if (i + 1 >= argc || argv[i + 1][0] == '-')
16371 goto usage;
16372 if (argv[i][1] == 'h')
16373 mstrlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
16374 else if (argv[i][1] == 'e')
16375 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
16376 else if (argv[i][1] == 'a') {
16377#ifdef HAVE_MONGOOSE6
16378 gUserAllowedHosts.push_back(argv[++i]);
16379#else
16380 user_hostlist.push_back(argv[++i]);
16381#endif
16382 } else if (argv[i][1] == 'p') {
16383 printf("Option \"-p port_number\" for the old web server is obsolete.\n");
16384 printf("mongoose web server is the new default, port number is set in ODB or with \"--http port_number\".\n");
16385 printf("To run the obsolete old web server, please use \"--oldserver\" switch.\n");
16386 return 1;
16387 } else {
16388 usage:
16389 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-v] [-D] [-a Hostname] [--expdir EXPDIR]\n\n", argv[0]);
16390 printf(" -a add hostname to the hostlist of hosts allowed to connect to mhttpd\n");
16391 printf(" -e experiment to connect to\n");
16392 printf(" -h connect to midas server (mserver) on given host\n");
16393 printf(" --expdir EXPDIR specify experiment directory if connected to mserver\n");
16394 printf(" -v display verbose HTTP communication\n");
16395 printf(" -D become a daemon\n");
16396 printf(" -E only display ELog system\n");
16397 printf(" -H only display history plots\n");
16398#ifdef HAVE_MONGOOSE6
16399 printf(" --http port - bind to specified HTTP port (default is ODB \"/Experiment/midas http port\")\n");
16400 printf(" --https port - bind to specified HTTP port (default is ODB \"/Experiment/midas https port\")\n");
16401#endif
16402 printf(" --verbose-mg - trace mongoose web requests\n");
16403 printf(" --trace-mg - trace mongoose events\n");
16404 printf(" --no-trace-mg-recv - do not trace mongoose recv events\n");
16405 printf(" --no-trace-mg-send - dop not trace mongoose send events\n");
16406#ifdef HAVE_MONGOOSE616
16407 printf(" --no-multithread - disable mongoose multithreading\n");
16408 printf(" --no-passwords - disable password protection\n");
16409 printf(" --no-hostlist - disable access control host list\n");
16410#endif
16411 return 0;
16412 }
16413 }
16414 }
16415
16416 if (daemon) {
16417 printf("Becoming a daemon...\n");
16419 }
16420
16421#ifdef OS_LINUX
16422 /* write PID file */
16423 FILE *f = fopen("/var/run/mhttpd.pid", "w");
16424 if (f != NULL) {
16425 fprintf(f, "%d", ss_getpid());
16426 fclose(f);
16427 }
16428#endif
16429
16430 if (history_mode)
16431 myname = "mhttpd_history";
16432
16433 /*---- connect to experiment ----*/
16434 status = cm_connect_experiment1(midas_hostname, midas_expt, myname, NULL,
16437 return 1;
16438 else if (status == DB_INVALID_HANDLE) {
16439 std::string s = cm_get_error(status);
16440 puts(s.c_str());
16441 } else if (status != CM_SUCCESS) {
16442 std::string s = cm_get_error(status);
16443 puts(s.c_str());
16444 return 1;
16445 }
16446
16447 if (expdir.empty()) {
16448 if (rpc_is_remote()) {
16449 printf("mhttpd is connected to the mserver, this is not the normal configuration and it will likely crash unless experiment directory is also specified via --expdir EXPDIR\n");
16450 }
16451 } else {
16452 if (!ss_dir_exist(expdir.c_str())) {
16453 cm_msg(MERROR, "main", "Experiment directory \"%s\" does not exist", expdir.c_str());
16456 return 1;
16457 }
16458
16459 cm_msg(MINFO, "main", "This mhttpd is connected via the mserver, using expriment path \"%s\"", expdir.c_str());
16460 cm_set_path(expdir.c_str());
16461 }
16462
16463 /* mhttpd needs the watchdog thread until we are sure
16464 * we do not have any long sleeps anywhere in the mhttpd code.
16465 * this includes reads from the history files or databases,
16466 * that can take arbitrary long time */
16468
16469 /* Get ODB handles */
16470
16471 HNDLE hDB;
16472
16474
16475 MVOdb *odb = MakeMidasOdb(hDB);
16476 gOdb = odb;
16477
16478 /* do ODB record checking */
16479 if (!check_odb_records(odb)) {
16480 // check_odb_records() fails with nothing printed to the terminal
16481 // because mhttpd does not print cm_msg(MERROR, ...) messages to the terminal.
16482 // At least print something!
16483 printf("check_odb_records() failed, see messages and midas.log, bye!\n");
16485 return 1;
16486 }
16487
16488#ifdef HAVE_MONGOOSE6
16489 if (init_allowed_hosts() != SUCCESS) {
16490 printf("init_allowed_hosts() failed, see messages and midas.log, bye!\n");
16492 return 1;
16493 }
16494
16495 if (verbose) {
16496 if (gAllowedHosts.size() > 0) {
16497 printf("mhttpd allowed hosts list: ");
16498 for (unsigned int i=0; i<gAllowedHosts.size(); i++) {
16499 if (i>0)
16500 printf(", ");
16501 printf("%s", gAllowedHosts[i].c_str());
16502 }
16503 printf("\n");
16504 } else {
16505 printf("mhttpd allowed hosts list is empty\n");
16506 }
16507 }
16508
16509 // populate the MIME.types table
16510 SaveMimetypes(odb->Chdir("WebServer/mime.types", true));
16511#endif
16512
16513 /* initialize odb entries needed for mhttpd and midas web pages */
16514 init_mhttpd_odb(odb);
16515
16516 /* initialize menu buttons */
16517 init_menu_buttons(odb);
16518
16519 /* initialize elog odb entries */
16520 init_elog_odb();
16521
16522 /* initialize the JSON RPC handlers */
16523 mjsonrpc_init();
16525
16527
16528#ifdef HAVE_MONGOOSE6
16529 status = start_mg(user_http_port, user_https_port, socket_priviledged_port, verbose);
16530 if (status != SUCCESS) {
16531 // At least print something!
16532 printf("could not start the mongoose web server, see messages and midas.log, bye!\n");
16534 return 1;
16535 }
16536#endif
16537
16538#ifdef HAVE_MONGOOSE616
16539
16540#ifdef SIGPIPE
16541#ifdef SIG_IGN
16542 signal(SIGPIPE, SIG_IGN);
16543#endif
16544#endif
16545
16546 if (!gTraceBuf) {
16548 }
16549
16550 //if (!request_mutex) {
16551 // status = ss_mutex_create(&request_mutex, FALSE);
16552 // assert(status==SS_SUCCESS || status==SS_CREATED);
16553 //}
16554
16555 /* establish Ctrl-C handler - will set _abort to TRUE */
16557
16558 MVOdb* o = odb->Chdir("WebServer", true);
16559 status = mongoose_init(o, no_passwords, no_hostlist, user_hostlist);
16560 if (status != SUCCESS) {
16561 // At least print something!
16562 printf("Error: Could not start the mongoose web server, see messages and midas.log, bye!\n");
16564 return 1;
16565 }
16566
16567 delete o;
16568#endif
16569
16570#ifdef HAVE_MONGOOSE6
16571 loop_mg();
16572 stop_mg();
16573#endif
16574
16575#ifdef HAVE_MONGOOSE616
16576 while (!_abort) {
16577
16578 /* cm_yield() is not thread safe, need to take a lock */
16579
16580 //status = ss_mutex_wait_for(request_mutex, 0);
16581 gMutex.lock();
16582
16583 /* check for shutdown message */
16584 status = cm_yield(0);
16585 if (status == RPC_SHUTDOWN)
16586 break;
16587
16588 gMutex.unlock();
16589 //status = ss_mutex_release(request_mutex);
16590
16591 //ss_sleep(10);
16592
16593 mongoose_poll(10);
16594 }
16595
16596 mongoose_cleanup();
16597#endif
16598
16599 if (gMh) {
16600 delete gMh;
16601 gMh = NULL;
16602 gMhkey = 0;
16603 }
16604
16605 mjsonrpc_exit();
16607 return 0;
16608}
16609
16610/* emacs
16611 * Local Variables:
16612 * tab-width: 8
16613 * c-basic-offset: 3
16614 * indent-tabs-mode: nil
16615 * End:
16616 */
#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:13761
std::string passwd_filename
Definition mhttpd.cxx:13760
std::string realm
Definition mhttpd.cxx:13759
int Init()
Definition mhttpd.cxx:13768
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:749
void unsetparam(const char *param)
Definition mhttpd.cxx:849
const char * getparam(const char *param)
Definition mhttpd.cxx:806
char _param[MAX_PARAM][PARAM_LENGTH]
Definition mhttpd.cxx:734
void setparam(const char *param, const char *value)
Definition mhttpd.cxx:756
~Param()
Definition mhttpd.cxx:744
char * _value[MAX_PARAM]
Definition mhttpd.cxx:735
BOOL isparam(const char *param)
Definition mhttpd.cxx:835
void printparam()
Definition mhttpd.cxx:797
std::string xgetparam(const char *param)
Definition mhttpd.cxx:826
Param()
Definition mhttpd.cxx:739
void freeparam()
Definition mhttpd.cxx:786
char _text[TEXT_SIZE]
Definition mhttpd.cxx:736
MUTEX_T * fMutex
Definition mhttpd.cxx:470
void AddTrace(RequestTrace *t)
Definition mhttpd.cxx:488
void AddTraceMTS(RequestTrace *t)
Definition mhttpd.cxx:493
std::vector< RequestTrace * > fBuf
Definition mhttpd.cxx:471
std::string fQuery
Definition mhttpd.cxx:426
std::string fMethod
Definition mhttpd.cxx:424
void PrintTrace0() const
Definition mhttpd.cxx:443
std::string fUri
Definition mhttpd.cxx:425
double fTimeSent
Definition mhttpd.cxx:422
std::string fResource
Definition mhttpd.cxx:428
bool fCompleted
Definition mhttpd.cxx:423
double fTimeReceived
Definition mhttpd.cxx:418
std::string fRPC
Definition mhttpd.cxx:427
double fTimeUnlocked
Definition mhttpd.cxx:420
double fTimeLocked
Definition mhttpd.cxx:419
double fTimeProcessed
Definition mhttpd.cxx:421
Return()
Definition mhttpd.cxx:554
va_end(argptr)
~Return()
Definition mhttpd.cxx:564
else strcpy(return_buffer+strlen_retbuf, str)
int return_grow(size_t len)
Definition mhttpd.cxx:586
return_grow(strlen(str))
vsprintf(str,(char *) format, argptr)
void rread(const char *filename, int fh, int len)
Definition mhttpd.cxx:618
int strlen_retbuf
Definition mhttpd.cxx:550
size_t return_size
Definition mhttpd.cxx:547
void zero()
Definition mhttpd.cxx:579
void char str[10000]
Definition mhttpd.cxx:702
void rsprintf(const char *format,...) MATTRPRINTF(2
void rmemcpy(const void *buf, int len)
Definition mhttpd.cxx:608
va_start(argptr, format)
int return_length
Definition mhttpd.cxx:551
void rsputs2(const char *str)
Definition mhttpd.cxx:651
void rsputs(const char *str)
Definition mhttpd.cxx:632
void reset()
Definition mhttpd.cxx:574
char * return_buffer
Definition mhttpd.cxx:548
assert(strlen(str)< sizeof(str))
static bool exists(const std::string &name)
Definition odbxx.cxx:76
static void usage()
int done
TRIGGER_SETTINGS ts
INT al_get_alarms(std::string *presult)
Definition alarm.cxx:862
INT cm_set_path(const char *path)
Definition midas.cxx:1513
INT cm_yield(INT millisec)
Definition midas.cxx:5660
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3027
INT cm_connect_client(const char *client_name, HNDLE *hConn)
Definition midas.cxx:2782
INT cm_start_watchdog_thread()
Definition midas.cxx:7366
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:2313
std::string cm_expand_env(const char *str)
Definition midas.cxx:7721
int cm_exec_script(const char *odb_path_to_script)
Definition midas.cxx:5479
INT cm_disconnect_experiment(void)
Definition midas.cxx:2862
std::string cm_get_exptab_filename()
Definition midas.cxx:1804
std::string cm_get_path()
Definition midas.cxx:1553
std::string cm_get_history_path(const char *history_channel)
Definition midas.cxx:5861
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2150
const char * cm_get_version()
Definition midas.cxx:1492
std::string cm_get_experiment_name()
Definition midas.cxx:1596
const char * cm_get_revision()
Definition midas.cxx:1500
INT cm_exist(const char *name, BOOL bUnique)
Definition midas.cxx:7531
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:126
#define CM_SUCCESS
Definition midas.h:582
#define CM_WRONG_PASSWORD
Definition midas.h:589
#define DB_STRUCT_MISMATCH
Definition midas.h:655
#define DB_OUT_OF_RANGE
Definition midas.h:652
#define DB_INVALID_HANDLE
Definition midas.h:636
#define DB_NO_ACCESS
Definition midas.h:649
#define DB_SUCCESS
Definition midas.h:632
#define DB_NO_KEY
Definition midas.h:643
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define SS_SUCCESS
Definition midas.h:664
#define SS_FILE_ERROR
Definition midas.h:670
#define SS_CREATED
Definition midas.h:665
#define SS_SOCKET_ERROR
Definition midas.h:674
#define RPC_SHUTDOWN
Definition midas.h:708
#define RPC_SUCCESS
Definition midas.h:699
#define RPC_NET_ERROR
Definition midas.h:702
#define HS_UNDEFINED_VAR
Definition midas.h:734
#define HS_SUCCESS
Definition midas.h:728
#define HS_FILE_ERROR
Definition midas.h:729
#define EL_SUCCESS
Definition midas.h:746
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 x
Definition mgd.h:121
char * data
Definition mgd.h:54
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
int y
Definition mgd.h:121
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()
void D(const char *description)
Definition mjsonrpc.cxx:303
MJsonNode * mjsonrpc_decode_post_data(const char *post_data)
void P(const char *name, int mjson_type, const char *description)
Definition mjsonrpc.cxx:340
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)
void R(const char *name, int mjson_type, const char *description)
Definition mjsonrpc.cxx:348
#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:835
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
char * buf
Definition mongoose6.h:834
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
int ss_dir_exist(const char *path)
Definition system.cxx:7264
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:989
INT EXPRT cm_msg_facilities(STRING_LIST *list)
Definition midas.cxx:518
INT cm_msg_flush_buffer()
Definition midas.cxx:881
std::string cm_get_error(INT code)
Definition midas.cxx:469
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:931
INT cm_msg_retrieve2(const char *facility, time_t t, INT n_message, char **messages, int *num_messages)
Definition midas.cxx:1280
void cm_msg_get_logfile(const char *fac, time_t t, std::string *filename, std::string *linkname, std::string *linktarget)
Definition midas.cxx:553
#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:3285
INT db_sprintfh(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:11005
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6917
INT db_find_link(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4293
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5185
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6385
std::string strcomb1(const char **list)
Definition odb.cxx:668
INT db_set_link_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7449
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4775
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11834
INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT *buffer_size, const char *path)
Definition odb.cxx:8230
INT db_set_link_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7773
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6563
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3392
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:13003
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9055
INT db_scan_tree(HNDLE hDB, HNDLE hKey, INT level, INT(*callback)(HNDLE, HNDLE, KEY *, INT, void *), void *info)
Definition odb.cxx:4544
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6043
INT db_get_link(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6096
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:13967
INT db_sprintff(char *string, const char *format, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10941
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:7668
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13845
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7239
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5495
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
Definition odb.cxx:3999
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:10865
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:10529
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:5028
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4256
INT db_get_link_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6680
INT db_rename_key(HNDLE hDB, HNDLE hKey, const char *name)
Definition odb.cxx:6285
INT db_get_key_time(HNDLE hDB, HNDLE hKey, DWORD *delta)
Definition odb.cxx:6156
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:5135
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5357
INT EXPRT db_resize_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int num_values, int max_string_length)
Definition odb.cxx:14058
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12831
INT db_sscanf(const char *data_str, void *data, INT *data_size, INT i, DWORD tid)
Definition odb.cxx:11336
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7523
INT db_create_link(HNDLE hDB, HNDLE hKey, const char *link_name, const char *destination)
Definition odb.cxx:3688
#define RPC_CNAF16
Definition mrpc.h:129
INT rpc_client_call(HNDLE hConn, DWORD routine_id,...)
Definition midas.cxx:13926
INT rpc_register_functions(const RPC_LIST *new_list, RPC_HANDLER func)
Definition midas.cxx:11958
#define RPC_JRPC
Definition mrpc.h:134
bool rpc_is_remote(void)
Definition midas.cxx:12892
static std::vector< RPC_LIST > rpc_list
Definition midas.cxx:11704
const char * rpc_tid_name(INT id)
Definition midas.cxx:11895
#define RPC_CNAF24
Definition mrpc.h:130
#define RPC_MANUAL_TRIG
Definition mrpc.h:132
INT rpc_tid_size(INT id)
Definition midas.cxx:11888
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:14207
static bool trace_mg
Definition mhttpd.cxx:13739
static void SaveHistPlotToOdb(MVOdb *odb, const HistPlot &hp, const char *group, const char *panel)
Definition mhttpd.cxx:10438
static bool trace_mg_send
Definition mhttpd.cxx:13741
#define LOG2
Definition mhttpd.cxx:7662
BOOL is_editable(char *eq_name, char *var_name)
Definition mhttpd.cxx:2561
#define LN10
Definition mhttpd.cxx:7661
const unsigned char favicon_png[]
Definition mhttpd.cxx:217
#define WEB_BUFFER_SIZE
Definition mhttpd.cxx:541
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:7665
static bool cmp_vars(const HistVar &a, const HistVar &b)
Definition mhttpd.cxx:10134
void output_key(Param *p, Return *r, HNDLE hkey, int index, const char *format)
Definition mhttpd.cxx:4406
static MVOdb * gOdb
Definition mhttpd.cxx:48
void get_elog_url(char *url, int len)
static void DeleteHistPlotDeleted(HistPlot &hp)
Definition mhttpd.cxx:10514
static BOOL history_mode
Definition mhttpd.cxx:95
static void LoadHistPlotFromParam(HistPlot *hp, Param *p)
Definition mhttpd.cxx:10333
static void add_rpc_functions()
Definition mhttpd.cxx:16250
#define RESPONSE_501
Definition mhttpd.cxx:14290
INT check_odb_records(MVOdb *odb)
Definition mhttpd.cxx:13423
static int handle_http_post(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14918
std::string get_content_type(const char *filename)
Definition mhttpd.cxx:1165
static const std::string find_header_mg(const struct http_message *msg, const char *name)
Definition mhttpd.cxx:14176
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:13789
#define HTTP_ENCODING
Definition mhttpd.cxx:213
void strencode(Return *r, const char *text)
Definition mhttpd.cxx:2049
static MVOdb * gMimeTypesOdb
Definition mhttpd.cxx:179
void init_elog_odb()
Definition mhttpd.cxx:2008
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:2589
static void history_watch_callback(HNDLE hDB, HNDLE hKey, int index, void *info)
Definition mhttpd.cxx:8178
void show_custom_file(Return *r, const char *name)
Definition mhttpd.cxx:3641
void show_find_page(Return *r, const char *value)
Definition mhttpd.cxx:7600
#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:6769
bool send_fp(Return *r, const std::string &path, FILE *fp)
Definition mhttpd.cxx:1196
std::vector< std::string > get_resource_paths()
Definition mhttpd.cxx:1021
static void SplitEventAndTagNames(std::string var_name, std::string &event_name, std::string &tag_name)
Definition mhttpd.cxx:10184
void decode_cookies(Cookies *c, const http_message *msg)
Definition mhttpd.cxx:14241
char * stristr(const char *str, const char *pattern)
Definition mhttpd.cxx:371
void submit_elog(MVOdb *odb, Param *pp, Return *r, Attachment *a)
Definition mhttpd.cxx:2278
void show_query_page(Param *p, Return *r)
Definition mhttpd.cxx:9824
static void urlEncode(char *ps, int ps_size)
Definition mhttpd.cxx:951
static std::string NextHistPlotColour(const HistPlot &hp)
Definition mhttpd.cxx:10149
std::string strencode2(const char *text)
Definition mhttpd.cxx:2077
void decode_get(Return *rr, char *string, const Cookies *c, const char *url, const char *query_string, RequestTrace *t)
Definition mhttpd.cxx:13228
static MJsonNode * get_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16223
void show_error(Return *r, const char *error)
Definition mhttpd.cxx:1868
static HNDLE gMhkey
Definition mhttpd.cxx:8186
static bool read_passwords(Auth *auth)
Definition mhttpd.cxx:13831
void redirect2(Return *r, const char *path)
Definition mhttpd.cxx:1478
static void show_cnaf_page(Param *p, Return *rr)
Definition mhttpd.cxx:5687
static void SaveMimetypes(MVOdb *odb)
Definition mhttpd.cxx:203
#define MAX_PARAM
Definition mhttpd.cxx:727
#define DEFAULT_REFRESH
Definition mhttpd.cxx:39
void show_navigation_bar(Return *r, const char *cur_page)
Definition mhttpd.cxx:1896
#define LOG5
Definition mhttpd.cxx:7663
void ctrlc_handler(int sig)
Definition mhttpd.cxx:13487
static void PrintHistPlot(const HistPlot &hp)
Definition mhttpd.cxx:10139
void javascript_commands(Param *p, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:4481
#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:14762
std::string time_to_string(time_t t)
Definition mhttpd.cxx:8166
static std::string mgstr(const mg_str *s)
Definition mhttpd.cxx:14171
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:7939
static bool mongoose_passwords_enabled(const struct mg_connection *nc)
static bool verbose_mg
Definition mhttpd.cxx:13738
static int cmp_names(const void *a, const void *b)
Definition mhttpd.cxx:10008
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:1285
int find_file_mg(const char *filename, std::string &path, FILE **fpp, bool trace)
Definition mhttpd.cxx:13706
void decode_query(Param *pp, const char *query_string)
Definition mhttpd.cxx:13203
static bool gDoReloadHistory
Definition mhttpd.cxx:8176
static std::string check_digest_auth(struct http_message *hm, Auth *auth)
Definition mhttpd.cxx:13927
static MidasHistoryInterface * gMh
Definition mhttpd.cxx:8185
static bool trace_mg_verbose
Definition mhttpd.cxx:13742
static bool gDoSetupHistoryWatch
Definition mhttpd.cxx:8175
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:8554
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:7818
void show_password_page(Return *r, const char *dec_path, const char *password)
Definition mhttpd.cxx:6735
time_t string_to_time(const char *str)
Definition mhttpd.cxx:8150
void show_header(Return *r, const char *title, const char *method, const char *path, int refresh)
Definition mhttpd.cxx:1808
bool send_resource(Return *r, const std::string &name, bool generate_404=true)
Definition mhttpd.cxx:1261
void strencode3(Return *r, const char *text)
Definition mhttpd.cxx:2108
static std::vector< std::string > gAllowedHosts
Definition mhttpd.cxx:13497
bool send_file(Return *r, const std::string &path, bool generate_404=true)
Definition mhttpd.cxx:1242
static int xmg_check_nonce(const char *nonce)
Definition mhttpd.cxx:13810
void show_text_header(Return *r)
Definition mhttpd.cxx:1856
char * find_odb_tag(char *p, char *path, char *format, int *edit, char *type, char *pwd, char *tail)
Definition mhttpd.cxx:3123
static std::string UrlDecode(const char *p)
Definition mhttpd.cxx:873
void strencode4(Return *r, const char *text)
Definition mhttpd.cxx:2133
void show_elog_attachment(Param *p, Return *r, const char *path)
Definition mhttpd.cxx:2513
void Unlock(RequestTrace *t)
Definition mhttpd.cxx:12276
int evaluate_src(char *key, char *src, double *fvalue)
Definition mhttpd.cxx:3529
void redirect(Return *r, const char *path)
Definition mhttpd.cxx:1441
static void urlDecode(char *p)
Definition mhttpd.cxx:912
static std::string add_param_to_url(const char *name, const char *value)
Definition mhttpd.cxx:9813
#define READ_HISTORY_DATA
Definition mhttpd.cxx:8353
bool starts_with(const std::string &s1, const char *s2)
Definition mhttpd.cxx:4465
static const char * cgif_bar_str[]
Definition mhttpd.cxx:3500
#define PARAM_LENGTH
Definition mhttpd.cxx:728
#define RESPONSE_QUEUED
Definition mhttpd.cxx:14289
static MidasHistoryInterface * get_history(bool reset=false)
Definition mhttpd.cxx:8190
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:3307
static int handle_http_get(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14835
#define READ_HISTORY_RUNMARKER
Definition mhttpd.cxx:8354
std::string add_custom_path(const std::string &filename)
Definition mhttpd.cxx:3602
void sec_to_label(char *result, int sec, int base, int force_date)
Definition mhttpd.cxx:7783
void show_odb_page(Param *pp, Return *r, const char *dec_path, int write_access)
Definition mhttpd.cxx:6826
void send_icon(Return *r, const char *icon)
Definition mhttpd.cxx:12218
static BOOL elog_mode
Definition mhttpd.cxx:94
void Lock(RequestTrace *t)
Definition mhttpd.cxx:12270
void show_set_page(Param *pp, Return *r, const char *group, int index, const char *value)
Definition mhttpd.cxx:7466
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:13266
#define DELETE(x)
Definition mhttpd.cxx:8268
void show_hist_config_page(MVOdb *odb, Param *p, Return *r, const char *hgroup, const char *hpanel)
Definition mhttpd.cxx:10552
static const std::string find_cookie_mg(const struct http_message *msg, const char *cookie_name)
Definition mhttpd.cxx:14189
void do_jrpc(Param *p, Return *r)
Definition mhttpd.cxx:4352
const unsigned char favicon_ico[]
Definition mhttpd.cxx:288
void init_mhttpd_odb(MVOdb *odb)
Definition mhttpd.cxx:1960
void check_obsolete_odb(HNDLE hDB, const char *odb_path)
Definition mhttpd.cxx:1910
void do_jrpc_rev1(Param *p, Return *r)
Definition mhttpd.cxx:4171
static RequestTraceBuf * gTraceBuf
Definition mhttpd.cxx:536
const char * mhttpd_revision(void)
Definition mhttpd.cxx:866
void show_hist_page(MVOdb *odb, Param *p, Return *r, const char *dec_path, char *buffer, int *buffer_size, int refresh)
Definition mhttpd.cxx:11295
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:14292
void gen_odb_attachment(Return *r, const char *path, std::string &bout)
Definition mhttpd.cxx:2164
#define RESPONSE_SENT
Definition mhttpd.cxx:14288
bool open_resource_file(const char *filename, std::string *ppath, FILE **pfp)
Definition mhttpd.cxx:1061
void redirect_307(Return *r, const char *path)
Definition mhttpd.cxx:1465
static std::string GetMimetype(const std::string &ext)
Definition mhttpd.cxx:181
static double GetTimeSec()
Definition mhttpd.cxx:406
void show_custom_page(Param *pp, Return *r, const char *cookie_cpwd)
Definition mhttpd.cxx:5453
static MJsonNode * set_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16236
const bool cmp_tags(const TAG &a, const TAG &b)
Definition mhttpd.cxx:10076
const bool cmp_events1(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10071
#define READ_HISTORY_LAST_WRITTEN
Definition mhttpd.cxx:8355
int read_history(const HistPlot &hp, int index, int flags, time_t tstart, time_t tend, time_t scale, HistoryData *data)
Definition mhttpd.cxx:8389
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:8125
static BOOL verbose
Definition mhttpd.cxx:96
void show_help_page(Return *r, const char *dec_path)
Definition mhttpd.cxx:1574
void do_jrpc_rev0(Param *p, Return *r)
Definition mhttpd.cxx:4046
INT search_callback(HNDLE hDB, HNDLE hKey, KEY *key, INT level, void *info)
Definition mhttpd.cxx:1491
void init_menu_buttons(MVOdb *odb)
Definition mhttpd.cxx:1919
std::atomic_bool _abort
Definition mhttpd.cxx:13485
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:8637
#define ALLOC(t, n)
Definition mhttpd.cxx:8267
static const char * cgif_label_str[]
Definition mhttpd.cxx:3460
time_t mktime_with_dst(const struct tm *ptms)
Definition mhttpd.cxx:9778
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:13673
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:11058
#define STRDUP(x)
Definition mhttpd.cxx:8270
static int http_trace
Definition mhttpd.cxx:465
static void xmg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
Definition mhttpd.cxx:13821
void interprete(Param *p, Return *r, Attachment *a, const Cookies *c, const char *dec_path, RequestTrace *t)
Definition mhttpd.cxx:12284
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:15044
#define DELETEA(x, n)
Definition mhttpd.cxx:8269
static Auth * gAuthMg
Definition mhttpd.cxx:13787
static void SortHistPlotVars(HistPlot &hp)
Definition mhttpd.cxx:10531
const bool cmp_events(const std::string &a, const std::string &b)
Definition mhttpd.cxx:10066
int xdb_get_data_index(HNDLE hDB, const char *str, void *value, int size, int index, int tid)
Definition mhttpd.cxx:10095
void show_error_404(Return *r, const char *error)
Definition mhttpd.cxx:1883
static void handle_http_message(struct mg_connection *nc, http_message *msg)
Definition mhttpd.cxx:15114
static int xdb_find_key(HNDLE hDB, HNDLE dir, const char *str, HNDLE *hKey, int tid, int size)
Definition mhttpd.cxx:10111
static void AddHistPlotSelectedParam(HistPlot &hp, Param *p)
Definition mhttpd.cxx:10410
void show_custom_gif(Return *rr, const char *name)
Definition mhttpd.cxx:3704
static void LoadHistPlotFromOdb(MVOdb *odb, HistPlot *hp, const char *group, const char *panel)
Definition mhttpd.cxx:10228
static bool trace_mg_recv
Definition mhttpd.cxx:13740
static int NextHistPlotOrder(const HistPlot &hp)
Definition mhttpd.cxx:10175
#define TEXT_SIZE
Definition mhttpd.cxx:729
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:1535
#define RPC_OUT
Definition midas.h:1564
DWORD BOOL
Definition midas.h:105
#define DIR_SEPARATOR_STR
Definition midas.h:194
#define RPC_IN
Definition midas.h:1563
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
#define RPC_MAX_ID
Definition midas.h:1591
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:1537
#define TRUE
Definition midas.h:182
#define CNAF
Definition midas.h:491
#define CNAF_CRATE_CLEAR
Definition midas.h:496
#define DEFAULT_ODB_SIZE
Definition midas.h:270
#define EQUIPMENT_COMMON_STR
Definition midas.h:1112
#define POINTER_T
Definition midas.h:166
std::vector< std::string > STRING_LIST
Definition midas.h:246
INT MUTEX_T
Definition midas.h:237
#define RUNINFO_STR(_name)
Definition midas.h:1409
#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
Definition mhttpd.cxx:13751
std::string password
Definition mhttpd.cxx:13754
std::string username
Definition mhttpd.cxx:13752
std::string realm
Definition mhttpd.cxx:13753
char bgcolor[8]
Definition mhttpd.cxx:3523
double max
Definition mhttpd.cxx:3521
char src[256]
Definition mhttpd.cxx:3518
BOOL logscale
Definition mhttpd.cxx:3520
double min
Definition mhttpd.cxx:3521
int width
Definition mhttpd.cxx:3519
char fgcolor[8]
Definition mhttpd.cxx:3522
int height
Definition mhttpd.cxx:3519
int direction
Definition mhttpd.cxx:3519
char bdcolor[8]
Definition mhttpd.cxx:3524
char format[32]
Definition mhttpd.cxx:3474
char src[256]
Definition mhttpd.cxx:3473
char bgcolor[8]
Definition mhttpd.cxx:3478
char font[32]
Definition mhttpd.cxx:3475
char fgcolor[8]
Definition mhttpd.cxx:3477
std::string cookie_pwd
Definition mhttpd.cxx:12261
int refresh
Definition mhttpd.cxx:12264
std::string cookie_wpwd
Definition mhttpd.cxx:12262
std::string cookie_cpwd
Definition mhttpd.cxx:12263
std::string timescale
Definition mhttpd.cxx:8373
bool enable_factor
Definition mhttpd.cxx:8382
bool show_fill
Definition mhttpd.cxx:8380
double minimum
Definition mhttpd.cxx:8374
double maximum
Definition mhttpd.cxx:8375
bool show_factor
Definition mhttpd.cxx:8381
bool zero_ylow
Definition mhttpd.cxx:8376
bool show_values
Definition mhttpd.cxx:8379
bool log_axis
Definition mhttpd.cxx:8377
std::vector< HistVar > vars
Definition mhttpd.cxx:8384
bool show_run_markers
Definition mhttpd.cxx:8378
double factor
Definition mhttpd.cxx:8366
std::string tag_name
Definition mhttpd.cxx:8360
double offset
Definition mhttpd.cxx:8367
int order
Definition mhttpd.cxx:8365
std::string formula
Definition mhttpd.cxx:8361
std::string label
Definition mhttpd.cxx:8363
double voffset
Definition mhttpd.cxx:8368
std::string colour
Definition mhttpd.cxx:8362
std::string event_name
Definition mhttpd.cxx:8359
bool show_raw_value
Definition mhttpd.cxx:8364
int * odb_index
Definition mhttpd.cxx:8279
time_t tstart
Definition mhttpd.cxx:8288
void Free()
Definition mhttpd.cxx:8310
int alloc_nvars
Definition mhttpd.cxx:8275
void Allocate(int xnvars)
Definition mhttpd.cxx:8292
time_t tend
Definition mhttpd.cxx:8289
double ** v
Definition mhttpd.cxx:8283
void Print() const
Definition mhttpd.cxx:8325
time_t ** t
Definition mhttpd.cxx:8282
char ** var_names
Definition mhttpd.cxx:8277
int * var_index
Definition mhttpd.cxx:8278
char ** event_names
Definition mhttpd.cxx:8276
int * status
Definition mhttpd.cxx:8280
bool have_last_written
Definition mhttpd.cxx:8285
time_t * last_written
Definition mhttpd.cxx:8286
int * num_entries
Definition mhttpd.cxx:8281
time_t scale
Definition mhttpd.cxx:8290
Definition midas.h:1027
INT num_values
Definition midas.h:1029
DWORD type
Definition midas.h:1028
INT total_size
Definition midas.h:1032
WORD access_mode
Definition midas.h:1034
INT last_written
Definition midas.h:1038
char name[NAME_LENGTH]
Definition midas.h:1030
INT item_size
Definition midas.h:1033
Definition mhttpd.cxx:125
std::string mimetype
Definition mhttpd.cxx:127
std::string ext
Definition mhttpd.cxx:126
Definition midas.h:1233
char name[NAME_LENGTH]
Definition midas.h:1234
Definition mgd.h:58
Definition mgd.h:120
Return * r
Definition mhttpd.cxx:1487
const char * search_name
Definition mhttpd.cxx:1488
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