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 += "/EL/";
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 std::string xurl;
11488 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &xurl, FALSE);
11489 if (status == DB_SUCCESS) {
11490 char url[256];
11491 get_elog_url(url, sizeof(url));
11492
11493 /*---- use external ELOG ----*/
11494 fsize = 100000;
11495 char* fbuffer = (char*)M_MALLOC(fsize);
11496 assert(fbuffer != NULL);
11497
11498 int width = 640;
11499 int height = 400;
11500
11501 if (equal_ustring(pmag, "Large")) {
11502 width = 1024;
11503 height = 768;
11504 } else if (equal_ustring(pmag, "Small")) {
11505 width = 320;
11506 height = 200;
11507 } else if (atoi(pmag) > 0) {
11508 width = atoi(pmag);
11509 height = 200;
11510 }
11511
11512 printf("hereA\n");
11513 generate_hist_graph(odb, r, hgroup, hpanel, fbuffer, &fsize, width, height, endtime, scale, index, labels, bgcolor.c_str(), fgcolor.c_str(), gridcolor.c_str());
11514
11515 /* save temporary file */
11516 std::string dir;
11517 db_get_value_string(hDB, 0, "/Elog/Logbook Dir", 0, &dir, TRUE);
11518 if (dir.length() > 0 && dir[dir.length()-1] != DIR_SEPARATOR)
11519 dir += DIR_SEPARATOR_STR;
11520
11521 time_t now = time(NULL);
11522 localtime_r(&now, &tms);
11523
11524 std::string file_name = msprintf("%02d%02d%02d_%02d%02d%02d_%s.gif",
11525 tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday,
11526 tms.tm_hour, tms.tm_min, tms.tm_sec, hpanel);
11527 std::string fname = dir + file_name;
11528
11529 /* save attachment */
11530 fh = open(fname.c_str(), O_CREAT | O_RDWR | O_BINARY, 0644);
11531 if (fh < 0) {
11532 cm_msg(MERROR, "show_hist_page", "Cannot write attachment file \"%s\", open() errno %d (%s)", fname.c_str(), errno, strerror(errno));
11533 } else {
11534 int wr = write(fh, fbuffer, fsize);
11535 if (wr != fsize) {
11536 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));
11537 }
11538 close(fh);
11539 }
11540
11541 /* redirect to ELOG */
11542 if (strlen(url) > 1 && url[strlen(url)-1] != '/')
11543 mstrlcat(url, "/", sizeof(url));
11544 mstrlcat(url, "?cmd=New&fa=", sizeof(url));
11545 mstrlcat(url, file_name, sizeof(url));
11546 redirect(r, url);
11547
11548 M_FREE(fbuffer);
11549 return;
11550
11551 } else {
11552 /*---- use internal ELOG ----*/
11553 std::string str = msprintf("\\HS\\%s.gif", hpanel);
11554 if (p->getparam("hscale") && *p->getparam("hscale"))
11555 str += msprintf("?scale=%s", p->getparam("hscale"));
11556 if (p->getparam("htime") && *p->getparam("htime")) {
11557 if (strchr(str.c_str(), '?'))
11558 str += "&";
11559 else
11560 str += "?";
11561 str += msprintf("time=%s", p->getparam("htime"));
11562 }
11563 //if (p->getparam("hoffset") && *p->getparam("hoffset")) {
11564 // if (strchr(str, '?'))
11565 // mstrlcat(str, "&", sizeof(str));
11566 // else
11567 // mstrlcat(str, "?", sizeof(str));
11568 // sprintf(str + strlen(str), "offset=%s", p->getparam("hoffset"));
11569 //}
11570 if (p->getparam("hwidth") && *p->getparam("hwidth")) {
11571 if (strchr(str.c_str(), '?'))
11572 str += "&";
11573 else
11574 str += "?";
11575 str += msprintf("width=%s", p->getparam("hwidth"));
11576 }
11577 if (p->getparam("hindex") && *p->getparam("hindex")) {
11578 if (strchr(str.c_str(), '?'))
11579 str += "&";
11580 else
11581 str += "?";
11582 str += msprintf("index=%s", p->getparam("hindex"));
11583 }
11584
11585 show_elog_new(r, hpanel, NULL, FALSE, str.c_str(), "../../EL/");
11586 return;
11587 }
11588 }
11589#endif
11590
11591 if (equal_ustring(hcmd, "Export")) {
11592 export_hist(odb, r, hgroup, hpanel, endtime, scale, index, labels);
11593 return;
11594 }
11595
11596 if (strstr(dec_path, ".gif")) {
11597 int width = 640;
11598 int height = 400;
11599 if (equal_ustring(pwidth, "Large")) {
11600 width = 1024;
11601 height = 768;
11602 } else if (equal_ustring(pwidth, "Small")) {
11603 width = 320;
11604 height = 200;
11605 } else if (atoi(pwidth) > 0) {
11606 width = atoi(pwidth);
11607 if (atoi(pheight) > 0)
11608 height = atoi(pheight);
11609 else
11610 height = (int)(0.625 * width);
11611 }
11612
11613 //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);
11614
11615 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());
11616
11617 return;
11618 }
11619
11620 if (history_mode && index < 0)
11621 return;
11622
11623 time_t now = time(NULL);
11624
11625 /* evaluate offset shift */
11626 if (equal_ustring(p->getparam("shift"), "leftmaxall")) {
11627 if (endtime == 0)
11628 endtime = now;
11629 time_t last_written = 0;
11630 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 1, &last_written);
11631 if (status == HS_SUCCESS)
11632 endtime = last_written + scale/2;
11633 }
11634
11635 if (equal_ustring(p->getparam("shift"), "leftmax")) {
11636 if (endtime == 0)
11637 endtime = now;
11638 time_t last_written = 0;
11639 status = get_hist_last_written(odb, hgroup, hpanel, endtime, index, 0, &last_written);
11640 if (status == HS_SUCCESS)
11641 if (last_written != endtime)
11642 endtime = last_written + scale/2;
11643 }
11644
11645 if (equal_ustring(p->getparam("shift"), "left")) {
11646 if (endtime == 0)
11647 endtime = now;
11648 endtime -= scale/2;
11649 //offset -= scale / 2;
11650 }
11651
11652 if (equal_ustring(p->getparam("shift"), "right")) {
11653 if (endtime == 0)
11654 endtime = now;
11655 endtime += scale/2;
11656 if (endtime > now)
11657 endtime = now;
11658 }
11659
11660 if (equal_ustring(p->getparam("shift"), "rightmax")) {
11661 endtime = 0;
11662 }
11663
11664 if (equal_ustring(p->getparam("shift"), "zoomin")) {
11665 if (endtime == 0)
11666 endtime = now;
11667 endtime -= scale / 4;
11668 scale /= 2;
11669 }
11670
11671 if (equal_ustring(p->getparam("shift"), "zoomout")) {
11672 if (endtime == 0)
11673 endtime = now;
11674 endtime += scale / 2;
11675 if (endtime > now)
11676 endtime = now;
11677 scale *= 2;
11678 }
11679
11680 int xrefresh = refresh;
11681 if (endtime != 0)
11682 xrefresh = 0;
11683 show_header(r, hpanel, "GET", "", xrefresh);
11684
11685 r->rsprintf("<script type=\"text/javascript\" src=\"midas.js\"></script>\n");
11686 r->rsprintf("<script type=\"text/javascript\" src=\"mhttpd.js\"></script>\n");
11687 show_navigation_bar(r, "History");
11688
11689 r->rsprintf("<table class=\"mtable\">");
11690 r->rsprintf("<tr><th class=\"mtableheader\" colspan=2>History</th></tr>");
11691
11692 {
11693 /* check if panel exists */
11694 std::string path;
11695 //sprintf(str, "/History/Display/%s/%s", hgroup, hpanel);
11696 path += "/History/Display/";
11697 path += hgroup;
11698 path += "/";
11699 path += hpanel;
11700 status = db_find_key(hDB, 0, path.c_str(), &hkey);
11701 if (status != DB_SUCCESS && !equal_ustring(hpanel, "All") && !equal_ustring(hpanel,"")) {
11702 r->rsprintf("<h1>Error: History panel \"%s\" in group \"%s\" does not exist</h1>\n", hpanel, hgroup);
11703 r->rsprintf("</table>\r\n");
11704 r->rsprintf("</div>\n"); // closing for <div id="mmain">
11705 r->rsprintf("</form>\n");
11706 r->rsprintf("</body></html>\r\n");
11707 return;
11708 }
11709 }
11710
11711 /* define hidden field for parameters */
11712 if (pscale && *pscale)
11713 r->rsprintf("<input type=hidden name=hscale id=hscale value=%d>\n", scale);
11714 else {
11715 /* if no scale and offset given, get it from default */
11716 if (hpanel[0] && !equal_ustring(hpanel, "All") && hgroup[0]) {
11717 std::string path;
11718 path += "/History/Display/";
11719 path += hgroup;
11720 path += "/";
11721 path += hpanel;
11722 path += "/Timescale";
11723
11724 std::string scalestr = "1h";
11725 status = db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11726 if (status != DB_SUCCESS) {
11727 /* delete old integer key */
11728 db_delete(hDB, 0, path.c_str());
11729 scalestr = "1h";
11730 db_get_value_string(hDB, 0, path.c_str(), 0, &scalestr, TRUE);
11731 }
11732
11733 r->rsprintf("<input type=hidden name=hscale id=hscale value=%s>\n", scalestr.c_str());
11734 scale = time_to_sec(scalestr.c_str());
11735 }
11736 }
11737
11738 if (endtime != 0)
11739 r->rsprintf("<input type=hidden name=htime id=htime value=%s>\n", time_to_string(endtime).c_str());
11740 if (pwidth && *pwidth)
11741 r->rsprintf("<input type=hidden name=hwidth id=hwidth value=%s>\n", pwidth);
11742 if (pheight && *pheight)
11743 r->rsprintf("<input type=hidden name=hheight id=hheight value=%s>\n", pheight);
11744 if (pindex && *pindex)
11745 r->rsprintf("<input type=hidden name=hindex id=hindex value=%s>\n", pindex);
11746
11747 r->rsprintf("</td></tr>\n");
11748
11749 if (hgroup[0] == 0) {
11750 /* "New" button */
11751 r->rsprintf("<tr><td colspan=2><input type=\"button\" name=\"New\" value=\"New\" ");
11752 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New'\"></td></tr>\n");
11753
11754 /* links for history panels */
11755 r->rsprintf("<tr><td colspan=2 style=\"text-align:left;\">\n");
11756 if (!hpanel[0])
11757 r->rsprintf("<b>Please select panel:</b><br>\n");
11758
11759 /* table for panel selection */
11760 r->rsprintf("<table class=\"historyTable\">");
11761
11762 /* "All" link */
11763 r->rsprintf("<tr><td colspan=2 class=\"titleCell\">\n");
11764 if (equal_ustring(hgroup, "All"))
11765 r->rsprintf("All &nbsp;&nbsp;");
11766 else
11767 r->rsprintf("<a href=\"?cmd=oldhistory&group=All\">ALL</a>\n");
11768 r->rsprintf("</td></tr>\n");
11769
11770 /* Setup History table links */
11771 db_find_key(hDB, 0, "/History/Display", &hkey);
11772 if (!hkey) {
11773 /* create default panel */
11774 char str[256];
11775 strcpy(str, "System:Trigger per sec.");
11776 strcpy(str + 2 * NAME_LENGTH, "System:Trigger kB per sec.");
11777 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Variables", str, 64, 2, TID_STRING);
11778 strcpy(str, "1h");
11779 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Time Scale", str, NAME_LENGTH, 1, TID_STRING);
11780
11781 strcpy(str, "1h");
11782 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Timescale", str, NAME_LENGTH, 1, TID_STRING);
11783 i = 1;
11784 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Zero ylow", &i, sizeof(BOOL), 1, TID_BOOL);
11785 i = 1;
11786 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Show run markers", &i, sizeof(BOOL), 1, TID_BOOL);
11787
11788 strcpy(str, "");
11789 db_set_value(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING);
11790 db_set_value_index(hDB, 0, "/History/Display/Default/Trigger rate/Formula", str, 64, 1, TID_STRING, FALSE);
11791 }
11792
11793 db_find_key(hDB, 0, "/History/Display", &hkey);
11794 if (hkey) {
11795 for (i = 0;; i++) {
11796 db_enum_link(hDB, hkey, i, &hkeyp);
11797
11798 if (!hkeyp)
11799 break;
11800
11801 // Group key
11802 db_get_key(hDB, hkeyp, &key);
11803
11804 char enc_name[256];
11805 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11806 urlEncode(enc_name, sizeof(enc_name));
11807
11808 if (equal_ustring(hpanel, key.name))
11809 r->rsprintf("<tr><td class=\"titleCell\">%s</td>\n<td>", key.name);
11810 else
11811 r->rsprintf("<tr><td class=\"titleCell\"><a href=\"?cmd=oldhistory&group=%s\">%s</a></td>\n<td>", enc_name, key.name);
11812
11813 for (j = 0;; j++) {
11814 // scan items
11815 db_enum_link(hDB, hkeyp, j, &hikeyp);
11816
11817 if (!hikeyp) {
11818 r->rsprintf("</tr>");
11819 break;
11820 }
11821 // Item key
11822 db_get_key(hDB, hikeyp, &ikey);
11823
11824 char enc_iname[256];
11825 mstrlcpy(enc_iname, ikey.name, sizeof(enc_iname));
11826 urlEncode(enc_iname, sizeof(enc_iname));
11827
11828 if (equal_ustring(hpanel, ikey.name))
11829 r->rsprintf("<small><b>%s</b></small> &nbsp;", ikey.name);
11830 else
11831 r->rsprintf("<small><a href=\"?cmd=oldhistory&group=%s&panel=%s\">%s</a></small> &nbsp;\n", enc_name, enc_iname, ikey.name);
11832 }
11833 }
11834 }
11835
11836 r->rsprintf("</table></tr>\n");
11837
11838 } else {
11839 int found = 0;
11840
11841 /* show drop-down selectors */
11842 r->rsprintf("<tr><td colspan=2>\n");
11843
11844 r->rsprintf("Group:\n");
11845
11846 r->rsprintf("<select title=\"Select group\" id=\"fgroup\" onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value;\">\n");
11847
11848 db_find_key(hDB, 0, "/History/Display", &hkey);
11849 if (hkey) {
11850 hkeyp = 0;
11851 for (i = 0;; i++) {
11852 db_enum_link(hDB, hkey, i, &hikeyp);
11853
11854 if (!hikeyp)
11855 break;
11856
11857 if (i == 0)
11858 hkeyp = hikeyp;
11859
11860 // Group key
11861 db_get_key(hDB, hikeyp, &key);
11862
11863 if (equal_ustring(key.name, hgroup)) {
11864 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11865 hkeyp = hikeyp;
11866 } else
11867 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11868 }
11869
11870 if (equal_ustring("ALL", hgroup)) {
11871 r->rsprintf("<option selected value=\"%s\">%s\n", "ALL", "ALL");
11872 } else {
11873 r->rsprintf("<option value=\"%s\">%s\n", "ALL", "ALL");
11874 }
11875
11876 r->rsprintf("</select>\n");
11877 r->rsprintf("&nbsp;&nbsp;Panel:\n");
11878 r->rsprintf("<select title=\"Select panel\" id=\"fpanel\" ");
11879 r->rsprintf("onChange=\"window.location.search='?cmd=oldhistory&group='+document.getElementById('fgroup').value+");
11880 r->rsprintf("'&panel='+document.getElementById('fpanel').value;\">\n");
11881
11882 found = 0;
11883 if (hkeyp) {
11884 for (i = 0;; i++) {
11885 // scan panels
11886 db_enum_link(hDB, hkeyp, i, &hikeyp);
11887
11888 if (!hikeyp)
11889 break;
11890
11891 // Item key
11892 db_get_key(hDB, hikeyp, &key);
11893
11894 if (equal_ustring(hpanel, key.name)) {
11895 r->rsprintf("<option selected value=\"%s\">%s\n", key.name, key.name);
11896 found = 1;
11897 } else
11898 r->rsprintf("<option value=\"%s\">%s\n", key.name, key.name);
11899 }
11900 }
11901
11902 if (found)
11903 r->rsprintf("<option value=\"\">- all -\n");
11904 else
11905 r->rsprintf("<option selected value=\"\">- all -\n");
11906
11907 r->rsprintf("</select>\n");
11908 }
11909
11910 r->rsprintf("<noscript>\n");
11911 r->rsprintf("<input type=submit value=\"Go\">\n");
11912 r->rsprintf("</noscript>\n");
11913
11914 r->rsprintf("&nbsp;&nbsp;<input type=\"button\" name=\"New\" value=\"New\" ");
11915 r->rsprintf("onClick=\"window.location.href='?cmd=oldhistory&hcmd=New&group=%s'\">\n", hgroup);
11916
11917 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Reset\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Reset&group=%s&panel=%s'\">\n", hgroup, hpanel);
11918
11919 r->rsprintf("<input type=\"button\" name=\"Cmd\" value=\"Query\" onClick=\"window.location.href='?cmd=oldhistory&hcmd=Query&group=%s&panel=%s'\">\n", hgroup, hpanel);
11920
11921 double xendtime = endtime;
11922 if (xendtime == 0)
11923 xendtime = now;
11924 double xstarttime = xendtime - scale;
11925
11926 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);
11927
11928 r->rsprintf("</td></tr>\n");
11929 }
11930
11931 //printf("hgroup [%s] hpanel [%s]\n", hgroup, hpanel);
11932
11933 /* check if whole group should be displayed */
11934 if (hgroup[0] && !equal_ustring(hgroup, "ALL") && hpanel[0] == 0) {
11935 std::string strwidth = "Small";
11936 db_get_value_string(hDB, 0, "/History/Display Settings/Width Group", 0, &strwidth, TRUE);
11937
11938 std::string path;
11939 path += "/History/Display/";
11940 path += hgroup;
11941 db_find_key(hDB, 0, path.c_str(), &hkey);
11942 if (hkey) {
11943 for (i = 0 ;; i++) { // scan group
11944 db_enum_link(hDB, hkey, i, &hikeyp);
11945
11946 if (!hikeyp)
11947 break;
11948
11949 db_get_key(hDB, hikeyp, &key);
11950
11951 char enc_name[256];
11952 mstrlcpy(enc_name, key.name, sizeof(enc_name));
11953 urlEncode(enc_name, sizeof(enc_name));
11954
11955 std::string ref;
11956 ref += "graph.gif?width=";
11957 ref += strwidth;
11958 ref += "&cmd=oldhistory&group=";
11959 ref += hgroup;
11960 ref += "&panel=";
11961 ref += enc_name;
11962
11963 std::string ref2;
11964 ref2 += "?cmd=oldhistory&group=";
11965 ref2 += hgroup;
11966 ref2 += "&panel=";
11967 ref2 += enc_name;
11968
11969 if (endtime != 0) {
11970 char tmp[256];
11971 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
11972 ref += "&";
11973 ref += tmp;
11974 ref2 += "?";
11975 ref2 += tmp;
11976 }
11977
11978 if (i % 2 == 0)
11979 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
11980 else
11981 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
11982 }
11983
11984 } else {
11985 r->rsprintf("Group \"%s\" not found", hgroup);
11986 }
11987 }
11988
11989 /* image panel */
11990 else if (hpanel[0] && !equal_ustring(hpanel, "All")) {
11991 /* navigation links */
11992 r->rsprintf("<tr><td>\n");
11993
11994 std::string path;
11995 path += "/History/Display/";
11996 path += hgroup;
11997 path += "/";
11998 path += hpanel;
11999 path += "/Buttons";
12000 db_find_key(hDB, 0, path.c_str(), &hkeybutton);
12001 if (hkeybutton == 0) {
12002 /* create default buttons */
12003 db_create_key(hDB, 0, path.c_str(), TID_STRING);
12004 status = db_find_key(hDB, 0, path.c_str(), &hkeybutton);
12005 if (status != DB_SUCCESS || !hkey) {
12006 cm_msg(MERROR, "show_hist_page", "Cannot create history panel with invalid ODB path \"%s\"", path.c_str());
12007 return;
12008 }
12009 db_set_data(hDB, hkeybutton, def_button, sizeof(def_button), 7, TID_STRING);
12010 }
12011
12012 r->rsprintf("<script>\n");
12013 r->rsprintf("function histDisp(p) {\n");
12014 r->rsprintf(" var params = '?cmd=oldhistory&group=%s&panel=%s';\n", hgroup, hpanel);
12015 r->rsprintf(" params += '&'+p;\n");
12016 r->rsprintf(" if (document.getElementById(\'hscale\') !== null)\n");
12017 r->rsprintf(" params += '&hscale='+document.getElementById(\'hscale\').value;\n");
12018 r->rsprintf(" if (document.getElementById(\'htime\') !== null)\n");
12019 r->rsprintf(" params += '&htime='+document.getElementById(\'htime\').value;\n");
12020 r->rsprintf(" if (document.getElementById(\'hwdith\') !== null)\n");
12021 r->rsprintf(" params += '&hwidth='+document.getElementById(\'hwidth\').value;\n");
12022 r->rsprintf(" if (document.getElementById(\'hindex\') !== null)\n");
12023 r->rsprintf(" params += '&hindex='+document.getElementById(\'hindex\').value;\n");
12024 r->rsprintf(" window.location.search = params;\n");
12025 r->rsprintf("}\n\n");
12026 r->rsprintf("</script>\n");
12027
12028 db_get_key(hDB, hkeybutton, &key);
12029
12030 for (i = 0; i < key.num_values; i++) {
12031 char str[256];
12032 size = sizeof(str);
12033 db_get_data_index(hDB, hkeybutton, str, &size, i, TID_STRING);
12034 r->rsprintf("<input type=\"button\" title=\"display last %s\" value=%s onclick=\"histDisp('scale=%s')\">\n", str, str, str);
12035 }
12036
12037 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')\">");
12038 r->rsprintf("<input type=\"button\" value=\"<<\" title=\"go back in time to last available data\" onclick=\"histDisp('shift=leftmax')\">");
12039 r->rsprintf("<input type=\"button\" value=\"<\" title=\"go back in time\" onclick=\"histDisp('shift=left')\">");
12040
12041 r->rsprintf("<input type=\"button\" value=\" + \" title=\"zoom in\" onclick=\"histDisp('shift=zoomin')\">");
12042 r->rsprintf("<input type=\"button\" value=\" - \" title=\"zoom out\" onclick=\"histDisp('shift=zoomout')\">");
12043
12044 if (endtime != 0) {
12045 r->rsprintf("<input type=\"button\" value=\">\" title=\"go forward in time\" onclick=\"histDisp('shift=right')\">");
12046 r->rsprintf("<input type=\"button\" value=\">>\" title=\"go to currently updated fresh data\" onclick=\"histDisp('shift=rightmax')\">");
12047 }
12048
12049 r->rsprintf("<td>\n");
12050 r->rsprintf("<input type=\"button\" value=\"Large\" title=\"large display\" onclick=\"histDisp('width=Large')\">\n");
12051 r->rsprintf("<input type=\"button\" value=\"Small\" title=\"large display\" onclick=\"histDisp('width=Small')\">\n");
12052 r->rsprintf("<input type=\"button\" value=\"Create Elog\" title=\"large display\" onclick=\"histDisp('hcmd=Create Elog')\">\n");
12053 r->rsprintf("<input type=\"button\" value=\"Config\" title=\"large display\" onclick=\"histDisp('hcmd=Config')\">\n");
12054 r->rsprintf("<input type=\"button\" value=\"Export\" title=\"large display\" onclick=\"histDisp('hcmd=Export')\">\n");
12055 r->rsprintf("</tr>\n");
12056
12057 char paramstr[256];
12058
12059 paramstr[0] = 0;
12060 sprintf(paramstr + strlen(paramstr), "&scale=%d", scale);
12061 if (endtime != 0)
12062 sprintf(paramstr + strlen(paramstr), "&time=%s", time_to_string(endtime).c_str());
12063 if (pwidth && *pwidth)
12064 sprintf(paramstr + strlen(paramstr), "&width=%s", pwidth);
12065 else {
12066 std::string wi = "640";
12067 db_get_value_string(hDB, 0, "/History/Display Settings/Width Individual", 0, &wi, TRUE);
12068 sprintf(paramstr + strlen(paramstr), "&width=%s", wi.c_str());
12069 }
12070 if (pheight && *pheight)
12071 sprintf(paramstr + strlen(paramstr), "&height=%s", pheight);
12072
12073 /* define image map */
12074 r->rsprintf("<map name=\"%s\">\r\n", hpanel);
12075
12076 if (!(pindex && *pindex)) {
12077 std::string path;
12078 path += "/History/Display/";
12079 path += hgroup;
12080 path += "/";
12081 path += hpanel;
12082 path += "/Variables";
12083 db_find_key(hDB, 0, path.c_str(), &hkey);
12084 if (hkey) {
12085 db_get_key(hDB, hkey, &key);
12086
12087 for (i = 0; i < key.num_values; i++) {
12088 std::string ref;
12089 //if (paramstr[0]) {
12090 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&%s&index=%d", hgroup, hpanel, paramstr, i);
12091 //} else {
12092 // sprintf(ref, "?cmd=oldhistory&group=%s&panel=%s&index=%d", hgroup, hpanel, i);
12093 //}
12094
12095 ref += "?cmd=oldhistory&group=";
12096 ref += hgroup;
12097 ref += "&panel=";
12098 ref += hpanel;
12099 if (paramstr[0]) {
12100 ref += "&";
12101 ref += paramstr;
12102 }
12103 ref += "&index=";
12104 ref += toString(i);
12105
12106 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());
12107 }
12108 }
12109 } else {
12110 std::string ref = "?cmd=oldhistory&group=";
12111 ref += hgroup;
12112 ref += "&panel=";
12113 ref += hpanel;
12114
12115 if (paramstr[0]) {
12116 ref += "&";
12117 ref += paramstr;
12118 }
12119
12120 if (equal_ustring(pwidth, "Large"))
12121 width = 1024;
12122 else if (equal_ustring(pwidth, "Small"))
12123 width = 320;
12124 else if (atoi(pwidth) > 0)
12125 width = atoi(pwidth);
12126 else
12127 width = 640;
12128
12129 r->rsprintf(" <area shape=rect coords=\"%d,%d,%d,%d\" href=\"%s\">\r\n", 0, 0, width, 20, ref.c_str());
12130 }
12131
12132 r->rsprintf("</map>\r\n");
12133
12134 /* Display individual panels */
12135 if (pindex && *pindex)
12136 sprintf(paramstr + strlen(paramstr), "&index=%s", pindex);
12137
12138 std::string ref;
12139 //sprintf(ref, "graph.gif?cmd=oldhistory&group=%s&panel=%s%s", hgroup, hpanel, paramstr);
12140 ref += "graph.gif?cmd=oldhistory&group=";
12141 ref += hgroup;
12142 ref += "&panel=";
12143 ref += hpanel;
12144 ref += paramstr;
12145
12146 /* put reference to graph */
12147 r->rsprintf("<tr><td colspan=2><img src=\"%s\" usemap=\"#%s\"></tr>\n", ref.c_str(), hpanel);
12148 }
12149
12150 else if (equal_ustring(hgroup, "All")) {
12151 /* Display all panels */
12152 db_find_key(hDB, 0, "/History/Display", &hkey);
12153 if (hkey)
12154 for (i = 0, k = 0;; i++) { // scan Groups
12155 db_enum_link(hDB, hkey, i, &hkeyp);
12156
12157 if (!hkeyp)
12158 break;
12159
12160 db_get_key(hDB, hkeyp, &key);
12161
12162 char enc_group_name[256];
12163 mstrlcpy(enc_group_name, key.name, sizeof(enc_group_name));
12164 urlEncode(enc_group_name, sizeof(enc_group_name));
12165
12166 for (j = 0;; j++, k++) {
12167 // scan items
12168 db_enum_link(hDB, hkeyp, j, &hikeyp);
12169
12170 if (!hikeyp)
12171 break;
12172
12173 db_get_key(hDB, hikeyp, &ikey);
12174
12175 char enc_panel_name[256];
12176 mstrlcpy(enc_panel_name, ikey.name, sizeof(enc_panel_name));
12177 urlEncode(enc_panel_name, sizeof(enc_panel_name));
12178
12179 std::string ref;
12180 ref += "graph.gif?width=Small";
12181 ref += "&cmd=oldhistory&group=";
12182 ref += enc_group_name;
12183 ref += "&panel=";
12184 ref += enc_panel_name;
12185
12186 std::string ref2;
12187 ref2 += "?cmd=oldhistory&group=";
12188 ref2 += enc_group_name;
12189 ref2 += "&panel=";
12190 ref2 += enc_panel_name;
12191
12192 if (endtime != 0) {
12193 char tmp[256];
12194 sprintf(tmp, "time=%s&scale=%d", time_to_string(endtime).c_str(), scale);
12195 ref += "&";
12196 ref += tmp;
12197 ref2 += "&";
12198 ref2 += tmp;
12199 }
12200
12201 if (k % 2 == 0)
12202 r->rsprintf("<tr><td><a href=\"%s\"><img src=\"%s\"></a>\n", ref2.c_str(), ref.c_str());
12203 else
12204 r->rsprintf("<td><a href=\"%s\"><img src=\"%s\"></a></tr>\n", ref2.c_str(), ref.c_str());
12205 } // items loop
12206 } // Groups loop
12207 } // All
12208 r->rsprintf("</table>\r\n");
12209 r->rsprintf("</div>\n"); // closing for <div id="mmain">
12210 r->rsprintf("</form>\n");
12211 r->rsprintf("</body></html>\r\n");
12212}
12213
12214
12215/*------------------------------------------------------------------*/
12216
12217void send_icon(Return* r, const char *icon)
12218{
12219 int length;
12220 const unsigned char *picon;
12221 char str[256], format[256];
12222 time_t now;
12223
12224 if (strstr(icon, "favicon.ico") != 0) {
12225 length = sizeof(favicon_ico);
12226 picon = favicon_ico;
12227 } else if (strstr(icon, "favicon.png") != 0) {
12228 length = sizeof(favicon_png);
12229 picon = favicon_png;
12230 } else
12231 return;
12232
12233 r->rsprintf("HTTP/1.1 200 Document follows\r\n");
12234 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12235 r->rsprintf("Accept-Ranges: bytes\r\n");
12236
12237 /* set expiration time to one day */
12238 time(&now);
12239 now += (int) (3600 * 24);
12240 struct tm gmt_tms;
12241 gmtime_r(&now, &gmt_tms);
12242 strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT");
12243 strftime(str, sizeof(str), format, &gmt_tms);
12244 r->rsprintf("Expires: %s\r\n", str);
12245
12246 if (equal_ustring(icon, "favicon.ico"))
12247 r->rsprintf("Content-Type: image/x-icon\r\n");
12248 else
12249 r->rsprintf("Content-Type: image/png\r\n");
12250
12251 r->rsprintf("Content-Length: %d\r\n\r\n", length);
12252
12253 r->rmemcpy(picon, length);
12254}
12255
12256/*------------------------------------------------------------------*/
12257
12259{
12260 std::string cookie_pwd;
12261 std::string cookie_wpwd;
12262 std::string cookie_cpwd;
12263 int refresh = 0;
12264 //int expand_equipment = 0;
12265};
12266
12267/*------------------------------------------------------------------*/
12268
12270{
12271 gMutex.lock();
12272 t->fTimeLocked = GetTimeSec();
12273}
12274
12276{
12278 gMutex.unlock();
12279}
12280
12281/*------------------------------------------------------------------*/
12282
12283void interprete(Param* p, Return* r, Attachment* a, const Cookies* c, const char *dec_path, RequestTrace* t)
12284/********************************************************************\
12285
12286 Routine: interprete
12287
12288 Purpose: Main interpreter of web commands
12289
12290 \********************************************************************/
12291{
12292 int status;
12293 HNDLE hkey, hDB;
12294
12295 //printf("dec_path [%s]\n", dec_path);
12296
12297 if (strstr(dec_path, "favicon.ico") != 0 ||
12298 strstr(dec_path, "favicon.png")) {
12299 send_icon(r, dec_path);
12300 return;
12301 }
12302
12303 const char* password = p->getparam("pwd");
12304 const char* wpassword = p->getparam("wpwd");
12305 const char* command = p->getparam("cmd");
12306
12307 //printf("interprete: dec_path [%s], command [%s]\n", dec_path, command);
12308
12310 MVOdb* odb = gOdb;
12311
12312 if (history_mode) {
12313 if (equal_ustring(command, "history")) {
12314 if (equal_ustring(command, "config")) {
12315 return;
12316 }
12317
12318 Lock(t);
12319 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12320 Unlock(t);
12321 return;
12322 }
12323 return;
12324 }
12325
12326 /* check for password */
12327 db_find_key(hDB, 0, "/Experiment/Security/Password", &hkey);
12328 if (!password[0] && hkey) {
12329 char str[256];
12330 int size = sizeof(str);
12331 db_get_data(hDB, hkey, str, &size, TID_STRING);
12332
12333 /* check for excemption */
12334 db_find_key(hDB, 0, "/Experiment/Security/Allowed programs/mhttpd", &hkey);
12335 if (hkey == 0 && strcmp(c->cookie_pwd.c_str(), str) != 0) {
12336 Lock(t);
12337 show_password_page(r, dec_path, "");
12338 Unlock(t);
12339 return;
12340 }
12341 }
12342
12343 /*---- redirect with cookie if password given --------------------*/
12344
12345 if (password[0]) {
12346 r->rsprintf("HTTP/1.1 302 Found\r\n");
12347 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12348
12349 time_t now;
12350 time(&now);
12351
12352 now += 3600 * 24;
12353
12354 struct tm gmt_tms;
12355 gmtime_r(&now, &gmt_tms);
12356
12357 char str[256];
12358 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12359
12360 r->rsprintf("Set-Cookie: midas_pwd=%s; path=/; expires=%s\r\n",
12361 ss_crypt(password, "mi"), str);
12362
12363 r->rsprintf("Location: ./\n\n<html>redir</html>\r\n");
12364 return;
12365 }
12366
12367 if (wpassword[0]) {
12368 /* check if password correct */
12369 if (!check_web_password(r, hDB, dec_path, ss_crypt(wpassword, "mi"), p->getparam("redir")))
12370 return;
12371
12372 r->rsprintf("HTTP/1.1 302 Found\r\n");
12373 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12374
12375 time_t now;
12376 time(&now);
12377
12378 now += 3600 * 24;
12379
12380 struct tm gmt_tms;
12381 gmtime_r(&now, &gmt_tms);
12382
12383 char str[256];
12384 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:%M:%S GMT", &gmt_tms);
12385
12386 r->rsprintf("Set-Cookie: midas_wpwd=%s; path=/; expires=%s\r\n", ss_crypt(wpassword, "mi"), str);
12387
12388 sprintf(str, "./%s", p->getparam("redir"));
12389 r->rsprintf("Location: %s\n\n<html>redir</html>\r\n", str);
12390 return;
12391 }
12392
12393 /*---- send sound file -------------------------------------------*/
12394
12395 if (strlen(dec_path) > 3 &&
12396 dec_path[strlen(dec_path)-3] == 'm' &&
12397 dec_path[strlen(dec_path)-2] == 'p' &&
12398 dec_path[strlen(dec_path)-1] == '3') {
12399 if (strrchr(dec_path, '/'))
12400 send_resource(r, strrchr(dec_path, '/')+1);
12401 else
12402 send_resource(r, dec_path);
12403 return;
12404 }
12405
12406 /*---- send midas.js and midas.css -------------------------------*/
12407
12408 if (strstr(dec_path, "midas.js")) {
12409 send_resource(r, "midas.js");
12410 return;
12411 }
12412
12413 if (strstr(dec_path, "midas.css")) {
12414 send_resource(r, "midas.css");
12415 return;
12416 }
12417
12418 /*---- send mhttpd.js --------------------------------------------*/
12419
12420 if (strstr(dec_path, "mhttpd.js")) {
12421 send_resource(r, "mhttpd.js");
12422 return;
12423 }
12424
12425 /*---- send obsolete.js ------------------------------------------*/
12426
12427 if (strstr(dec_path, "obsolete.js")) {
12428 send_resource(r, "obsolete.js");
12429 return;
12430 }
12431
12432 /*---- send the obsolete mhttpd.css ------------------------------*/
12433
12434 if (strstr(dec_path, "mhttpd.css")) {
12435 send_resource(r, "mhttpd.css");
12436 return;
12437 }
12438
12439 /*---- send controls.js ------------------------------------------*/
12440
12441 if (strstr(dec_path, "controls.js")) {
12442 send_resource(r, "controls.js");
12443 return;
12444 }
12445
12446 /*---- send example web page -------------------------------------*/
12447
12448 if (equal_ustring(command, "example")) {
12449 send_resource(r, "example.html");
12450 return;
12451 }
12452
12453 /*---- send example custom page -------------------------------------*/
12454
12455 if (equal_ustring(command, "custom_example")) {
12456 send_resource(r, "custom_example.html");
12457 return;
12458 }
12459
12460 if (equal_ustring(command, "plot_example")) {
12461 send_resource(r, "plot_example.html");
12462 return;
12463 }
12464
12465 /*---- script command --------------------------------------------*/
12466
12467 if (p->getparam("script") && *p->getparam("script")) {
12468
12469 std::string str = msprintf("%s?script=%s", dec_path, p->getparam("script"));
12470 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12471 return;
12472
12473 std::string path;
12474 path += "/Script/";
12475 path += p->getparam("script");
12476
12477 Lock(t);
12478
12479 cm_exec_script(path.c_str());
12480
12481 Unlock(t);
12482
12483 if (p->isparam("redir"))
12484 redirect2(r, p->getparam("redir"));
12485 else
12486 redirect2(r, "");
12487
12488 return;
12489 }
12490
12491 /*---- customscript command --------------------------------------*/
12492
12493 if (p->getparam("customscript") && *p->getparam("customscript")) {
12494
12495 std::string str = msprintf("%s?customscript=%s", dec_path, p->getparam("customscript"));
12496 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12497 return;
12498
12499 std::string path;
12500 path += "/CustomScript/";
12501 path += p->getparam("customscript");
12502
12503 Lock(t);
12504
12505 cm_exec_script(path.c_str());
12506
12507 Unlock(t);
12508
12509 if (p->isparam("redir"))
12510 redirect2(r, p->getparam("redir"));
12511 else
12512 redirect2(r, str.c_str());
12513
12514 return;
12515 }
12516
12517 /*---- send the new html pages -----------------------------------*/
12518
12519 if (equal_ustring(command, "start")) {
12520 send_resource(r, "start.html");
12521 return;
12522 }
12523
12524 if ((equal_ustring(command, "") || equal_ustring(command, "status")) && strlen(dec_path) == 0) {
12525 if (midas::odb::exists("/Custom/Status")) {
12526 midas::odb custom("/Custom");
12527
12528 std::string filename = custom["Status"];
12529 filename = add_custom_path(filename);
12530
12531 // if custom file exists, send it (like normal web server)
12532 if (ss_file_exist(filename.c_str())) {
12533 send_file(r, filename);
12534 return;
12535 }
12536 } else
12537 send_resource(r, "status.html");
12538 return;
12539 }
12540
12541 if (equal_ustring(command, "eqtable")) {
12542 send_resource(r, "eqtable.html");
12543 return;
12544 }
12545
12546 if (equal_ustring(command, "newODB")) {
12547 send_resource(r, "odb.html");
12548 return;
12549 }
12550
12551 if (equal_ustring(command, "programs")) {
12552 send_resource(r, "programs.html");
12553 return;
12554 }
12555
12556 if (equal_ustring(command, "alarms")) {
12557 send_resource(r, "alarms.html");
12558 return;
12559 }
12560
12561 if (equal_ustring(command, "transition")) {
12562 send_resource(r, "transition.html");
12563 return;
12564 }
12565
12566 if (equal_ustring(command, "messages")) {
12567 send_resource(r, "messages.html");
12568 return;
12569 }
12570
12571 if (equal_ustring(command, "config") &&
12572 !(dec_path[0] == 'H' && dec_path[1] == 'S' && dec_path[2] == '/')) {
12573 send_resource(r, "config.html");
12574 return;
12575 }
12576
12577 if (equal_ustring(command, "chat")) {
12578 send_resource(r, "chat.html");
12579 return;
12580 }
12581
12582 if (equal_ustring(command, "buffers")) {
12583 send_resource(r, "buffers.html");
12584 return;
12585 }
12586
12587 if (equal_ustring(command, "Show elog")) {
12588 send_resource(r, "elog_show.html");
12589 return;
12590 }
12591
12592 if (equal_ustring(command, "Query elog")) {
12593 send_resource(r, "elog_query_form.html");
12594 return;
12595 }
12596
12597 if (equal_ustring(command, "New elog")) {
12598 send_resource(r, "elog_edit.html");
12599 return;
12600 }
12601
12602 if (equal_ustring(command, "Edit elog")) {
12603 send_resource(r, "elog_edit.html");
12604 return;
12605 }
12606
12607 if (equal_ustring(command, "Reply Elog")) {
12608 send_resource(r, "elog_edit.html");
12609 return;
12610 }
12611
12612 if (equal_ustring(command, "Last elog")) {
12613 send_resource(r, "elog_show.html");
12614 return;
12615 }
12616
12617 if (equal_ustring(command, "Submit Query")) {
12618 send_resource(r, "elog_query.html");
12619 return;
12620 }
12621
12622 if (equal_ustring(dec_path, "spinning-wheel.gif")) {
12623 send_resource(r, "spinning-wheel.gif");
12624 return;
12625 }
12626
12627 /*---- java script commands --------------------------------------*/
12628
12629 if (equal_ustring(command, "jset") ||
12630 equal_ustring(command, "jget") ||
12631 equal_ustring(command, "jcopy") ||
12632 equal_ustring(command, "jpaste") ||
12633 equal_ustring(command, "jkey") ||
12634 equal_ustring(command, "jcreate") ||
12635 equal_ustring(command, "jresize") ||
12636 equal_ustring(command, "jlink") ||
12637 equal_ustring(command, "jrename") ||
12638 equal_ustring(command, "jreorder") ||
12639 equal_ustring(command, "jdelete") ||
12640 equal_ustring(command, "jmsg") ||
12641 equal_ustring(command, "jalm") ||
12642 equal_ustring(command, "jgenmsg") ||
12643 equal_ustring(command, "jrpc_rev0") ||
12644 equal_ustring(command, "jrpc_rev1") ||
12645 equal_ustring(command, "jrpc")) {
12646 Lock(t);
12647 javascript_commands(p, r, c->cookie_cpwd.c_str());
12648 Unlock(t);
12649 return;
12650 }
12651
12652 /*---- history editord -------------------------------------------*/
12653
12654 if (equal_ustring(command, "hs_edit")) {
12655 send_resource(r, "hs_edit.html");
12656 return;
12657 }
12658
12659 /*---- history command -------------------------------------------*/
12660
12661 if (equal_ustring(command, "oldhistory")) {
12662 Lock(t);
12663 show_hist_page(odb, p, r, dec_path, NULL, NULL, c->refresh);
12664 Unlock(t);
12665 return;
12666 }
12667
12668 if (equal_ustring(command, "history")) {
12669 send_resource(r, "history.html");
12670 return;
12671 }
12672
12673 /*---- MSCB command ----------------------------------------------*/
12674
12675 if (equal_ustring(command, "MSCB")) {
12676 if (equal_ustring(command, "set")) {
12677 std::string str;
12678 str += dec_path;
12679 str += "?";
12680 str += add_param_to_url("cmd", command);
12681 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str.c_str()))
12682 return;
12683 }
12684
12685 Lock(t);
12686
12687#ifdef HAVE_MSCB
12688 show_mscb_page(p, r, c->refresh);
12689#else
12690 show_error(r, "MSCB support not compiled into this version of mhttpd");
12691#endif
12692
12693 Unlock(t);
12694 return;
12695 }
12696
12697 /*---- help command ----------------------------------------------*/
12698
12699 if (equal_ustring(command, "help")) {
12700 Lock(t);
12701 show_help_page(r, dec_path);
12702 Unlock(t);
12703 return;
12704 }
12705
12706 /*---- trigger equipment readout ---------------------------*/
12707
12708 if (strncmp(command, "Trigger", 7) == 0) {
12709 std::string cmd;
12710 cmd += "?cmd=";
12711 cmd += command;
12712 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), cmd.c_str())) {
12713 return;
12714 }
12715
12716 Lock(t);
12717
12718 /* extract equipment name */
12719 char eq_name[NAME_LENGTH];
12720
12721 mstrlcpy(eq_name, command + 8, sizeof(eq_name));
12722 if (strchr(eq_name, ' '))
12723 *strchr(eq_name, ' ') = 0;
12724
12725 /* get frontend name */
12726 std::string path;
12727 path += "/Equipment/";
12728 path += eq_name;
12729 path += "/Common/Frontend name";
12730 char fe_name[NAME_LENGTH];
12731 int size = NAME_LENGTH;
12732 db_get_value(hDB, 0, path.c_str(), fe_name, &size, TID_STRING, TRUE);
12733
12734 /* and ID */
12735 path = "";
12736 path += "/Equipment/";
12737 path += eq_name;
12738 path += "/Common/Event ID";
12739 WORD event_id = 0;
12740 size = sizeof(event_id);
12741 db_get_value(hDB, 0, path.c_str(), &event_id, &size, TID_WORD, TRUE);
12742
12743 if (cm_exist(fe_name, FALSE) != CM_SUCCESS) {
12744 std::string str;
12745 str += "Frontend \"";
12746 str += fe_name;
12747 str += "\" not running!";
12748 show_error(r, str.c_str());
12749 } else {
12750 HNDLE hconn;
12751 status = cm_connect_client(fe_name, &hconn);
12752 if (status != RPC_SUCCESS) {
12753 std::string str;
12754 str += "Cannot connect to frontend \"";
12755 str += fe_name;
12756 str +="\" !";
12757 show_error(r, str.c_str());
12758 } else {
12760 if (status != CM_SUCCESS)
12761 show_error(r, "Error triggering event");
12762 else
12763 redirect(r, "");
12764
12765 //cm_disconnect_client(hconn, FALSE);
12766 }
12767 }
12768
12769 Unlock(t);
12770
12771 return;
12772 }
12773
12774 /*---- switch to next subrun -------------------------------------*/
12775
12776 if (strncmp(command, "Next Subrun", 11) == 0) {
12777 int i = TRUE;
12778 db_set_value(hDB, 0, "/Logger/Next subrun", &i, sizeof(i), 1, TID_BOOL);
12779 redirect(r, "");
12780 return;
12781 }
12782
12783 /*---- cancel command --------------------------------------------*/
12784
12785 if (equal_ustring(command, "cancel")) {
12786 if (p->isparam("redir"))
12787 redirect(r, p->getparam("redir"));
12788 else
12789 redirect(r, "");
12790 return;
12791 }
12792
12793 /*---- set command -----------------------------------------------*/
12794
12795 if (equal_ustring(command, "set")) {
12796 char str[256];
12797 mstrlcpy(str, "?cmd=set", sizeof(str));
12798 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), str))
12799 return;
12800
12801 const char* group = p->getparam("group");
12802 int index = atoi(p->getparam("index"));
12803 const char* value = p->getparam("value");
12804
12805 Lock(t);
12806 show_set_page(p, r, group, index, value);
12807 Unlock(t);
12808 return;
12809 }
12810
12811 /*---- find command ----------------------------------------------*/
12812
12813 if (equal_ustring(command, "find")) {
12814 const char* value = p->getparam("value");
12815 Lock(t);
12817 Unlock(t);
12818 return;
12819 }
12820
12821 /*---- CAMAC CNAF command ----------------------------------------*/
12822
12823 if (equal_ustring(command, "CNAF") || strncmp(dec_path, "CNAF", 4) == 0) {
12824 if (!check_web_password(r, hDB, dec_path, c->cookie_wpwd.c_str(), "?cmd=CNAF"))
12825 return;
12826
12827 Lock(t);
12828 show_cnaf_page(p, r);
12829 Unlock(t);
12830 return;
12831 }
12832
12833 /*---- ELog command ----------------------------------------------*/
12834
12835 if (equal_ustring(command, "elog")) {
12836 /* redirect to external ELOG if URL present */
12838 BOOL external_elog = FALSE;
12839 std::string external_elog_url;
12840 int size = sizeof(external_elog);
12841 status = db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, TRUE);
12842 status = db_get_value_string(hDB, 0, "/Elog/URL", 0, &external_elog_url, TRUE);
12843 if (external_elog && (external_elog_url.length() > 0)) {
12844 redirect(r, external_elog_url.c_str());
12845 return;
12846 }
12847 send_resource(r, "elog_show.html");
12848 return;
12849 }
12850
12851 // special processing for "Elog last 7d", etc
12852
12853 char cmdx[32];
12854 mstrlcpy(cmdx, command, sizeof(cmdx));
12855 cmdx[9] = 0;
12856
12857 if (equal_ustring(cmdx, "Elog last")) {
12858 // "Elog last 7d", etc
12859 send_resource(r, "elog_query.html");
12860 return;
12861 }
12862
12863 if (equal_ustring(command, "Create ELog from this page")) {
12864 std::string redir;
12865 redir += "?cmd=New+elog";
12866 redir += "&odb_path=";
12867 redir += p->getparam("odb_path");
12868 redirect(r, redir.c_str());
12869 return;
12870 }
12871
12872 if (equal_ustring(command, "Submit elog")) {
12873 Lock(t);
12874 submit_elog(odb, p, r, a);
12875 Unlock(t);
12876 return;
12877 }
12878
12879 if (equal_ustring(command, "elog_att")) {
12880 Lock(t);
12881 show_elog_attachment(p, r, dec_path);
12882 Unlock(t);
12883 return;
12884 }
12885
12886 /*---- accept command --------------------------------------------*/
12887
12888 if (equal_ustring(command, "accept")) {
12889 int refresh = atoi(p->getparam("refr"));
12890
12891 /* redirect with cookie */
12892 r->rsprintf("HTTP/1.1 302 Found\r\n");
12893 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
12894 r->rsprintf("Content-Type: text/html; charset=%s\r\n", HTTP_ENCODING);
12895
12896 time_t now;
12897 time(&now);
12898
12899 now += 3600 * 24 * 365;
12900
12901 struct tm gmt_tms;
12902 gmtime_r(&now, &gmt_tms);
12903
12904 char str[256];
12905 strftime(str, sizeof(str), "%A, %d-%b-%Y %H:00:00 GMT", &gmt_tms);
12906
12907 r->rsprintf("Set-Cookie: midas_refr=%d; path=/; expires=%s\r\n", refresh, str);
12908 r->rsprintf("Location: ./\r\n\r\n<html>redir</html>\r\n");
12909
12910 return;
12911 }
12912
12913#ifdef OBSOLETE
12914 /*---- slow control display --------------------------------------*/
12915
12916 if (equal_ustring(command, "eqtable")) {
12917 Lock(t);
12918 show_eqtable_page(p, r, c->refresh);
12919 Unlock(t);
12920 return;
12921 }
12922#endif
12923
12924 /*---- sequencer page --------------------------------------------*/
12925
12926 if (equal_ustring(command, "Sequencer")) {
12927 send_resource(r, "sequencer.html");
12928 return;
12929 }
12930
12931 // obsolete
12932 if (equal_ustring(command, "seq")) {
12933 send_resource(r, "sequencer.html");
12934 return;
12935 }
12936
12937 if (equal_ustring(command, "start_script")) {
12938 send_resource(r, "start_script.html");
12939 return;
12940 }
12941
12942 if (equal_ustring(command, "load_script")) {
12943 send_resource(r, "load_script.html");
12944 return;
12945 }
12946
12947 if (equal_ustring(command, "edit_script")) {
12948 send_resource(r, "edit_script.html");
12949 return;
12950 }
12951
12952 /*---- show ODB --------------------------------------------------*/
12953
12954 if (equal_ustring(command, "oldOdb")) {
12955 int write_access = TRUE;
12956 db_find_key(hDB, 0, "/Experiment/Security/Web Password", &hkey);
12957 if (hkey) {
12958 char str[256];
12959 int size = sizeof(str);
12960 db_get_data(hDB, hkey, str, &size, TID_STRING);
12961 if (strcmp(c->cookie_wpwd.c_str(), str) == 0)
12962 write_access = TRUE;
12963 else
12964 write_access = FALSE;
12965 }
12966
12967 std::string odb_path;
12968 if (p->getparam("odb_path") && *p->getparam("odb_path"))
12969 odb_path = p->getparam("odb_path");
12970
12971 Lock(t);
12972 show_odb_page(p, r, odb_path.c_str(), write_access);
12973 Unlock(t);
12974 return;
12975 }
12976
12977 /*---- New ODB browser --------------------------------------------*/
12978
12979 if (equal_ustring(command, "odb")) {
12980 send_resource(r, "odb.html");
12981 return;
12982 }
12983
12984 /*---- ODB show open records --------------------------------------*/
12985
12986 if (equal_ustring(command, "odb_sor")) {
12987 send_resource(r, "odb_sor.html");
12988 return;
12989 }
12990
12991 /*---- ODB show clients -------------------------------------------*/
12992
12993 if (equal_ustring(command, "odb_scl")) {
12994 send_resource(r, "odb_scl.html");
12995 return;
12996 }
12997
12998 /*---- old ODB path ----------------------------------------------*/
12999
13000 if ((command[0]==0) && dec_path[0]) {
13001 if (equal_ustring(dec_path, "root")) {
13002 std::string new_url = "./?cmd=odb";
13003 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13004 redirect_307(r, new_url.c_str());
13005 return;
13006 }
13007 }
13008
13009 if ((command[0]==0) && dec_path[0]) {
13010 HNDLE hkey;
13011 status = db_find_key(hDB, 0, dec_path, &hkey);
13012 //printf("try odb path [%s], status %d\n", dec_path, status);
13013 if (status == DB_SUCCESS) {
13014 int level = 0;
13015 for (const char* s = dec_path; *s; s++) {
13016 if (*s == '/')
13017 level++;
13018 }
13019 std::string new_url;
13020 if (level == 0) {
13021 // Top-level directory like /Logger, (which appears in dec_path as "Logger")
13022 new_url += "./";
13023 } else {
13024 for (int i=0; i<level; i++) {
13025 if (i>0)
13026 new_url += "/";
13027 new_url += "..";
13028 }
13029 }
13030 new_url += "?cmd=odb";
13031 new_url += "&odb_path=";
13032 new_url += urlEncode(dec_path);
13033 //printf("redirect old odb path url [%s] to [%s]\n", dec_path, new_url.c_str());
13034 redirect_307(r, new_url.c_str());
13035 return;
13036 }
13037 }
13038
13039 /*---- event dump ------------------------------------------------*/
13040
13041 if (equal_ustring(command, "event dump")) {
13042 send_resource(r, "event_dump.html");
13043 return;
13044 }
13045
13046 /*---- custom page -----------------------------------------------*/
13047
13048 if (equal_ustring(command, "custom")) {
13049 Lock(t);
13050 show_custom_page(p, r, c->cookie_cpwd.c_str());
13051 Unlock(t);
13052 return;
13053 }
13054
13055 /*---- custom page accessed by direct URL that used to be under /CS/... ----*/
13056
13057 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13058 std::string odb_path;
13059 std::string value;
13060 int status;
13061
13062 odb_path = "";
13063 odb_path += "/Custom/Images/";
13064 odb_path += dec_path;
13065 odb_path += "/Background";
13066
13067 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13068
13069 //printf("Try custom gif [%s] status %d\n", odb_path.c_str(), status);
13070
13071 if (status == DB_SUCCESS) {
13072 if (strstr(dec_path, "..")) {
13073 std::string str;
13074 str += "Invalid custom gif name \'";
13075 str += dec_path;
13076 str += "\' contains \'..\'";
13077 show_error_404(r, str.c_str());
13078 return;
13079 }
13080
13081 Lock(t);
13082 show_custom_gif(r, dec_path);
13083 Unlock(t);
13084 return;
13085 }
13086
13087 bool found_custom = false;
13088
13089 odb_path = "";
13090 odb_path += "/Custom/";
13091 odb_path += dec_path;
13092
13093 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13094
13095 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13096
13097 if (status == DB_SUCCESS) {
13098 found_custom = true;
13099 } else {
13100 odb_path = "";
13101 odb_path += "/Custom/";
13102 odb_path += dec_path;
13103 odb_path += "&";
13104
13105 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13106
13107 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13108
13109 if (status == DB_SUCCESS) {
13110 found_custom = true;
13111 } else {
13112 odb_path = "";
13113 odb_path += "/Custom/";
13114 odb_path += dec_path;
13115 odb_path += "!";
13116
13117 status = db_get_value_string(hDB, 0, odb_path.c_str(), 0, &value, FALSE);
13118
13119 //printf("Try [%s] status %d\n", odb_path.c_str(), status);
13120
13121 if (status == DB_SUCCESS) {
13122 found_custom = true;
13123 }
13124 }
13125 }
13126
13127 if (found_custom) {
13128 //printf("custom file: serving [%s] value [%s]\n", dec_path, value.c_str());
13129 if (strstr(dec_path, "..")) {
13130 std::string str;
13131 str += "Invalid custom page name \'";
13132 str += dec_path;
13133 str += "\' contains \'..\'";
13134 show_error_404(r, str.c_str());
13135 return;
13136 }
13137
13138 p->setparam("page", dec_path);
13139 Lock(t);
13140 show_custom_page(p, r, c->cookie_cpwd.c_str());
13141 Unlock(t);
13142 return;
13143 }
13144 }
13145
13146 /* new custom pages */
13147 if (db_find_key(hDB, 0, "/Custom", &hkey) == DB_SUCCESS && dec_path[0]) {
13148 std::string custom_path;
13149 status = db_get_value_string(hDB, 0, "/Custom/Path", 0, &custom_path, TRUE);
13150 if ((status == DB_SUCCESS) && (custom_path.length() > 0)) {
13151 if (strstr(dec_path, "..")) {
13152 std::string str;
13153 str += "Invalid custom file name \'";
13154 str += dec_path;
13155 str += "\' contains \'..\'";
13156 show_error_404(r, str.c_str());
13157 return;
13158 }
13159
13160 std::string full_filename = add_custom_path(dec_path);
13161
13162 // if custom file exists, send it (like normal web server)
13163 if (ss_file_exist(full_filename.c_str())) {
13164 send_file(r, full_filename);
13165 return;
13166 }
13167 }
13168 }
13169
13170 /*---- redirect if web page --------------------------------------*/
13171
13172 //if (strlen(command) > 0) {
13173 // if (send_resource(r, std::string(command) + ".html", false))
13174 // return;
13175 //}
13176
13177 /*---- serve url as a resource file ------------------------------*/
13178
13179 if (strlen(p->getparam("path")) > 0) {
13180 if (send_resource(r, p->getparam("path"), false)) {
13181 return;
13182 }
13183 }
13184
13185 /*---- show status -----------------------------------------------*/
13186
13187 if (elog_mode) {
13188 redirect(r, "EL/");
13189 return;
13190 }
13191
13192 /* header */
13193 r->rsprintf("HTTP/1.1 400 Bad Request\r\n");
13194 r->rsprintf("Server: MIDAS HTTP %s\r\n", mhttpd_revision());
13195 r->rsprintf("Content-Type: text/plain; charset=%s\r\n", HTTP_ENCODING);
13196 r->rsprintf("\r\n");
13197 r->rsprintf("Error: Invalid URL \"%s\" or query \"%s\" or command \"%s\"\n", p->getparam("path"), p->getparam("query"), command);
13198}
13199
13200/*------------------------------------------------------------------*/
13201
13202void decode_query(Param* pp, const char *query_string)
13203{
13204 int len = strlen(query_string);
13205 char *buf = (char *)malloc(len+1);
13206 assert(buf != NULL);
13207 memcpy(buf, query_string, len+1);
13208 char* p = buf;
13209 p = strtok(p, "&");
13210 while (p != NULL) {
13211 char *pitem = p;
13212 p = strchr(p, '=');
13213 if (p != NULL) {
13214 *p++ = 0;
13215 urlDecode(pitem); // parameter name
13216 if (!equal_ustring(pitem, "format"))
13217 urlDecode(p); // parameter value
13218
13219 pp->setparam(pitem, p); // decoded query parameters
13220
13221 p = strtok(NULL, "&");
13222 }
13223 }
13224 free(buf);
13225}
13226
13227void decode_get(Return* rr, char *string, const Cookies* c, const char* url, const char* query_string, RequestTrace* t)
13228{
13229 char path[256];
13230
13231 //printf("decode_get: string [%s], decode_url %d, url [%s], query_string [%s]\n", string, decode_url, url, query_string);
13232
13233 Param* param = new Param();
13234
13235 param->initparam();
13236
13237 if (url)
13238 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13239 else {
13240 mstrlcpy(path, string + 1, sizeof(path)); /* strip leading '/' */
13241
13242 if (strchr(path, '?'))
13243 *strchr(path, '?') = 0;
13244 }
13245
13246 param->setparam("path", path);
13247
13248 assert(query_string != NULL);
13249
13250 decode_query(param, query_string);
13251
13252 param->setparam("query", query_string);
13253
13254 char dec_path[256];
13255 mstrlcpy(dec_path, path, sizeof(dec_path));
13256
13257 interprete(param, rr, NULL, c, dec_path, t);
13258
13259 param->freeparam();
13260 delete param;
13261}
13262
13263/*------------------------------------------------------------------*/
13264
13265void decode_post(Return* rr, const char *header, const char *string, const char *boundary, int length, const Cookies* c, const char* url, RequestTrace* t)
13266{
13267 bool debug_decode_post = false;
13268
13269 Param* param = new Param;
13270
13271 param->initparam();
13272
13273 char path[256];
13274
13275 if (url)
13276 mstrlcpy(path, url + 1, sizeof(path)); /* strip leading '/' */
13277 else {
13278 mstrlcpy(path, header + 1, sizeof(path)); /* strip leading '/' */
13279 if (strchr(path, '?'))
13280 *strchr(path, '?') = 0;
13281 if (strchr(path, ' '))
13282 *strchr(path, ' ') = 0;
13283 }
13284 param->setparam("path", path); // undecoded path
13285
13286 Attachment* a = new Attachment;
13287
13288 const char* pinit = string;
13289
13290 /* return if no boundary defined */
13291 if (!boundary[0])
13292 return;
13293
13294 if (strstr(string, boundary))
13295 string = strstr(string, boundary) + strlen(boundary);
13296
13297 if (debug_decode_post)
13298 printf("decode_post: -->[%s]<--\n", string);
13299
13300 do {
13301 //printf("decode_post: [%s]\n", string);
13302 if (strstr(string, "name=")) {
13303 const char* pitem = strstr(string, "name=") + 5;
13304 if (*pitem == '\"')
13305 pitem++;
13306
13307 //printf("decode_post: pitem [%s]\n", pitem);
13308
13309 if (strncmp(pitem, "attfile", 7) == 0) {
13310 int n = pitem[7] - '1';
13311
13312 char file_name[256];
13313 file_name[0] = 0;
13314
13315 /* evaluate file attachment */
13316 if (strstr(pitem, "filename=")) {
13317 const char* p = strstr(pitem, "filename=") + 9;
13318 if (*p == '\"')
13319 p++;
13320 if (strstr(p, "\r\n\r\n"))
13321 string = strstr(p, "\r\n\r\n") + 4;
13322 else if (strstr(p, "\r\r\n\r\r\n"))
13323 string = strstr(p, "\r\r\n\r\r\n") + 6;
13324
13325 mstrlcpy(file_name, p, sizeof(file_name));
13326
13327 char* pp = file_name;
13328 if (strchr(pp, '\"'))
13329 *strchr(pp, '\"') = 0;
13330
13331 /* set attachment filename */
13332 char str[256];
13333 sprintf(str, "attachment%d", n);
13334 if (debug_decode_post)
13335 printf("decode_post: [%s] = [%s]\n", str, file_name);
13336 param->setparam(str, file_name); // file_name should be decoded?
13337 }
13338
13339 /* find next boundary */
13340 const char* ptmp = string;
13341 const char* p = NULL;
13342 do {
13343 while (*ptmp != '-')
13344 ptmp++;
13345
13346 p = strstr(ptmp, boundary);
13347 if (p != NULL) {
13348 while (*p == '-')
13349 p--;
13350 if (*p == 10)
13351 p--;
13352 if (*p == 13)
13353 p--;
13354 p++;
13355 break;
13356 } else
13357 ptmp += strlen(ptmp);
13358
13359 } while (TRUE);
13360
13361 /* save pointer to file */
13362 if (file_name[0]) {
13363 size_t size = (POINTER_T) p - (POINTER_T) string;
13364 char* buf = (char*)malloc(size+1);
13365 if (!buf) {
13366 return;
13367 }
13368 memcpy(buf, string, size);
13369 buf[size] = 0; // make sure string is NUL terminated
13370 a->attachment_buffer[n] = buf;
13371 a->attachment_size[n] = size;
13372 if (debug_decode_post)
13373 printf("decode_post: attachment[%d] size %d data --->[%s]<---\n", n, (int)a->attachment_size[n], a->attachment_buffer[n]);
13374 }
13375
13376 string = strstr(p, boundary) + strlen(boundary);
13377 } else {
13378 const char* p = pitem;
13379 if (strstr(p, "\r\n\r\n"))
13380 p = strstr(p, "\r\n\r\n") + 4;
13381 else if (strstr(p, "\r\r\n\r\r\n"))
13382 p = strstr(p, "\r\r\n\r\r\n") + 6;
13383
13384 char* ppitem = (char*)strchr(pitem, '\"'); // NB: defeat "const char* string"
13385 if (ppitem)
13386 *ppitem = 0;
13387
13388 char* pb = (char*)(strstr(p, boundary)); // NB: defeat "const char* string"
13389 if (pb) {
13390 string = pb + strlen(boundary);
13391 *pb = 0;
13392 char* ptmp = (char*)(p + (strlen(p) - 1)); // NB: defeat "const char* string"
13393 while (*ptmp == '-' || *ptmp == '\n' || *ptmp == '\r')
13394 *ptmp-- = 0;
13395 } else {
13396 show_error(rr, "Invalid POST request");
13397 return;
13398 }
13399 if (debug_decode_post)
13400 printf("decode_post: [%s] = [%s]\n", pitem, p);
13401 param->setparam(pitem, p); // in decode_post()
13402 }
13403
13404 while (*string == '-' || *string == '\n' || *string == '\r')
13405 string++;
13406 }
13407
13408 } while ((POINTER_T) string - (POINTER_T) pinit < length);
13409
13410 char dec_path[256];
13411 mstrlcpy(dec_path, path, sizeof(dec_path));
13412
13413 interprete(param, rr, a, c, dec_path, t);
13414
13415 delete a;
13416 delete param;
13417}
13418
13419/*------------------------------------------------------------------*/
13420
13422{
13423 HNDLE hDB, hKeyEq, hKey;
13424 RUNINFO_STR(runinfo_str);
13425 int i, status;
13426 KEY key;
13427
13428 /* check /Runinfo structure */
13430 assert(status == DB_SUCCESS);
13431
13432 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), FALSE);
13433 if (status == DB_STRUCT_MISMATCH) {
13434 status = db_check_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str(), TRUE);
13435 if (status == DB_SUCCESS) {
13436 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo corrected successfully");
13437 } else {
13438 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13439 return 0;
13440 }
13441 } else if (status == DB_NO_KEY) {
13442 cm_msg(MERROR, "check_odb_records", "ODB subtree /Runinfo does not exist");
13443 status = db_create_record(hDB, 0, "/Runinfo", strcomb1(runinfo_str).c_str());
13444 if (status == DB_SUCCESS) {
13445 cm_msg(MINFO, "check_odb_records", "ODB subtree /Runinfo created successfully");
13446 } else {
13447 cm_msg(MERROR, "check_odb_records", "Cannot create ODB subtree /Runinfo, db_create_record() status %d", status);
13448 return 0;
13449 }
13450 } else if (status != DB_SUCCESS) {
13451 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Runinfo, db_check_record() status %d", status);
13452 return 0;
13453 }
13454
13455 /* check /Equipment/<name>/Common structures */
13456 if (db_find_key(hDB, 0, "/equipment", &hKeyEq) == DB_SUCCESS) {
13457 for (i = 0 ;; i++) {
13458 db_enum_key(hDB, hKeyEq, i, &hKey);
13459 if (!hKey)
13460 break;
13461 db_get_key(hDB, hKey, &key);
13462
13464 if (status == DB_STRUCT_MISMATCH) {
13466 if (status == DB_SUCCESS) {
13467 cm_msg(MINFO, "check_odb_records", "ODB subtree /Equipment/%s/Common corrected successfully", key.name);
13468 } else {
13469 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13470 }
13471 } else if (status != DB_SUCCESS) {
13472 cm_msg(MERROR, "check_odb_records", "Cannot correct ODB subtree /Equipment/%s/Common, db_check_record() status %d", key.name, status);
13473 }
13474 }
13475 }
13476
13477 return CM_SUCCESS;
13478}
13479
13480
13481/*------------------------------------------------------------------*/
13482
13483std::atomic_bool _abort{false};
13484
13485void ctrlc_handler(int sig)
13486{
13487 _abort = true;
13488}
13489
13490/*------------------------------------------------------------------*/
13491
13492#ifdef HAVE_MONGOOSE6
13493static std::vector<std::string> gUserAllowedHosts;
13494#endif
13495static std::vector<std::string> gAllowedHosts;
13496#ifdef HAVE_MONGOOSE6
13497static const std::string gOdbAllowedHosts = "/Experiment/Security/mhttpd hosts/Allowed hosts";
13498#endif
13499
13500#ifdef HAVE_MONGOOSE6
13501static void load_allowed_hosts(HNDLE hDB, HNDLE hKey, int index, void* info)
13502{
13503 if (hKey != 0)
13504 cm_msg(MINFO, "load_allowed_hosts", "Reloading mhttpd hosts access control list via hotlink callback");
13505
13506 gAllowedHosts.clear();
13507
13508 // copy the user allowed hosts
13509 for (unsigned int i=0; i<gUserAllowedHosts.size(); i++)
13510 gAllowedHosts.push_back(gUserAllowedHosts[i]);
13511
13512 int total = 0;
13513 int last = 0;
13514 for (int i=0; ; i++) {
13515 std::string s;
13516 int status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), i, &s, FALSE);
13517 //printf("get %d, status %d, string [%s]\n", i, status, s.c_str());
13518 if (status != DB_SUCCESS) {
13519 total = i;
13520 break;
13521 }
13522
13523 if (s.length() < 1) // skip emties
13524 continue;
13525
13526 if (s[0] == '#') // skip commented-out entries
13527 continue;
13528
13529 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
13530 gAllowedHosts.push_back(s);
13531 last = i;
13532 }
13533
13534 //printf("total %d, last %d\n", total, last);
13535
13536 if (total - last < 5) {
13537 int new_size = last + 10;
13538 //printf("new size %d\n", new_size);
13539 int status = db_resize_string(hDB, 0, gOdbAllowedHosts.c_str(), new_size, 256);
13540 if (status != DB_SUCCESS) {
13541 cm_msg(MERROR, "load_allowed_hosts", "Cannot resize the allowed hosts access control list, db_resize_string(%d) status %d", new_size, status);
13542 }
13543 }
13544}
13545
13546static int init_allowed_hosts()
13547{
13548 HNDLE hDB;
13549 HNDLE hKey;
13550 int status;
13551
13553
13554 // create "allowed hosts" so we can watch it
13555
13556 std::string s;
13557 status = db_get_value_string(hDB, 0, gOdbAllowedHosts.c_str(), 0, &s, TRUE);
13558
13559 if (status != DB_SUCCESS) {
13560 cm_msg(MERROR, "init_allowed_hosts", "Cannot create the mhttpd hosts access control list, db_get_value_string() status %d", status);
13561 return status;
13562 }
13563
13564 status = db_find_key(hDB, 0, gOdbAllowedHosts.c_str(), &hKey);
13565
13566 if (status != DB_SUCCESS || hKey == 0) {
13567 cm_msg(MERROR, "init_allowed_hosts", "Cannot find the mhttpd hosts access control list, db_find_key() status %d", status);
13568 return status;
13569 }
13570
13571 load_allowed_hosts(hDB, 0, 0, NULL);
13572
13573 status = db_watch(hDB, hKey, load_allowed_hosts, NULL);
13574
13575 if (status != DB_SUCCESS) {
13576 cm_msg(MERROR, "init_allowed_hosts", "Cannot watch the mhttpd hosts access control list, db_watch() status %d", status);
13577 return status;
13578 }
13579
13580 return SUCCESS;
13581}
13582
13583 int check_midas_acl(const struct sockaddr *sa, int len) {
13584 // access control list is empty?
13585 if (gAllowedHosts.size() == 0)
13586 return 1;
13587
13588 char hname[NI_MAXHOST];
13589 hname[0] = 0;
13590
13591 int status;
13592 const char* status_string = "success";
13593
13594 status = getnameinfo(sa, len, hname, sizeof(hname), NULL, 0, 0);
13595
13596 if (status)
13597 status_string = gai_strerror(status);
13598
13599 //printf("connection from [%s], status %d (%s)\n", hname, status, status_string);
13600
13601 if (status != 0) {
13602 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, status, status_string);
13603 return 0;
13604 }
13605
13606 /* always permit localhost */
13607 if (strcmp(hname, "localhost.localdomain") == 0)
13608 return 1;
13609 if (strcmp(hname, "localhost") == 0)
13610 return 1;
13611
13612 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++)
13613 if (gAllowedHosts[i] == hname) {
13614 return 1;
13615 }
13616
13617 printf("Rejecting connection from \'%s\'\n", hname);
13618 return 0;
13619 }
13620
13621int open_listening_socket(int port)
13622{
13623 int status;
13624 struct sockaddr_in bind_addr;
13625
13626 /* create a new socket */
13627 int lsock = socket(AF_INET, SOCK_STREAM, 0);
13628
13629 if (lsock == -1) {
13630 printf("Cannot create socket, socket() errno %d (%s)\n", errno, strerror(errno));
13631 return -1;
13632 }
13633
13634 /* bind local node name and port to socket */
13635 memset(&bind_addr, 0, sizeof(bind_addr));
13636 bind_addr.sin_family = AF_INET;
13637 bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
13638 bind_addr.sin_port = htons((short) port);
13639
13640 /* try reusing address */
13641 int flag = 1;
13642 status = setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT));
13643
13644 if (status < 0) {
13645 printf("Cannot setsockopt(SOL_SOCKET, SO_REUSEADDR), errno %d (%s)\n", errno, strerror(errno));
13646 return -1;
13647 }
13648
13649 status = bind(lsock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
13650
13651 if (status < 0) {
13652 printf("Cannot bind() to port %d, bind() errno %d (%s)\n", port, errno, strerror(errno));
13653 return -1;
13654 }
13655
13656 /* listen for connection */
13657 status = listen(lsock, SOMAXCONN);
13658 if (status < 0) {
13659 printf("Cannot listen() on port %d, errno %d (%s), bye!\n", port, errno, strerror(errno));
13660 return -1;
13661 }
13662
13663 printf("mhttpd is listening on port %d\n", port);
13664
13665 return lsock;
13666}
13667#endif
13668
13669/*------------------------------------------------------------------*/
13670
13671int try_file_mg(const char* try_dir, const char* filename, std::string& path, FILE** fpp, bool trace)
13672{
13673 if (fpp)
13674 *fpp = NULL;
13675 if (!try_dir)
13676 return SS_FILE_ERROR;
13677 if (strlen(try_dir) < 1)
13678 return SS_FILE_ERROR;
13679
13680 path = try_dir;
13681 if (path[path.length()-1] != DIR_SEPARATOR)
13682 path += DIR_SEPARATOR_STR;
13683 path += filename;
13684
13685 FILE* fp = fopen(path.c_str(), "r");
13686
13687 if (trace) {
13688 if (fp)
13689 printf("file \"%s\": OK!\n", path.c_str());
13690 else
13691 printf("file \"%s\": not found.\n", path.c_str());
13692 }
13693
13694 if (!fp)
13695 return SS_FILE_ERROR;
13696 else if (fpp)
13697 *fpp = fp;
13698 else
13699 fclose(fp);
13700
13701 return SUCCESS;
13702}
13703
13704int find_file_mg(const char* filename, std::string& path, FILE** fpp, bool trace)
13705{
13706 std::string exptdir = cm_get_path();
13707
13708 if (try_file_mg(".", filename, path, fpp, trace) == SUCCESS)
13709 return SUCCESS;
13710
13711 if (try_file_mg(getenv("MIDAS_DIR"), filename, path, fpp, trace) == SUCCESS)
13712 return SUCCESS;
13713
13714 if (try_file_mg(exptdir.c_str(), filename, path, fpp, trace) == SUCCESS)
13715 return SUCCESS;
13716
13717 if (try_file_mg(getenv("MIDASSYS"), filename, path, fpp, trace) == SUCCESS)
13718 return SUCCESS;
13719
13720 // setup default filename
13721 try_file_mg(exptdir.c_str(), filename, path, NULL, false);
13722 return SS_FILE_ERROR;
13723}
13724
13725#ifdef HAVE_MONGOOSE6
13726#include "mongoose6.h"
13727#endif
13728
13729#ifdef HAVE_MONGOOSE616
13730#undef closesocket
13731#include "mongoose616.h"
13732// cs_md5() in not in mongoose.h
13733extern void cs_md5(char buf[33], ...);
13734#endif
13735
13736static bool verbose_mg = false;
13737static bool trace_mg = false;
13738static bool trace_mg_recv = false;
13739static bool trace_mg_send = false;
13740static bool trace_mg_verbose = false;
13741#ifdef HAVE_MONGOOSE616
13742static bool multithread_mg = true;
13743#endif
13744
13745#ifdef HAVE_MONGOOSE6
13746static struct mg_mgr mgr_mg;
13747#endif
13748
13750 std::string username;
13751 std::string realm;
13752 std::string password;
13753};
13754
13755class Auth {
13756public:
13757 std::string realm;
13758 std::string passwd_filename;
13759 std::vector<AuthEntry> passwords;
13760public:
13761 int Init();
13762};
13763
13764static bool read_passwords(Auth* auth);
13765
13767{
13768 std::string exptname = cm_get_experiment_name();
13769
13770 if (!exptname.empty())
13771 realm = exptname;
13772 else
13773 realm = "midas";
13774
13775 bool ok = read_passwords(this);
13776 if (!ok) {
13777 cm_msg(MERROR, "mongoose", "mongoose web server password file \"%s\" has no passwords for realm \"%s\"", passwd_filename.c_str(), realm.c_str());
13778 cm_msg(MERROR, "mongoose", "please add passwords by running: htdigest %s %s midas", passwd_filename.c_str(), realm.c_str());
13779 return SS_FILE_ERROR;
13780 }
13781
13782 return SUCCESS;
13783}
13784
13785static Auth *gAuthMg = NULL;
13786
13787static void xmg_mkmd5resp(const char *method, size_t method_len, const char *uri,
13788 size_t uri_len, const char *ha1, size_t ha1_len,
13789 const char *nonce, size_t nonce_len, const char *nc,
13790 size_t nc_len, const char *cnonce, size_t cnonce_len,
13791 const char *qop, size_t qop_len, char *resp) {
13792 static const char colon[] = ":";
13793 static const size_t one = 1;
13794 char ha2[33];
13795
13796 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
13797 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
13798 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
13799 colon, one, ha2, sizeof(ha2) - 1, NULL);
13800}
13801
13802/*
13803 * Check for authentication timeout.
13804 * Clients send time stamp encoded in nonce. Make sure it is not too old,
13805 * to prevent replay attacks.
13806 * Assumption: nonce is a hexadecimal number of seconds since 1970.
13807 */
13808static int xmg_check_nonce(const char *nonce) {
13809 unsigned long now = (unsigned long) time(NULL);
13810 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
13811 return now < val || now - val < 3600;
13812}
13813
13814/*
13815 * Authenticate HTTP request against opened passwords file.
13816 * Returns 1 if authenticated, 0 otherwise.
13817 */
13818
13820 const char *domain) {
13821 mg_printf(c,
13822 "HTTP/1.1 401 Unauthorized\r\n"
13823 "WWW-Authenticate: Digest qop=\"auth\", "
13824 "realm=\"%s\", nonce=\"%lu\"\r\n"
13825 "Content-Length: 0\r\n\r\n",
13826 domain, (unsigned long) time(NULL));
13827}
13828
13829static bool read_passwords(Auth* auth)
13830{
13831 std::string path;
13832 FILE *fp;
13833 int status = find_file_mg("htpasswd.txt", path, &fp, trace_mg||verbose_mg);
13834
13835 auth->passwd_filename = path;
13836 auth->passwords.clear();
13837
13838 if (status != SUCCESS || fp == NULL) {
13839 cm_msg(MERROR, "mongoose", "mongoose web server cannot find password file \"%s\"", path.c_str());
13840 cm_msg(MERROR, "mongoose", "please create password file: touch %s", path.c_str());
13841 return false;
13842 }
13843
13844 bool have_realm = false;
13845 char buf[256];
13846
13847 /*
13848 * Read passwords file line by line. If should have htdigest format,
13849 * i.e. each line should be a colon-separated sequence:
13850 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
13851 */
13852 while (fgets(buf, sizeof(buf), fp) != NULL) {
13853 char f_user[256];
13854 char f_domain[256];
13855 char f_ha1[256];
13856
13857 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3) {
13858 AuthEntry e;
13859 e.realm = f_domain;
13860 e.username = f_user;
13861 e.password = f_ha1;
13862
13863 if (e.realm == auth->realm) {
13864 have_realm = true;
13865 auth->passwords.push_back(e);
13866 }
13867 }
13868 }
13869
13870 fclose(fp);
13871
13872 return have_realm;
13873}
13874
13875#ifdef HAVE_MONGOOSE6
13876std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13877{
13878 assert(!"this code is untested!");
13879
13880 char* buf = NULL;
13881 int buf_size = 0;
13882
13883 while (1) {
13884 if (buf_size == 0) {
13885 buf_size = 256;
13886 buf = (char*)malloc(buf_size);
13887 assert(buf != NULL);
13888 }
13889
13890 int size = mg_http_parse_header(hdr, var_name, buf, buf_size);
13891
13892 if (size <= 0) {
13893 free(buf);
13894 return "";
13895 }
13896
13897 if (size < buf_size) {
13898 std::string s = buf;
13899 free(buf);
13900 return s;
13901 }
13902
13903 buf_size = buf_size*2 + 16;
13904 buf = (char*)realloc(buf, buf_size);
13905 assert(buf != NULL);
13906 }
13907}
13908#endif
13909
13910#ifdef HAVE_MONGOOSE616
13911std::string find_var_mg(struct mg_str *hdr, const char* var_name)
13912{
13913 char* buf = NULL;
13914 int buf_size = 0;
13915 int size = mg_http_parse_header2(hdr, var_name, &buf, buf_size);
13916 if (size <= 0)
13917 return "";
13918 assert(buf != NULL);
13919 std::string s = buf;
13920 free(buf);
13921 return s;
13922}
13923#endif
13924
13925static std::string check_digest_auth(struct http_message *hm, Auth* auth)
13926{
13927 char expected_response[33];
13928
13929 //printf("HereA!\n");
13930
13931 /* Parse "Authorization:" header, fail fast on parse error */
13932 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
13933
13934 if (!hdr)
13935 return "";
13936
13937 //printf("HereB!\n");
13938
13939 std::string user = find_var_mg(hdr, "username");
13940 std::string cnonce = find_var_mg(hdr, "cnonce");
13941 std::string response = find_var_mg(hdr, "response");
13942 std::string uri = find_var_mg(hdr, "uri");
13943 std::string qop = find_var_mg(hdr, "qop");
13944 std::string nc = find_var_mg(hdr, "nc");
13945 std::string nonce = find_var_mg(hdr, "nonce");
13946
13947 if (user.length()<1) return "";
13948 if (cnonce.length()<1) return "";
13949 if (response.length()<1) return "";
13950 if (uri.length()<1) return "";
13951 if (qop.length()<1) return "";
13952 if (nc.length()<1) return "";
13953 if (nonce.length()<1) return "";
13954
13955 if (xmg_check_nonce(nonce.c_str()) == 0) return "";
13956 //printf("HereB8!\n");
13957
13958 //printf("HereC!\n");
13959
13960 const char* uri_end = strchr(hm->uri.p, ' ');
13961 if (!uri_end) return "";
13962
13963 size_t uri_length = uri_end - hm->uri.p;
13964
13965 if (uri_length != uri.length())
13966 return "";
13967
13968 int cmp = strncmp(hm->uri.p, uri.c_str(), uri_length);
13969
13970 //printf("check URI: message %d %d [%d] authorization [%s]\n", (int)hm->uri.len, uri_length, cmp, uri);
13971
13972 if (cmp != 0)
13973 return "";
13974
13975 for (unsigned i=0; i<auth->passwords.size(); i++) {
13976 AuthEntry* e = &auth->passwords[i];
13977 if (e->username != user)
13978 continue;
13979 if (e->realm != auth->realm)
13980 continue;
13981 const char* f_ha1 = e->password.c_str();
13982 int uri_len = hm->uri.len;
13983 if (hm->uri.p[uri_len] == '?')
13984 uri_len += hm->query_string.len + 1; // "+1" accounts for the "?" character
13985 xmg_mkmd5resp(hm->method.p, hm->method.len,
13986 hm->uri.p, uri_len,
13987 f_ha1, strlen(f_ha1),
13988 nonce.c_str(), nonce.length(),
13989 nc.c_str(), nc.length(),
13990 cnonce.c_str(), cnonce.length(),
13991 qop.c_str(), qop.length(),
13992 expected_response);
13993 int cmp = strcasecmp(response.c_str(), expected_response);
13994 //printf("digest_auth: expected %s, got %s, cmp %d\n", expected_response, response.c_str(), cmp);
13995 if (cmp == 0) {
13996 return e->username;
13997 }
13998 }
13999
14000 return "";
14001}
14002
14003#ifdef HAVE_MONGOOSE616
14004
14005struct HostlistCacheEntry
14006{
14007 time_t time_created = 0;
14008 time_t time_last_used = 0;
14009 int count_used = 0;
14010 bool ipv4 = false;
14011 bool ipv6 = false;
14012 uint32_t ipv4addr = 0;
14013 struct in6_addr ipv6addr;
14014 std::string hostname;
14015 int gai_status = 0;
14016 std::string gai_strerror;
14017 bool ok = false;
14018};
14019
14020static std::vector<HostlistCacheEntry*> gHostlistCache;
14021
14022static void print_hostlist_cache()
14023{
14024 time_t now = time(NULL);
14025
14026 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14027 HostlistCacheEntry* e = gHostlistCache[i];
14028 if (!e) {
14029 // empty slot
14030 continue;
14031 }
14032
14033 printf("%3d: %s \"%s\", ok %d, count_used %d, age created: %d, last_used %d",
14034 i,
14035 e->ipv4?"IPv4":(e->ipv6?"IPv6":"????"),
14036 e->hostname.c_str(),
14037 e->ok,
14038 e->count_used,
14039 (int)(now - e->time_created),
14040 (int)(now - e->time_last_used));
14041
14042 if (e->gai_status) {
14043 printf(", getnameinfo() status %d (%s)", e->gai_status, e->gai_strerror.c_str());
14044 }
14045
14046 printf("\n");
14047 }
14048}
14049
14050static bool mongoose_check_hostlist(const union socket_address *sa)
14051{
14052 time_t now = time(NULL);
14053 bool ipv4 = false;
14054 bool ipv6 = false;
14055 uint32_t ipv4addr = 0;
14056 struct in6_addr ipv6addr;
14057
14058 if (sa->sa.sa_family == AF_INET) {
14059 ipv4 = true;
14060 ipv4addr = sa->sin.sin_addr.s_addr;
14061 } else if (sa->sa.sa_family == AF_INET6) {
14062 ipv6 = true;
14063 memcpy(&ipv6addr, &sa->sin6.sin6_addr, sizeof(ipv6addr));
14064 } else {
14065 printf("Rejecting connection from unknown address family %d (AF_xxx)\n", sa->sa.sa_family);
14066 return false;
14067 }
14068
14069 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14070 HostlistCacheEntry* e = gHostlistCache[i];
14071 if (!e) {
14072 // empty slot
14073 continue;
14074 }
14075
14076 if ((ipv4 == e->ipv4) && (ipv4addr == e->ipv4addr)) {
14077 // IPv4 address match
14078 e->time_last_used = now;
14079 e->count_used++;
14080 return e->ok;
14081 }
14082
14083 if ((ipv6 == e->ipv6) && (memcmp(&ipv6addr, &e->ipv6addr, sizeof(ipv6addr)) == 0)) {
14084 // IPv6 address match
14085 e->time_last_used = now;
14086 e->count_used++;
14087 return e->ok;
14088 }
14089
14090 // not this one. maybe expire old entries?
14091
14092 if (e->time_last_used < now - 24*60*60) {
14093 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);
14094 gHostlistCache[i] = NULL;
14095 delete e;
14096 }
14097 }
14098
14099 // not found in cache
14100
14101 assert(ipv4 || ipv6);
14102
14103 HostlistCacheEntry* e = new HostlistCacheEntry;
14104
14105 bool found = false;
14106 for (unsigned i=0; i<gHostlistCache.size(); i++) {
14107 if (gHostlistCache[i] == NULL) {
14108 gHostlistCache[i] = e;
14109 found = true;
14110 }
14111 }
14112 if (!found) {
14113 gHostlistCache.push_back(e);
14114 }
14115
14116 e->time_created = now;
14117 e->time_last_used = now;
14118 e->count_used = 1;
14119 e->ipv4 = ipv4;
14120 e->ipv6 = ipv6;
14121 if (ipv4)
14122 e->ipv4addr = ipv4addr;
14123 if (ipv6)
14124 memcpy(&e->ipv6addr, &ipv6addr, sizeof(ipv6addr));
14125 e->ok = false;
14126
14127 char hname[NI_MAXHOST];
14128 hname[0] = 0;
14129
14130 e->gai_status = getnameinfo(&sa->sa, sizeof(*sa), hname, sizeof(hname), NULL, 0, 0);
14131
14132 if (e->gai_status) {
14133 e->gai_strerror = gai_strerror(e->gai_status);
14134
14135 printf("Rejecting connection from \'%s\', getnameinfo() status %d (%s)\n", hname, e->gai_status, e->gai_strerror.c_str());
14136
14137 e->ok = false;
14138 return e->ok;
14139 }
14140
14141 printf("connection from \"%s\"\n", hname);
14142
14143 e->hostname = hname;
14144
14145 /* always permit localhost */
14146 if (e->hostname == "localhost.localdomain")
14147 e->ok = true;
14148 else if (e->hostname == "localhost")
14149 e->ok = true;
14150 else {
14151 for (unsigned int i=0 ; i<gAllowedHosts.size() ; i++) {
14152 if (e->hostname == gAllowedHosts[i]) {
14153 e->ok = true;
14154 }
14155 }
14156 }
14157
14158 if (!e->ok) {
14159 printf("Rejecting connection from \'%s\'\n", hname);
14160 }
14161
14162 print_hostlist_cache();
14163
14164 return e->ok;
14165}
14166
14167#endif
14168
14169static std::string mgstr(const mg_str* s)
14170{
14171 return std::string(s->p, s->len);
14172}
14173
14174static const std::string find_header_mg(const struct http_message *msg, const char* name)
14175{
14176 size_t nlen = strlen(name);
14177 for (int i=0; i<MG_MAX_HTTP_HEADERS; i++) {
14178 if (msg->header_names[i].len != nlen)
14179 continue;
14180 if (strncmp(msg->header_names[i].p, name, nlen) != 0)
14181 continue;
14182 return mgstr(&msg->header_values[i]);
14183 }
14184 return "";
14185}
14186
14187static const std::string find_cookie_mg(const struct http_message *msg, const char* cookie_name)
14188{
14189 const std::string cookies = find_header_mg(msg, "Cookie");
14190 if (cookies.length() < 1)
14191 return "";
14192 const char* p = strstr(cookies.c_str(), cookie_name);
14193 if (!p)
14194 return "";
14195 const char* v = p+strlen(cookie_name);
14196 if (*v != '=')
14197 return "";
14198 v++;
14199 //printf("cookie [%s] value [%s]\n", cookie_name, v);
14200 return v;
14201}
14202
14203// Generic event handler
14204
14205static void handle_event_mg(struct mg_connection *nc, int ev, void *ev_data)
14206{
14207 struct mbuf *io = &nc->recv_mbuf;
14208 switch (ev) {
14209 case MG_EV_POLL: // periodic call from loop_mg() via mg_mgr_poll()
14210 break;
14211 case MG_EV_ACCEPT:
14212 if (trace_mg)
14213 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> accept\n", nc, ev, ev_data);
14214 break;
14215 case MG_EV_RECV:
14216 if (trace_mg)
14217 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);
14218#if 0
14219 // This event handler implements simple TCP echo server
14220 mg_send(nc, io->buf, io->len); // Echo received data back
14221 mbuf_remove(io, io->len); // Discard data from recv buffer
14222#endif
14223 break;
14224 case MG_EV_SEND:
14225 if (trace_mg)
14226 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> send %d bytes\n", nc, ev, ev_data, *(int*)ev_data);
14227 break;
14228 case MG_EV_CLOSE:
14229 if (trace_mg)
14230 printf("handle_event_mg: nc %p, ev %d, ev_data %p -> close\n", nc, ev, ev_data);
14231 break;
14232 default:
14233 if (trace_mg)
14234 printf("handle_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
14235 break;
14236 }
14237}
14238
14240{
14241 // extract password cookies
14242
14243 char cookie_pwd[256]; // general access password
14244 char cookie_wpwd[256]; // "write mode" password
14245 char cookie_cpwd[256]; // custom page and javascript password
14246
14247 cookie_pwd[0] = 0;
14248 cookie_wpwd[0] = 0;
14249 cookie_cpwd[0] = 0;
14250
14251 std::string s = find_cookie_mg(msg, "midas_pwd");
14252 if (s.length() > 0) {
14253 mstrlcpy(cookie_pwd, s.c_str(), sizeof(cookie_pwd));
14254 cookie_pwd[strcspn(cookie_pwd, " ;\r\n")] = 0;
14255 }
14256
14257 s = find_cookie_mg(msg, "midas_wpwd");
14258 if (s.length()) {
14259 mstrlcpy(cookie_wpwd, s.c_str(), sizeof(cookie_pwd));
14260 cookie_wpwd[strcspn(cookie_wpwd, " ;\r\n")] = 0;
14261 }
14262
14263 s = find_cookie_mg(msg, "cpwd");
14264 if (s.length()) {
14265 mstrlcpy(cookie_cpwd, s.c_str(), sizeof(cookie_pwd));
14266 cookie_cpwd[strcspn(cookie_cpwd, " ;\r\n")] = 0;
14267 }
14268
14269 // extract refresh rate
14270 c->refresh = DEFAULT_REFRESH;
14271 s = find_cookie_mg(msg, "midas_refr");
14272 if (s.length() > 0)
14273 c->refresh = atoi(s.c_str());
14274
14275 // extract equipment expand flag
14276 //c->expand_equipment = 0;
14277 //s = find_cookie_mg(msg, "midas_expeq");
14278 //if (s.length() > 0)
14279 // c->expand_equipment = atoi(s.c_str());
14280
14281 c->cookie_pwd = cookie_pwd;
14282 c->cookie_wpwd = cookie_wpwd;
14283 c->cookie_cpwd = cookie_cpwd;
14284}
14285
14286#define RESPONSE_SENT 1
14287#define RESPONSE_QUEUED 2
14288#define RESPONSE_501 3
14289
14290static int handle_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14291{
14292 Cookies cookies;
14293
14294 decode_cookies(&cookies, msg);
14295
14296 // lock shared structures
14297
14298#ifdef HAVE_MONGOOSE6
14299 int status = ss_mutex_wait_for(request_mutex, 0);
14300 assert(status == SS_SUCCESS);
14301#endif
14302
14303 //t->fTimeLocked = GetTimeSec();
14304
14305 // prepare return buffer
14306
14307 Return *rr = new Return();
14308
14309 rr->zero();
14310
14311 // call midas
14312
14313 decode_get(rr, NULL, &cookies, uri, query_string, t);
14314
14315 if (trace_mg)
14316 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14317
14319
14320 if (rr->return_length == -1) {
14321 delete rr;
14322#ifdef HAVE_MONGOOSE6
14323 //t->fTimeUnlocked = GetTimeSec();
14324 ss_mutex_release(request_mutex);
14325#endif
14326 return RESPONSE_501;
14327 }
14328
14329 if (rr->return_length == 0)
14330 rr->return_length = strlen(rr->return_buffer);
14331
14332 //t->fTimeUnlocked = GetTimeSec();
14333
14334#ifdef HAVE_MONGOOSE6
14335 ss_mutex_release(request_mutex);
14336#endif
14337
14338 mg_send(nc, rr->return_buffer, rr->return_length);
14339
14340 if (!strstr(rr->return_buffer, "Content-Length")) {
14341 // cannot do pipelined http if response generated by mhttpd
14342 // decode_get() has no Content-Length header.
14343 // must close the connection.
14345 }
14346
14347 t->fTimeSent = GetTimeSec();
14348
14349 delete rr;
14350
14351 return RESPONSE_SENT;
14352}
14353
14354#ifdef HAVE_MONGOOSE616
14355
14356static uint32_t s_ncseqno = 1;
14357
14358struct MongooseNcUserData
14359{
14360 uint32_t ncseqno = 0;
14361
14362 MongooseNcUserData() // ctor
14363 {
14364 ncseqno = s_ncseqno++;
14365 //printf("MongooseNcUserData::ctor! ncseqno %d\n", ncseqno);
14366 }
14367
14368 ~MongooseNcUserData() // ctor
14369 {
14370 //printf("MongooseNcUserData::dtor! ncseqno %d\n", ncseqno);
14371 }
14372};
14373
14374static uint32_t GetNcSeqno(const mg_connection* nc)
14375{
14376 if (nc == NULL)
14377 return 0;
14378 if (nc->user_data == NULL)
14379 return 0;
14380 const MongooseNcUserData* ncud = (const MongooseNcUserData*)nc->user_data;
14381 return ncud->ncseqno;
14382}
14383
14384static uint32_t s_wseqno = 1;
14385
14386struct MongooseWorkObject
14387{
14388 uint32_t wseqno = 0;
14389 mg_connection* nc = NULL;
14390 uint32_t wncseqno = 0;
14391 bool http_get = false;
14392 bool http_post = false;
14393 bool mjsonrpc = false;
14394 Cookies cookies;
14395 std::string origin;
14396 std::string uri;
14397 std::string query_string;
14398 std::string post_body;
14399 std::string post_boundary;
14400 RequestTrace* t = NULL;
14401 bool send_done = false;
14402
14403 MongooseWorkObject(mg_connection* xnc) // ctor
14404 {
14405 wseqno = s_wseqno++;
14406 nc = xnc;
14407 wncseqno = GetNcSeqno(nc);
14408
14409 //printf("MongooseWorkObject::ctor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14410 }
14411
14412 ~MongooseWorkObject() // dtor
14413 {
14414 //printf("MongooseWorkObject::dtor! wseqno %d, nc %p, wncseqno %d\n", wseqno, nc, wncseqno);
14415
14416 // poison pointers
14417 nc = NULL;
14418 t = NULL;
14419 }
14420};
14421
14422struct MongooseThreadObject
14423{
14424 std::atomic_bool fIsRunning{false};
14425 std::thread* fThread = NULL; // thread
14426 void* fNc = NULL; // thread is attached to this network connection
14427 std::mutex fMutex;
14428 std::deque<MongooseWorkObject*> fQueue;
14429 std::condition_variable fNotify;
14430
14431 //MongooseThreadObject() // ctor
14432 //{
14433 // printf("MongooseThreadObject %p created!\n", this);
14434 //}
14435
14436 //~MongooseThreadObject() // dtor
14437 //{
14438 // printf("MongooseThreadObject %p destroyed!\n", this);
14439 //}
14440};
14441
14442static std::vector<MongooseThreadObject*> gMongooseThreads;
14443
14444static void mongoose_thread(MongooseThreadObject*);
14445
14446MongooseThreadObject* FindThread(void* nc)
14447{
14448 //printf("FindThread: nc %p, thread %s\n", nc, ss_tid_to_string(ss_gettid()).c_str());
14449
14450 MongooseThreadObject* last_not_connected = NULL;
14451
14452 for (auto it : gMongooseThreads) {
14453 MongooseThreadObject* to = it;
14454 if (to->fNc == nc) {
14455 //printf("to %p, nc %p: found thread\n", to, nc);
14456 return to;
14457 }
14458 if (to->fNc == NULL) {
14459 last_not_connected = to;
14460 }
14461 }
14462
14463 if (last_not_connected) {
14464 MongooseThreadObject* to = last_not_connected;
14465 to->fNc = nc;
14466 //printf("to %p, nc %p: reusing thread\n", to, nc);
14467 return to;
14468 }
14469
14470 MongooseThreadObject* to = new MongooseThreadObject();
14471
14472 to->fNc = nc;
14473
14474 //printf("to %p, nc %p: new thread\n", to, nc);
14475
14476 gMongooseThreads.push_back(to);
14477
14478 printf("Mongoose web server is using %d threads \r", (int)gMongooseThreads.size());
14479 fflush(stdout);
14480
14481 to->fThread = new std::thread(mongoose_thread, to);
14482
14483 return to;
14484}
14485
14486void FreeThread(void* nc)
14487{
14488 //printf("FreeThread, nc %p\n", nc);
14489
14490 for (auto it : gMongooseThreads) {
14491 MongooseThreadObject* to = it;
14492 if (to->fNc == nc) {
14493 //printf("to %p, nc %p: connection closed\n", to, nc);
14494 to->fNc = NULL;
14495 return;
14496 }
14497 }
14498
14499 //printf("to %p, nc %p: connection closed, but no thread\n", nullptr, nc);
14500}
14501
14502static void mongoose_queue(mg_connection* nc, MongooseWorkObject* w)
14503{
14504 w->nc = nc;
14505 MongooseThreadObject* to = FindThread(nc);
14506 assert(to->fNc == nc);
14507 to->fMutex.lock();
14508 to->fQueue.push_back(w);
14509 to->fMutex.unlock();
14510 to->fNotify.notify_one();
14511}
14512
14513static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag = false);
14514
14515static int queue_decode_get(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14516{
14517 MongooseWorkObject* w = new MongooseWorkObject(nc);
14518 w->http_get = true;
14519 decode_cookies(&w->cookies, msg);
14520 w->uri = uri;
14521 w->query_string = query_string;
14522 w->t = t;
14523
14524 mongoose_queue(nc, w);
14525
14526 return RESPONSE_QUEUED;
14527}
14528
14529static int queue_decode_post(struct mg_connection *nc, const http_message* msg, const char* boundary, const char* uri, const char* query_string, RequestTrace* t)
14530{
14531 MongooseWorkObject* w = new MongooseWorkObject(nc);
14532 w->http_post = true;
14533 decode_cookies(&w->cookies, msg);
14534 w->uri = uri;
14535 w->query_string = query_string;
14536 w->post_body = mgstr(&msg->body);
14537 w->post_boundary = boundary;
14538 w->t = t;
14539
14540 mongoose_queue(nc, w);
14541
14542 return RESPONSE_QUEUED;
14543}
14544
14545static int queue_mjsonrpc(struct mg_connection *nc, const std::string& origin, const std::string& post_body, RequestTrace* t)
14546{
14547 MongooseWorkObject* w = new MongooseWorkObject(nc);
14548 w->mjsonrpc = true;
14549 w->origin = origin;
14550 w->post_body = post_body;
14551 w->t = t;
14552
14553 mongoose_queue(nc, w);
14554
14555 return RESPONSE_QUEUED;
14556}
14557
14558static int thread_http_get(mg_connection *nc, MongooseWorkObject *w)
14559{
14560 // lock shared structures
14561
14562 //int status = ss_mutex_wait_for(request_mutex, 0);
14563 //assert(status == SS_SUCCESS);
14564
14565 //w->t->fTimeLocked = GetTimeSec();
14566
14567 // prepare return buffer
14568
14569 Return *rr = new Return();
14570
14571 rr->zero();
14572
14573 // call midas
14574
14575 decode_get(rr, NULL, &w->cookies, w->uri.c_str(), w->query_string.c_str(), w->t);
14576
14577 if (trace_mg)
14578 printf("handle_decode_get: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14579
14580 w->t->fTimeProcessed = GetTimeSec();
14581
14582 if (rr->return_length == -1) {
14583 delete rr;
14584 //w->t->fTimeUnlocked = GetTimeSec();
14585 //ss_mutex_release(request_mutex);
14586 return RESPONSE_501;
14587 }
14588
14589 if (rr->return_length == 0)
14590 rr->return_length = strlen(rr->return_buffer);
14591
14592 //w->t->fTimeUnlocked = GetTimeSec();
14593
14594 //ss_mutex_release(request_mutex);
14595
14596 bool close_flag = false;
14597
14598 if (!strstr(rr->return_buffer, "Content-Length")) {
14599 // cannot do pipelined http if response generated by mhttpd
14600 // decode_get() has no Content-Length header.
14601 // must close the connection.
14602 close_flag = true;
14603 }
14604
14605 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14606
14607 w->t->fTimeSent = GetTimeSec();
14608
14609 delete rr;
14610
14611 return RESPONSE_SENT;
14612}
14613
14614static int thread_http_post(mg_connection *nc, MongooseWorkObject *w)
14615{
14616 const char* post_data = w->post_body.c_str();
14617 int post_data_len = w->post_body.length();
14618
14619 // lock shared strctures
14620
14621 //int status = ss_mutex_wait_for(request_mutex, 0);
14622 //assert(status == SS_SUCCESS);
14623
14624 // prepare return buffer
14625
14626 Return* rr = new Return;
14627
14628 rr->zero();
14629
14630 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14631
14632 decode_post(rr, NULL, (char*)post_data, w->post_boundary.c_str(), post_data_len, &w->cookies, w->uri.c_str(), w->t);
14633
14634 if (trace_mg)
14635 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14636
14637 if (rr->return_length == -1) {
14638 //ss_mutex_release(request_mutex);
14639 delete rr;
14640 return RESPONSE_501;
14641 }
14642
14643 if (rr->return_length == 0)
14644 rr->return_length = strlen(rr->return_buffer);
14645
14646 //ss_mutex_release(request_mutex);
14647
14648 bool close_flag = false;
14649 if (!strstr(rr->return_buffer, "Content-Length")) {
14650 // cannot do pipelined http if response generated by mhttpd
14651 // decode_get() has no Content-Length header.
14652 // must close the connection.
14653 close_flag = true;
14654 }
14655
14656 mongoose_send(nc, w, rr->return_buffer, rr->return_length, NULL, 0, close_flag);
14657
14658 delete rr;
14659
14660 return RESPONSE_SENT;
14661
14662}
14663
14664static int thread_mjsonrpc(mg_connection *nc, MongooseWorkObject *w)
14665{
14666 w->t->fRPC = w->post_body;
14667
14668 //int status = ss_mutex_wait_for(request_mutex, 0);
14669 //assert(status == SS_SUCCESS);
14670
14671 //gMutex.lock();
14672 //w->t->fTimeLocked = GetTimeSec();
14673
14674 MJsonNode* reply = mjsonrpc_decode_post_data(w->post_body.c_str());
14675
14676 //w->t->fTimeUnlocked = GetTimeSec();
14677 //gMutex.unlock();
14678
14679 //ss_mutex_release(request_mutex);
14680
14681 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14682 const char* ptr;
14683 size_t size;
14684 reply->GetArrayBuffer(&ptr, &size);
14685
14686 std::string headers;
14687 headers += "HTTP/1.1 200 OK\n";
14688 if (w->origin.length() > 0)
14689 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14690 else
14691 headers += "Access-Control-Allow-Origin: *\n";
14692 headers += "Access-Control-Allow-Credentials: true\n";
14693 headers += "Content-Length: " + toString(size) + "\n";
14694 headers += "Content-Type: application/octet-stream\n";
14695 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14696
14697 //printf("sending headers: %s\n", headers.c_str());
14698 //printf("sending reply: %s\n", reply_string.c_str());
14699
14700 std::string send = headers + "\n";
14701
14702 w->t->fTimeProcessed = GetTimeSec();
14703
14704 mongoose_send(nc, w, send.c_str(), send.length(), ptr, size);
14705
14706 w->t->fTimeSent = GetTimeSec();
14707
14708 delete reply;
14709
14710 return RESPONSE_SENT;
14711 }
14712
14713 std::string reply_string = reply->Stringify();
14714 int reply_length = reply_string.length();
14715
14716 std::string headers;
14717 headers += "HTTP/1.1 200 OK\n";
14718 if (w->origin.length() > 0)
14719 headers += "Access-Control-Allow-Origin: " + w->origin + "\n";
14720 else
14721 headers += "Access-Control-Allow-Origin: *\n";
14722 headers += "Access-Control-Allow-Credentials: true\n";
14723 headers += "Content-Length: " + toString(reply_length) + "\n";
14724 headers += "Content-Type: application/json\n";
14725 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14726
14727 if (trace_mg_verbose) {
14728 printf("-----------------------\nSending headers: %s", headers.c_str());
14729 std::string r = reply_string.substr(0, 128);
14730 printf("-----------------------\nSending reply (%d bytes): %s\n\n\n", (int)reply_string.size(), r.c_str());
14731 }
14732
14733 std::string send = headers + "\n" + reply_string;
14734
14735 w->t->fTimeProcessed = GetTimeSec();
14736
14737 mongoose_send(nc, w, send.c_str(), send.length(), NULL, 0);
14738
14739 w->t->fTimeSent = GetTimeSec();
14740
14741 delete reply;
14742
14743 return RESPONSE_SENT;
14744}
14745
14746static int thread_work_function(mg_connection *nc, MongooseWorkObject *w)
14747{
14748 if (w->http_get)
14749 return thread_http_get(nc, w);
14750 else if (w->http_post)
14751 return thread_http_post(nc, w);
14752 else if (w->mjsonrpc)
14753 return thread_mjsonrpc(nc, w);
14754 else
14755 return RESPONSE_501;
14756}
14757
14758#endif
14759
14760static int handle_decode_post(struct mg_connection *nc, const http_message* msg, const char* uri, const char* query_string, RequestTrace* t)
14761{
14762
14763 char boundary[256];
14764 boundary[0] = 0;
14765 const std::string ct = find_header_mg(msg, "Content-Type");
14766 if (ct.length() > 0) {
14767 const char* s = strstr(ct.c_str(), "boundary=");
14768 if (s)
14769 mstrlcpy(boundary, s+9, sizeof(boundary));
14770 }
14771
14772#ifdef HAVE_MONGOOSE616
14773 if (multithread_mg)
14774 return queue_decode_post(nc, msg, boundary, uri, query_string, t);
14775#endif
14776
14777 Cookies cookies;
14778
14779 decode_cookies(&cookies, msg);
14780
14781 const char* post_data = msg->body.p;
14782 int post_data_len = msg->body.len;
14783
14784 // lock shared strctures
14785
14786#ifdef HAVE_MONGOOSE6
14787 int status = ss_mutex_wait_for(request_mutex, 0);
14788 assert(status == SS_SUCCESS);
14789#endif
14790
14791 // prepare return buffer
14792
14793 Return* rr = new Return;
14794
14795 rr->zero();
14796
14797 //printf("post_data_len %d, data [%s], boundary [%s]\n", post_data_len, post_data, boundary);
14798
14799 decode_post(rr, NULL, (char*)post_data, boundary, post_data_len, &cookies, uri, t);
14800
14801 if (trace_mg)
14802 printf("handle_decode_post: return buffer length %d bytes, strlen %d\n", rr->return_length, (int)strlen(rr->return_buffer));
14803
14804 if (rr->return_length == -1) {
14805#ifdef HAVE_MONGOOSE6
14806 ss_mutex_release(request_mutex);
14807#endif
14808 delete rr;
14809 return RESPONSE_501;
14810 }
14811
14812 if (rr->return_length == 0)
14813 rr->return_length = strlen(rr->return_buffer);
14814
14815#ifdef HAVE_MONGOOSE6
14816 ss_mutex_release(request_mutex);
14817#endif
14818
14819 mg_send(nc, rr->return_buffer, rr->return_length);
14820
14821 if (!strstr(rr->return_buffer, "Content-Length")) {
14822 // cannot do pipelined http if response generated by mhttpd
14823 // decode_get() has no Content-Length header.
14824 // must close the connection.
14826 }
14827
14828 delete rr;
14829
14830 return RESPONSE_SENT;
14831}
14832
14833static int handle_http_get(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14834{
14835 std::string query_string = mgstr(&msg->query_string);
14836
14837 if (trace_mg||verbose_mg)
14838 printf("handle_http_get: uri [%s], query [%s]\n", uri, query_string.c_str());
14839
14840 if (query_string == "mjsonrpc_schema") {
14841 MJsonNode* s = mjsonrpc_get_schema();
14842 std::string reply = s->Stringify();
14843 delete s;
14844
14845 int reply_length = reply.length();
14846
14847 const std::string origin_header = find_header_mg(msg, "Origin");
14848
14849 std::string headers;
14850 headers += "HTTP/1.1 200 OK\n";
14851 if (origin_header.length() > 0)
14852 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14853 else
14854 headers += "Access-Control-Allow-Origin: *\n";
14855 headers += "Access-Control-Allow-Credentials: true\n";
14856 headers += "Content-Length: " + toString(reply_length) + "\n";
14857 headers += "Content-Type: application/json\n";
14858 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14859
14860 //printf("sending headers: %s\n", headers.c_str());
14861 //printf("sending reply: %s\n", reply.c_str());
14862
14863 std::string send = headers + "\n" + reply;
14864
14866
14867 mg_send(nc, send.c_str(), send.length());
14868
14869 t->fTimeSent = GetTimeSec();
14870
14871 return RESPONSE_SENT;
14872 }
14873
14874 if (query_string == "mjsonrpc_schema_text") {
14875 MJsonNode* s = mjsonrpc_get_schema();
14876 std::string reply = mjsonrpc_schema_to_text(s);
14877 delete s;
14878
14879 int reply_length = reply.length();
14880
14881 const std::string origin_header = find_header_mg(msg, "Origin");
14882
14883 std::string headers;
14884 headers += "HTTP/1.1 200 OK\n";
14885 if (origin_header.length() > 0)
14886 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14887 else
14888 headers += "Access-Control-Allow-Origin: *\n";
14889 headers += "Access-Control-Allow-Credentials: true\n";
14890 headers += "Content-Length: " + toString(reply_length) + "\n";
14891 headers += "Content-Type: text/plain\n";
14892 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14893
14894 //printf("sending headers: %s\n", headers.c_str());
14895 //printf("sending reply: %s\n", reply.c_str());
14896
14897 std::string send = headers + "\n" + reply;
14898
14900
14901 mg_send(nc, send.c_str(), send.length());
14902
14903 t->fTimeSent = GetTimeSec();
14904
14905 return RESPONSE_SENT;
14906 }
14907
14908#ifdef HAVE_MONGOOSE616
14909 if (multithread_mg)
14910 return queue_decode_get(nc, msg, uri, query_string.c_str(), t);
14911#endif
14912
14913 return handle_decode_get(nc, msg, uri, query_string.c_str(), t);
14914}
14915
14916static int handle_http_post(struct mg_connection *nc, const http_message* msg, const char* uri, RequestTrace* t)
14917{
14918 std::string query_string = mgstr(&msg->query_string);
14919 std::string post_data = mgstr(&msg->body);
14920
14921 if (trace_mg||verbose_mg)
14922 printf("handle_http_post: uri [%s], query [%s], post data %d bytes\n", uri, query_string.c_str(), (int)post_data.length());
14923 if (trace_mg_verbose)
14924 printf("handle_http_post: post data = \n%s\n", post_data.c_str());
14925
14926 if (query_string.substr(0, 8) == "mjsonrpc") { // ignore any parameter after "mjsonrpc"
14927 const std::string origin_header = find_header_mg(msg, "Origin");
14928 const std::string ctype_header = find_header_mg(msg, "Content-Type");
14929
14930 if (strstr(ctype_header.c_str(), "application/json") == NULL) {
14931 std::string headers;
14932 headers += "HTTP/1.1 415 Unsupported Media Type\n";
14933 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14934
14935 //printf("sending headers: %s\n", headers.c_str());
14936 //printf("sending reply: %s\n", reply.c_str());
14937
14938 if (trace_mg_verbose)
14939 printf("handle_http_post: unsupported media type \"%s\"\n", ctype_header.c_str());
14940
14941 std::string send = headers + "\n";
14942
14944
14945 mg_send(nc, send.c_str(), send.length());
14946
14947 t->fTimeSent = GetTimeSec();
14948
14949 return RESPONSE_SENT;
14950 }
14951
14952#ifdef HAVE_MONGOOSE616
14953 if (multithread_mg)
14954 return queue_mjsonrpc(nc, origin_header, post_data, t);
14955#endif
14956
14957 //printf("post body: %s\n", post_data.c_str());
14958
14959 t->fRPC = post_data;
14960
14961#ifdef HAVE_MONGOOSE6
14962 int status = ss_mutex_wait_for(request_mutex, 0);
14963 assert(status == SS_SUCCESS);
14964#endif
14965
14966 //t->fTimeLocked = GetTimeSec();
14967
14968 MJsonNode* reply = mjsonrpc_decode_post_data(post_data.c_str());
14969
14970 //t->fTimeUnlocked = GetTimeSec();
14971
14972#ifdef HAVE_MONGOOSE6
14973 ss_mutex_release(request_mutex);
14974#endif
14975
14976 if (reply->GetType() == MJSON_ARRAYBUFFER) {
14977 const char* ptr;
14978 size_t size;
14979 reply->GetArrayBuffer(&ptr, &size);
14980
14981 std::string headers;
14982 headers += "HTTP/1.1 200 OK\n";
14983 if (origin_header.length() > 0)
14984 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
14985 else
14986 headers += "Access-Control-Allow-Origin: *\n";
14987 headers += "Access-Control-Allow-Credentials: true\n";
14988 headers += "Content-Length: " + toString(size) + "\n";
14989 headers += "Content-Type: application/octet-stream\n";
14990 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
14991
14992 //printf("sending headers: %s\n", headers.c_str());
14993 //printf("sending reply: %s\n", reply_string.c_str());
14994
14995 std::string send = headers + "\n";
14996
14998
14999 mg_send(nc, send.c_str(), send.length());
15000 mg_send(nc, ptr, size);
15001
15002 t->fTimeSent = GetTimeSec();
15003
15004 delete reply;
15005
15006 return RESPONSE_SENT;
15007 }
15008
15009 std::string reply_string = reply->Stringify();
15010 int reply_length = reply_string.length();
15011
15012 std::string headers;
15013 headers += "HTTP/1.1 200 OK\n";
15014 if (origin_header.length() > 0)
15015 headers += "Access-Control-Allow-Origin: " + std::string(origin_header) + "\n";
15016 else
15017 headers += "Access-Control-Allow-Origin: *\n";
15018 headers += "Access-Control-Allow-Credentials: true\n";
15019 headers += "Content-Length: " + toString(reply_length) + "\n";
15020 headers += "Content-Type: application/json\n";
15021 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15022
15023 //printf("sending headers: %s\n", headers.c_str());
15024 //printf("sending reply: %s\n", reply_string.c_str());
15025
15026 std::string send = headers + "\n" + reply_string;
15027
15029
15030 mg_send(nc, send.c_str(), send.length());
15031
15032 t->fTimeSent = GetTimeSec();
15033
15034 delete reply;
15035
15036 return RESPONSE_SENT;
15037 }
15038
15039 return handle_decode_post(nc, msg, uri, query_string.c_str(), t);
15040}
15041
15043{
15044 //
15045 // JSON-RPC CORS pre-flight request, see
15046 // https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
15047 //
15048 // OPTIONS /resources/post-here/ HTTP/1.1
15049 // Host: bar.other
15050 // User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
15051 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
15052 // Accept-Language: en-us,en;q=0.5
15053 // Accept-Encoding: gzip,deflate
15054 // Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
15055 // Connection: keep-alive
15056 // Origin: http://foo.example
15057 // Access-Control-Request-Method: POST
15058 // Access-Control-Request-Headers: X-PINGOTHER
15059 //
15060 // HTTP/1.1 200 OK
15061 // Date: Mon, 01 Dec 2008 01:15:39 GMT
15062 // Server: Apache/2.0.61 (Unix)
15063 // Access-Control-Allow-Origin: http://foo.example
15064 // Access-Control-Allow-Methods: POST, GET, OPTIONS
15065 // Access-Control-Allow-Headers: X-PINGOTHER
15066 // Access-Control-Max-Age: 1728000
15067 // Vary: Accept-Encoding, Origin
15068 // Content-Encoding: gzip
15069 // Content-Length: 0
15070 // Keep-Alive: timeout=2, max=100
15071 // Connection: Keep-Alive
15072 // Content-Type: text/plain
15073 //
15074
15075 const std::string origin_header = find_header_mg(msg, "Origin");
15076
15077 if (trace_mg||verbose_mg)
15078 printf("handle_http_options_cors: origin [%s]\n", origin_header.c_str());
15079
15080 std::string headers;
15081 headers += "HTTP/1.1 200 OK\n";
15082 //headers += "Date: Sat, 08 Jul 2006 12:04:08 GMT\n";
15083 if (origin_header.length() > 0)
15084 headers += "Access-Control-Allow-Origin: " + origin_header + "\n";
15085 else
15086 headers += "Access-Control-Allow-Origin: *\n";
15087 headers += "Access-Control-Allow-Headers: Content-Type\n";
15088 headers += "Access-Control-Allow-Credentials: true\n";
15089 headers += "Access-Control-Max-Age: 120\n";
15090 headers += "Content-Length: 0\n";
15091 headers += "Content-Type: text/plain\n";
15092 //printf("sending headers: %s\n", headers.c_str());
15093 //printf("sending reply: %s\n", reply.c_str());
15094
15095 std::string send = headers + "\n";
15096
15098
15099 mg_send(nc, send.c_str(), send.length());
15100
15101 t->fTimeSent = GetTimeSec();
15102}
15103
15104// HTTP event handler
15105
15106static bool mongoose_passwords_enabled(const struct mg_connection *nc);
15107
15108#ifdef HAVE_MONGOOSE616
15109static MVOdb* gProxyOdb = NULL;
15110#endif
15111
15113{
15114 std::string method = mgstr(&msg->method);
15115 std::string query_string = mgstr(&msg->query_string);
15116 std::string uri_encoded = mgstr(&msg->uri);
15117 std::string uri = UrlDecode(uri_encoded.c_str());
15118 mg_str* user_mg_str = mg_get_http_header(msg, "X-Remote-User");
15119 std::string user;
15120
15121 if (user_mg_str)
15122 user = mgstr(user_mg_str);
15123
15124 if (trace_mg)
15125 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());
15126
15127 RequestTrace* t = new RequestTrace;
15129 t->fMethod = method;
15130 t->fUri = uri;
15131 t->fQuery = query_string;
15132
15133 // process OPTIONS for Cross-origin (CORS) preflight request
15134 // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
15135 if (method == "OPTIONS" && query_string == "mjsonrpc" && mg_get_http_header(msg, "Access-Control-Request-Method") != NULL) {
15136 handle_http_options_cors(nc, msg, t);
15137 t->fCompleted = true;
15139 return;
15140 }
15141
15143 std::string username = check_digest_auth(msg, gAuthMg);
15144
15145 // Cannot re-read the password file - it is not thread safe to do so
15146 // unless I lock gAuthMg for each call check_digest_auth() and if I do so,
15147 // I will serialize (single-thread) all the http requests and defeat
15148 // the whole point of multithreading the web server. K.O.
15149 //
15151 //if (username.length() < 1) {
15152 // bool ok = read_passwords(&gAuthMg);
15153 // if (ok)
15154 // username = check_digest_auth(msg, &gAuthMg);
15155 //}
15156
15157 if (trace_mg)
15158 printf("handle_http_message: auth user: \"%s\"\n", username.c_str());
15159
15160 if (username.length() == 0) {
15161 if (trace_mg||verbose_mg)
15162 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());
15163
15165 t->fCompleted = true;
15167 return;
15168 }
15169 t->fAuthOk = true;
15170 } else {
15171 t->fAuthOk = true;
15172 }
15173
15174#ifdef HAVE_MONGOOSE616
15175 if (gProxyOdb && starts_with(uri, "/proxy/")) {
15176 std::string::size_type p1 = uri.find("/", 1);
15177 if (p1 == uri.length()-1) {
15178 std::string response = "404 Not Found (Proxy name is missing)";
15179 mg_send_head(nc, 404, response.length(), NULL);
15180 mg_send(nc, response.c_str(), response.length());
15181 delete t;
15182 return;
15183 }
15184 std::string::size_type p2 = uri.find("/", p1+1);
15185 if (p2 == std::string::npos) {
15186 std::string response = "404 Not Found (Proxy URL should end with a slash)";
15187 mg_send_head(nc, 404, response.length(), NULL);
15188 mg_send(nc, response.c_str(), response.length());
15189 delete t;
15190 return;
15191 }
15192 std::string p = uri.substr(p1+1, p2-p1-1);
15193 //printf("uri [%s], p1: %d, p2: %d, substr: [%s]\n", uri.c_str(), (int)p1, (int)p2, p.c_str());
15194 if (p.length() < 1) {
15195 std::string response = "404 Not Found (Double-slash or Proxy name is too short)";
15196 mg_send_head(nc, 404, response.length(), NULL);
15197 mg_send(nc, response.c_str(), response.length());
15198 delete t;
15199 return;
15200 }
15201 std::string destination;
15202 gProxyOdb->RS(p.c_str(), &destination);
15203 if (destination.length() < 1) {
15204 std::string response = "404 Not Found (Proxy not found in ODB)";
15205 mg_send_head(nc, 404, response.length(), NULL);
15206 mg_send(nc, response.c_str(), response.length());
15207 delete t;
15208 return;
15209 } else if (destination[0] == '#') {
15210 std::string response = "404 Not Found (Proxy commented-out in ODB)";
15211 mg_send_head(nc, 404, response.length(), NULL);
15212 mg_send(nc, response.c_str(), response.length());
15213 delete t;
15214 return;
15215 } else if (ends_with_char(destination, '/')) {
15216 std::string response = "404 Not Found (Proxy address should not end with a slash)";
15217 mg_send_head(nc, 404, response.length(), NULL);
15218 mg_send(nc, response.c_str(), response.length());
15219 delete t;
15220 return;
15221 } else if (!starts_with(destination, "http")) {
15222 std::string response = "404 Not Found (Proxy address does not start with http";
15223 mg_send_head(nc, 404, response.length(), NULL);
15224 mg_send(nc, response.c_str(), response.length());
15225 delete t;
15226 return;
15227 } else {
15228 std::string m;
15229 m += "/proxy";
15230 m += "/";
15231 m += p;
15232 mg_str mount = mg_mk_str(m.c_str());
15233 mg_str upstream = mg_mk_str(destination.c_str());
15234 if (verbose_mg||trace_mg) {
15235 printf("proxy: uri [%s] mount [%s] upstream [%s]\n", uri.c_str(), mgstr(&mount).c_str(), mgstr(&upstream).c_str());
15236 }
15237 mg_http_reverse_proxy(nc, msg, mount, upstream);
15238 delete t;
15239 return;
15240 }
15241 }
15242#endif
15243
15244 int response = RESPONSE_501;
15245
15246 if (method == "GET")
15247 response = handle_http_get(nc, msg, uri.c_str(), t);
15248 else if (method == "POST")
15249 response = handle_http_post(nc, msg, uri.c_str(), t);
15250
15251 if (response == RESPONSE_501) {
15252 if (trace_mg||verbose_mg)
15253 printf("handle_http_message: sending 501 Not Implemented error\n");
15254
15255 std::string response = "501 Not Implemented";
15256 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15257 mg_send(nc, response.c_str(), response.length());
15258 }
15259
15260 if (response != RESPONSE_QUEUED) {
15261 t->fCompleted = true;
15263 }
15264}
15265
15266#ifdef HAVE_MONGOOSE6
15267
15268static void handle_http_event_mg(struct mg_connection *nc, int ev, void *ev_data)
15269{
15270 switch (ev) {
15271 case MG_EV_HTTP_REQUEST:
15272 if (trace_mg)
15273 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15274 handle_http_message(nc, (http_message*)ev_data);
15275 break;
15276 default:
15277 if (trace_mg)
15278 printf("handle_http_event_mg: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15279 break;
15280 }
15281}
15282
15283static void handle_http_redirect(struct mg_connection *nc, int ev, void *ev_data)
15284{
15285 switch (ev) {
15286 case MG_EV_HTTP_REQUEST:
15287 {
15288 http_message* msg = (http_message*)ev_data;
15289 if (trace_mg)
15290 printf("handle_http_redirect: nc %p, ev %d, ev_data %p -> http request\n", nc, ev, ev_data);
15291
15292 mg_printf(nc, "HTTP/1.1 302 Found\r\nLocation: https://%s%s\r\n\r\n",
15293 ((std::string*)(nc->user_data))->c_str(),
15294 mgstr(&msg->uri).c_str());
15296 }
15297 break;
15298 default:
15299 if (trace_mg)
15300 printf("handle_http_redirect: nc %p, ev %d, ev_data %p\n", nc, ev, ev_data);
15301 }
15302}
15303
15304#endif
15305
15306#ifdef HAVE_MONGOOSE616
15307
15308// from mongoose examples/multithreaded/multithreaded.c
15309
15310//static sock_t s_sock[2];
15311static std::atomic_bool s_shutdown{false};
15312static struct mg_mgr s_mgr;
15313static std::atomic_int s_rseqno{1};
15314static std::mutex s_mg_broadcast_mutex;
15315
15316#if 0
15317// This info is passed to the worker thread
15318struct work_request {
15319 void* nc;
15320 MongooseWorkObject* w;
15321};
15322#endif
15323
15324// This info is passed by the worker thread to mg_broadcast
15325struct work_result {
15326 mg_connection* nc = NULL;
15327 uint32_t check = 0x12345678;
15328 int rseqno = 0;
15329 MongooseWorkObject* w = NULL;
15330 const char* p1 = NULL;
15331 size_t s1 = 0;
15332 const char* p2 = NULL;
15333 size_t s2 = 0;
15334 bool close_flag = false;
15335 bool send_501 = false;
15336};
15337
15338#if 0
15339static void mongoose_queue(void *nc, MongooseWorkObject *w)
15340{
15341 struct work_request req = {nc, w};
15342
15343 //printf("nc: %p: wseqno: %d, queue work object!\n", nc, w->wseqno);
15344
15345 if (write(s_sock[0], &req, sizeof(req)) < 0) {
15346 fprintf(stderr, "mongoose_queue: Error: write(s_sock(0)) error %d (%s)\n", errno, strerror(errno));
15347 abort();
15348 }
15349}
15350#endif
15351
15352static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data)
15353{
15354 (void) ev;
15355 struct work_result *res = (struct work_result *)ev_data;
15356
15357 assert(res != NULL);
15358 assert(res->w != NULL);
15359
15360 //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);
15361
15362 // check for correct connection, note that nc objects are reused and after a socket is closed
15363 // and a new one is opened, the same nc address and the same nc->sock can now refer to a completely
15364 // different tcp connection. So we check ncseqno instead of nc. K.O.
15365
15366 //if (res->nc != nc)
15367 //return;
15368
15369 if (GetNcSeqno(nc) != res->w->wncseqno)
15370 return;
15371
15372 //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);
15373
15374 if (res->send_501) {
15375 std::string response = "501 Not Implemented";
15376 mg_send_head(nc, 501, response.length(), NULL); // 501 Not Implemented
15377 mg_send(nc, response.c_str(), response.length());
15378 }
15379
15380 if (res->s1 > 0)
15381 mg_send(nc, res->p1, res->s1);
15382
15383 if (res->s2 > 0)
15384 mg_send(nc, res->p2, res->s2);
15385
15386 if (res->close_flag) {
15387 // cannot do pipelined http if response generated by mhttpd
15388 // decode_get() has no Content-Length header.
15389 // must close the connection.
15391 }
15392
15393 res->w->send_done = true;
15394}
15395
15396static void mongoose_send(mg_connection* nc, MongooseWorkObject* w, const char* p1, size_t s1, const char* p2, size_t s2, bool close_flag)
15397{
15398 //printf("nc: %p: send %d and %d\n", nc, (int)s1, (int)s2);
15399 struct work_result res;
15400 res.nc = nc;
15401 res.w = w;
15402 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15403 res.p1 = p1;
15404 res.s1 = s1;
15405 res.p2 = p2;
15406 res.s2 = s2;
15407 res.close_flag = close_flag;
15408 res.send_501 = false;
15409 //printf("nc: %p: call mg_broadcast()\n", nc);
15410
15411 // NB: mg_broadcast() is advertised as thread-safe, but it is not.
15412 //
15413 // in mongoose 6.16, mg_brodacast() and mg_mgr_handle_ctl_sock() have several problems:
15414 //
15415 // a) "wrong thread" read from mgr->ctl[0], defeating the handshake
15416 //
15417 // b) "lost messages". if more than one message is written to mgr->ctl[0], the second message
15418 // will be "eaten" by mg_mgr_handle_ctl_sock() because of mistatch between number of bytes read and written
15419 // in the two functions. mg_mgr_handle_ctl_sock() always reads about 8000 bytes while mg_broadcast()
15420 // writes 8 bytes per message, (per examples/multithreaded/multithreaded.c. mhttpd messages are a bit longer).
15421 // So if multiple messages are present in the msg->ctl[0] pipe, the read call (of about 8000 bytes)
15422 // in mg_mgr_handle_ctl_sock() will return several messages (last message may be truncated)
15423 // but only the first message will be processed by the code. any additional messages are ignored.
15424 //
15425 // Problems (a) and (b) are easy to fix by using a mutex to serialize mg_broadcast().
15426 //
15427 // c) if the mg_broadcast() message contains pointers to the data buffer to be sent out,
15428 // the caller of mg_broadcast() should not free these data buffers until mg_send() is called
15429 // in "on_work_complete()". In theory, the caller of mg_broadcast() could wait until on_work_complete()
15430 // sets a "done" flag. In practice, if the corresponding network connection is closed before
15431 // mg_mgr_handle_ctl_sock() has looped over it, on_work_complete() will never run
15432 // and the "done" flag will never be set. (Of course, network connections are permitted to close
15433 // at any time without warning, but) the firefox browser closes the network connections "a lot"
15434 // especially when user pressed the "page reload" button at the moment when HTTP transations
15435 // are "in flight". (google-chrome tends to permit these "lame duck" transactions to complete and mongoose
15436 // does not see unexpected socket closures, at least not as many).
15437 //
15438 // To fix problem (c) I need to know when mg_mgr_handle_ctl_sock()'s loop over network connections
15439 // has completed (two cases: (a) my on_work_complete() was hopefully called and finished,
15440 // and (b) the "right" network connection was already closed (for whatever reason) and my on_work_complete()
15441 // was never called).
15442 //
15443 // My solution is to change the handshake between mg_broadcast() and mg_mgr_handle_ctl_sock() by sending
15444 // the handshake reply after looping over the network connections instead of after reading the message
15445 // from msg->ctl[1].
15446 //
15447 // This requires a modification to the code in mongoose.c. If this change is lost/undone, nothing will work.
15448 //
15449
15450 s_mg_broadcast_mutex.lock();
15451 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15452 s_mg_broadcast_mutex.unlock();
15453}
15454
15455static void mongoose_send_501(mg_connection* nc, MongooseWorkObject* w)
15456{
15457 struct work_result res;
15458 res.nc = nc;
15459 res.w = w;
15460 res.rseqno = s_rseqno++; // thread-asfe, s_rseqno is std::atomic_int
15461 res.p1 = 0;
15462 res.s1 = 0;
15463 res.p2 = 0;
15464 res.s2 = 0;
15465 res.close_flag = false;
15466 res.send_501 = true;
15467 //printf("nc: %p, call mg_broadcast()\n", nc);
15468
15469 s_mg_broadcast_mutex.lock();
15470 mg_broadcast(&s_mgr, on_work_complete, (void *)&res, sizeof(res));
15471 s_mg_broadcast_mutex.unlock();
15472}
15473
15474#if 0
15475void *worker_thread_proc(void *param)
15476{
15477 //struct mg_mgr *mgr = (struct mg_mgr *) param;
15478 struct work_request req = {0};
15479
15480 while ((! _abort) && (! s_shutdown)) {
15481 int rd = read(s_sock[1], &req, sizeof(req));
15482 if (rd == 0) {
15483 // socket closed, shutdown the thread
15484 break;
15485 }
15486 if (rd < 0) {
15487 if (_abort || s_shutdown) {
15488 return NULL;
15489 }
15490 fprintf(stderr, "worker_thread_proc: Error: read(s_sock(1)) returned %d, error %d (%s)\n", rd, errno, strerror(errno));
15491 abort();
15492 return NULL;
15493 }
15494
15495 //printf("nc: %p: received request!\n", req.nc);
15496
15497 int response = thread_work_function(req.nc, req.w);
15498
15499 if (response == RESPONSE_501) {
15500 if (trace_mg||verbose_mg)
15501 printf("handle_http_message: sending 501 Not Implemented error\n");
15502 mongoose_send_501(req.nc, req.w);
15503 }
15504
15505 req.w->t->fCompleted = true;
15506 gTraceBuf->AddTraceMTS(req.w->t);
15507
15508 //printf("nc: %p: wseqno: %d, delete work object!\n", req.nc, req.w->wseqno);
15509
15510 delete req.w;
15511 req.w = NULL;
15512 }
15513 return NULL;
15514}
15515#endif
15516
15517static void mongoose_thread(MongooseThreadObject* to)
15518{
15519 //printf("to %p, nc %p: thread %p started!\n", to, to->fNc, to->fThread);
15520
15521 std::unique_lock<std::mutex> ulm(to->fMutex, std::defer_lock);
15522
15523 to->fIsRunning = true;
15524
15525 while ((! _abort) && (! s_shutdown)) {
15526 MongooseWorkObject *w = NULL;
15527
15528 ulm.lock();
15529 while (to->fQueue.empty()) {
15530 //printf("to %p, nc %p, thread %p: waiting!\n", to, to->fNc, to->fThread);
15531 to->fNotify.wait(ulm);
15532 if (_abort || s_shutdown) {
15533 break;
15534 }
15535 }
15536
15537 if (_abort || s_shutdown) {
15538 break;
15539 }
15540
15541 w = to->fQueue.front();
15542 to->fQueue.pop_front();
15543 ulm.unlock();
15544
15545 //printf("to %p, nc %p: wseqno: %d, received request!\n", to, w->nc, w->wseqno);
15546
15547 int response = thread_work_function(w->nc, w);
15548
15549 if (response == RESPONSE_501) {
15550 if (trace_mg||verbose_mg)
15551 printf("handle_http_message: sending 501 Not Implemented error\n");
15552 mongoose_send_501(w->nc, w);
15553 }
15554
15555 // mg_broadcast() called on_work_complete() on the main thread and waited until it finished
15556
15557 if (!w->send_done) {
15558 // NB: careful here, if connection nc was closed, pointer nc points to nowhere! do not dereference it!
15559 // NB: stay quiet about it, nothing special about network connctions closing and opening as they wish.
15560 //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);
15561 }
15562
15563 w->t->fCompleted = true;
15564 gTraceBuf->AddTraceMTS(w->t);
15565
15566 //printf("nc: %p: wseqno: %d, delete work object!\n", w->nc, w->wseqno);
15567
15568 delete w;
15569 }
15570
15571 to->fIsRunning = false;
15572
15573 //printf("to %p, nc %p: thread %p finished!\n", to, to->fNc, to->fThread);
15574}
15575
15576static bool mongoose_hostlist_enabled(const struct mg_connection *nc);
15577
15578static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
15579{
15580 (void) nc;
15581 (void) ev_data;
15582
15583 //if (trace_mg && ev != 0) {
15584 // printf("ev_handler: connection %p, event %d\n", nc, ev);
15585 //}
15586
15587 switch (ev) {
15588 case 0:
15589 break;
15590 default: {
15591 if (trace_mg) {
15592 printf("ev_handler: connection %p, event %d\n", nc, ev);
15593 }
15594 break;
15595 }
15596 case MG_EV_ACCEPT:
15597 assert(nc->user_data == NULL);
15598 nc->user_data = new MongooseNcUserData();
15599
15600 if (trace_mg) {
15601 printf("ev_handler: connection %p, MG_EV_ACCEPT, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15602 }
15603 if (s_shutdown) {
15604 //printf("XXX nc %p!\n", nc);
15606 } else if (mongoose_hostlist_enabled(nc)) {
15607 if (!mongoose_check_hostlist(&nc->sa)) {
15609 }
15610 }
15611 break;
15612 case MG_EV_RECV:
15613 if (trace_mg_recv) {
15614 printf("ev_handler: connection %p, MG_EV_RECV, %d bytes\n", nc, *(int*)ev_data);
15615 }
15616 if (s_shutdown) {
15617 //printf("RRR nc %p!\n", nc);
15619 }
15620 break;
15621 case MG_EV_SEND:
15622 if (trace_mg_send) {
15623 printf("ev_handler: connection %p, MG_EV_SEND, %d bytes\n", nc, *(int*)ev_data);
15624 }
15625 break;
15626 case MG_EV_HTTP_CHUNK: {
15627 if (trace_mg) {
15628 printf("ev_handler: connection %p, MG_EV_HTTP_CHUNK\n", nc);
15629 }
15630 if (s_shutdown) {
15631 //printf("RRR1 nc %p!\n", nc);
15633 }
15634 break;
15635 }
15636 case MG_EV_HTTP_REQUEST: {
15637 struct http_message* msg = (struct http_message*)ev_data;
15638 if (trace_mg) {
15639 printf("ev_handler: connection %p, MG_EV_HTTP_REQUEST \"%s\" \"%s\"\n", nc, mgstr(&msg->method).c_str(), mgstr(&msg->uri).c_str());
15640 }
15641 if (s_shutdown) {
15642 //printf("RRR2 nc %p!\n", nc);
15644 } else {
15645 handle_http_message(nc, msg);
15646 }
15647 break;
15648 }
15649 case MG_EV_CLOSE: {
15650 if (trace_mg) {
15651 printf("ev_handler: connection %p, MG_EV_CLOSE, user_data %p, ncseqno %d\n", nc, nc->user_data, GetNcSeqno(nc));
15652 }
15653 //printf("CCC nc %p!\n", nc);
15654 FreeThread(nc);
15655 if (nc->user_data) {
15656 MongooseNcUserData* ncud = (MongooseNcUserData*)nc->user_data;
15657 nc->user_data = NULL;
15658 delete ncud;
15659 ncud = NULL;
15660 }
15661 }
15662 }
15663}
15664
15665#define FLAG_HTTPS MG_F_USER_1
15666#define FLAG_PASSWORDS MG_F_USER_2
15667#define FLAG_HOSTLIST MG_F_USER_3
15668
15669static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15670{
15671 int flags = 0;
15672 if (nc && nc->listener) {
15673 flags = nc->listener->flags;
15674 }
15675 //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);
15676 return flags & FLAG_PASSWORDS;
15677}
15678
15679static bool mongoose_hostlist_enabled(const struct mg_connection *nc)
15680{
15681 int flags = 0;
15682 if (nc && nc->listener) {
15683 flags = nc->listener->flags;
15684 }
15685 //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);
15686 return flags & FLAG_HOSTLIST;
15687}
15688
15689static int mongoose_listen(const char* address, int flags)
15690{
15691#if MG_ENABLE_SSL
15692#else
15693 if (flags & FLAG_HTTPS) {
15694 cm_msg(MERROR, "mongoose_listen", "https port \"%s\" requested, but mhttpd compiled without MG_ENABLE_SSL", address);
15695 return SS_SOCKET_ERROR;
15696 }
15697#endif
15698
15699 struct mg_connection *nc = mg_bind(&s_mgr, address, ev_handler);
15700 if (nc == NULL) {
15701 cm_msg(MERROR, "mongoose_listen", "Cannot mg_bind address \"%s\"", address);
15702 return SS_SOCKET_ERROR;
15703 }
15704
15705 if (flags & FLAG_HTTPS) {
15706#if MG_ENABLE_SSL
15707 std::string cert_file;
15708
15709 int status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
15710
15711 if (status != SUCCESS) {
15712 cm_msg(MERROR, "mongoose_listen", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
15713 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");
15714 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");
15715 return SS_FILE_ERROR;
15716 }
15717
15718 printf("Mongoose web server will use https certificate file \"%s\"\n", cert_file.c_str());
15719
15720 const char* errmsg = mg_set_ssl(nc, cert_file.c_str(), NULL);
15721 if (errmsg) {
15722 cm_msg(MERROR, "mongoose_listen", "Cannot enable https with certificate file \"%s\", error: %s", cert_file.c_str(), errmsg);
15723 return SS_SOCKET_ERROR;
15724 }
15725
15726 // NB: where is the warning that the SSL certificate has expired?!? K.O.
15727#else
15728 abort(); // cannot happen!
15729#endif
15730 }
15731
15733
15734 nc->flags |= flags;
15735
15736 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");
15737
15738 return SUCCESS;
15739}
15740
15741static int mongoose_init(MVOdb* odb, bool no_passwords, bool no_hostlist, const std::vector<std::string>& user_hostlist)
15742{
15743 bool enable_localhost_port = true;
15744 int localhost_port = 8080;
15745 bool localhost_port_passwords = false;
15746
15747 bool enable_insecure_port = false;
15748 int insecure_port = 8081;
15749 bool insecure_port_passwords = true;
15750 bool insecure_port_hostlist = true;
15751
15752 bool enable_https_port = false;
15753 int https_port = 8443;
15754 bool https_port_passwords = true;
15755 bool https_port_hostlist = false;
15756
15757 std::vector<std::string> hostlist;
15758 hostlist.push_back("localhost");
15759
15760 bool enable_ipv6 = true;
15761
15762 odb->RB("Enable localhost port", &enable_localhost_port, true);
15763 odb->RI("localhost port", &localhost_port, true);
15764 odb->RB("localhost port passwords", &localhost_port_passwords, true);
15765 odb->RB("Enable insecure port", &enable_insecure_port, true);
15766 odb->RI("insecure port", &insecure_port, true);
15767 odb->RB("insecure port passwords", &insecure_port_passwords, true);
15768 odb->RB("insecure port host list", &insecure_port_hostlist, true);
15769 odb->RB("Enable https port", &enable_https_port, true);
15770 odb->RI("https port", &https_port, true);
15771 odb->RB("https port passwords", &https_port_passwords, true);
15772 odb->RB("https port host list", &https_port_hostlist, true);
15773 odb->RSA("Host list", &hostlist, true, 10, 256);
15774 odb->RB("Enable IPv6", &enable_ipv6, true);
15775
15776 // populate the MIME.types table
15777 gProxyOdb = odb->Chdir("Proxy", true);
15778 std::string proxy_example = "#http://localhost:8080";
15779 gProxyOdb->RS("example", &proxy_example, true);
15780
15781 // populate the MIME.types table
15782 SaveMimetypes(odb->Chdir("mime.types", true));
15783
15784 if (!no_passwords
15785 && ((enable_localhost_port && localhost_port_passwords)
15786 || (enable_insecure_port && insecure_port_passwords)
15787 || (enable_https_port && https_port_passwords))) {
15788 gAuthMg = new Auth();
15789 int status = gAuthMg->Init();
15790 if (status != SUCCESS) {
15791 printf("mongoose_init: Error: Cannot initialize authorization object!\n");
15792 return status;
15793 }
15794 printf("HTTP Digest authentication with realm \"%s\" and password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
15795 } else {
15796 printf("Password protection is off\n");
15797 }
15798
15799 if (!no_hostlist
15800 && ((enable_insecure_port && insecure_port_hostlist)
15801 || (enable_https_port && https_port_hostlist))) {
15802 gAllowedHosts.clear();
15803
15804 // copy the user allowed hosts
15805 for (unsigned int i=0; i<user_hostlist.size(); i++)
15806 gAllowedHosts.push_back(user_hostlist[i]);
15807
15808 for (unsigned i=0; i<hostlist.size(); i++) {
15809 std::string s = hostlist[i];
15810 if (s.length() < 1) // skip emties
15811 continue;
15812
15813 if (s[0] == '#') // skip commented-out entries
15814 continue;
15815
15816 //printf("add allowed hosts %d [%s]\n", i, s.c_str());
15817 gAllowedHosts.push_back(s);
15818 }
15819
15820 printf("Hostlist active, connections will be accepted only from: ");
15821 for (unsigned i=0; i<gAllowedHosts.size(); i++) {
15822 if (i>0)
15823 printf(", ");
15824 printf("%s", gAllowedHosts[i].c_str());
15825 }
15826 printf("\n");
15827 } else {
15828 printf("Hostlist off, connections from anywhere will be accepted\n");
15829 }
15830
15831 mg_mgr_init(&s_mgr, NULL);
15832
15833 bool listen_failed = false;
15834
15835 if (enable_localhost_port) {
15836 char str[256];
15837 sprintf(str, "localhost:%d", localhost_port);
15838 int status = mongoose_listen(str, 0);
15839 if (status != SUCCESS)
15840 listen_failed = true;
15841 if (enable_ipv6) {
15842 sprintf(str, "[::1]:%d", localhost_port);
15843 status = mongoose_listen(str, 0);
15844 if (status != SUCCESS)
15845 listen_failed = true;
15846 }
15847 }
15848
15849 if (enable_insecure_port) {
15850 char str[256];
15851 int flags = 0;
15852 if (insecure_port_passwords)
15853 flags |= FLAG_PASSWORDS;
15854 if (insecure_port_hostlist)
15855 flags |= FLAG_HOSTLIST;
15856 if (enable_ipv6) {
15857 sprintf(str, "[::]:%d", insecure_port);
15858 int status = mongoose_listen(str, flags);
15859 if (status != SUCCESS)
15860 listen_failed = true;
15861 } else {
15862 sprintf(str, "%d", insecure_port);
15863 int status = mongoose_listen(str, flags);
15864 if (status != SUCCESS)
15865 listen_failed = true;
15866 }
15867 }
15868
15869 if (enable_https_port) {
15870 char str[256];
15871 int flags = 0;
15872 if (https_port_passwords)
15873 flags |= FLAG_PASSWORDS;
15874 if (https_port_hostlist)
15875 flags |= FLAG_HOSTLIST;
15876 flags |= FLAG_HTTPS;
15877 if (enable_ipv6) {
15878 sprintf(str, "[::]:%d", https_port);
15879 int status = mongoose_listen(str, flags);
15880 if (status != SUCCESS)
15881 listen_failed = true;
15882 } else {
15883 sprintf(str, "%d", https_port);
15884 int status = mongoose_listen(str, flags);
15885 if (status != SUCCESS)
15886 listen_failed = true;
15887 }
15888 }
15889
15890 if (listen_failed) {
15891 cm_msg(MERROR, "mongoose_init", "Failed to listen on a TCP port enabled in ODB /WebServer");
15892 return SS_SOCKET_ERROR;
15893 }
15894
15895 return SUCCESS;
15896}
15897
15898static void mongoose_poll(int msec = 200)
15899{
15900 mg_mgr_poll(&s_mgr, msec);
15901}
15902
15903static void mongoose_cleanup()
15904{
15905 printf("Mongoose web server shutting down\n");
15906
15907 s_shutdown = true;
15908
15909 // close listener sockets
15910 if (s_mgr.active_connections) {
15911 struct mg_connection* nc = s_mgr.active_connections;
15912 while (nc) {
15913 //printf("nc %p, next %p, user_data %p, listener %p, flags %lu\n", nc, nc->next, nc->user_data, nc->listener, nc->flags);
15914 if (nc->flags & MG_F_LISTENING) {
15916 }
15917 nc = nc->next;
15918 }
15919 }
15920
15921 // tell threads to shut down
15922 for (auto it : gMongooseThreads) {
15923 MongooseThreadObject* to = it;
15924 to->fNotify.notify_one();
15925 }
15926
15927 // wait until all threads stop
15928 for (int i=0; i<10; i++) {
15929 int count_running = 0;
15930 for (auto it : gMongooseThreads) {
15931 MongooseThreadObject* to = it;
15932 //printf("AAA6C %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15933 if (to->fIsRunning) {
15934 count_running++;
15935 }
15936 }
15937 printf("Mongoose web server shutting down, %d threads still running\n", count_running);
15938 if (count_running == 0)
15939 break;
15940 mongoose_poll(1000);
15941 }
15942
15943 // delete thread objects
15944 for (auto it : gMongooseThreads) {
15945 MongooseThreadObject* to = it;
15946 //printf("AAA7B %p thread %p running %d!\n", to, to->fThread, to->fIsRunning);
15947 if (to->fIsRunning) {
15948 cm_msg(MERROR, "mongoose", "thread failed to shut down");
15949 continue;
15950 }
15951 to->fThread->join();
15952 delete to->fThread;
15953 delete to;
15954 }
15955 gMongooseThreads.clear();
15956
15957 mg_mgr_free(&s_mgr);
15958
15959 //closesocket(s_sock[0]);
15960 //closesocket(s_sock[1]);
15961
15962 // make leak sanitizer happy!
15963 for (auto e : gHostlistCache) {
15964 delete e;
15965 }
15966 gHostlistCache.clear();
15967 if (gProxyOdb) {
15968 delete gProxyOdb;
15969 gProxyOdb = NULL;
15970 }
15971 if (gMimeTypesOdb) {
15972 delete gMimeTypesOdb;
15973 gMimeTypesOdb = NULL;
15974 }
15975
15976 printf("Mongoose web server shut down\n");
15977}
15978
15979#endif
15980
15981#ifdef HAVE_MONGOOSE6
15982
15983static bool mongoose_passwords_enabled(const struct mg_connection *nc)
15984{
15985 return true;
15986}
15987
15988int start_mg(int user_http_port, int user_https_port, int socket_priviledged_port, int verbose)
15989{
15990 HNDLE hDB;
15991 int size;
15992 int status;
15993
15994 //if (verbose)
15995 // trace_mg = true;
15996
15997 if (verbose)
15998 verbose_mg = true;
15999
16001 assert(status == CM_SUCCESS);
16002
16003 int http_port = 8080;
16004 int https_port = 8443;
16005 int http_redirect_to_https = 1;
16006
16007 size = sizeof(http_port);
16008 db_get_value(hDB, 0, "/Experiment/midas http port", &http_port, &size, TID_INT, TRUE);
16009
16010 size = sizeof(https_port);
16011 db_get_value(hDB, 0, "/Experiment/midas https port", &https_port, &size, TID_INT, TRUE);
16012
16013 size = sizeof(http_redirect_to_https);
16014 db_get_value(hDB, 0, "/Experiment/http redirect to https", &http_redirect_to_https, &size, TID_BOOL, TRUE);
16015
16016 bool need_cert_file = false;
16017 bool need_password_file = false;
16018
16019 if (user_http_port)
16020 http_port = user_http_port;
16021
16022 if (user_https_port)
16023 https_port = user_https_port;
16024
16025 if (https_port) {
16026 need_cert_file = true;
16027 need_password_file = true;
16028 }
16029
16030 if (!https_port)
16031 http_redirect_to_https = 0;
16032
16033 if (http_port && !http_redirect_to_https) {
16034 // no passwords serving over http unless
16035 // http is just a redict to https
16036 need_password_file = false;
16037 }
16038
16039 if (socket_priviledged_port >= 0) {
16040 // no passwords if serving unencrypted http on port 80
16041 need_password_file = false;
16042 printf("Mongoose web server password portection is disabled: serving unencrypted http on port 80\n");
16043 }
16044
16045 bool have_at_least_one_port = false;
16046
16047 std::string cert_file;
16048
16049 if (need_cert_file) {
16050 status = find_file_mg("ssl_cert.pem", cert_file, NULL, trace_mg);
16051
16052 if (status != SUCCESS) {
16053 cm_msg(MERROR, "mongoose", "cannot find SSL certificate file \"%s\"", cert_file.c_str());
16054 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");
16055 return SS_FILE_ERROR;
16056 }
16057
16058 printf("Mongoose web server will use SSL certificate file \"%s\"\n", cert_file.c_str());
16059 }
16060
16061 if (need_password_file) {
16062 gAuthMg = new Auth();
16063 status = gAuthMg->Init();
16064 if (status != SUCCESS) {
16065 printf("Error: Cannot initialize authorization object!\n");
16066 return status;
16067 }
16068 printf("Mongoose web server will use authentication realm \"%s\", password file \"%s\"\n", gAuthMg->realm.c_str(), gAuthMg->passwd_filename.c_str());
16069 } else {
16070 printf("Mongoose web server will not use password protection\n");
16071 }
16072
16073 if (trace_mg)
16074 printf("start_mg!\n");
16075
16076#ifndef OS_WINNT
16077 signal(SIGPIPE, SIG_IGN);
16078#endif
16079
16080 if (!gTraceBuf) {
16082 }
16083
16084 if (!request_mutex) {
16085 status = ss_mutex_create(&request_mutex, FALSE);
16086 assert(status==SS_SUCCESS || status==SS_CREATED);
16087 }
16088
16089 mg_mgr_init(&mgr_mg, NULL);
16090
16091 // use socket bound to priviledged port (setuid-mode)
16092 if (socket_priviledged_port >= 0) {
16093 struct mg_connection* nc = mg_add_sock(&mgr_mg, socket_priviledged_port, handle_event_mg);
16094 if (nc == NULL) {
16095 cm_msg(MERROR, "mongoose", "Cannot create mg_connection for set-uid-root privileged port");
16096 return SS_SOCKET_ERROR;
16097 }
16098
16099 nc->flags |= MG_F_LISTENING;
16100#ifdef MG_ENABLE_THREADS
16102#endif
16104 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16105
16106 have_at_least_one_port = true;
16107 printf("mongoose web server is listening on the set-uid-root privileged port\n");
16108 }
16109
16110 if (http_port != 80) { // port 80 is already handled by socket_priviledged_port
16111 char str[256];
16112 sprintf(str, "%d", http_port);
16113 struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16114 if (nc == NULL) {
16115 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", http_port);
16116 return SS_SOCKET_ERROR;
16117 }
16118
16119#ifdef MG_ENABLE_THREADS
16121#endif
16123
16124 if (http_redirect_to_https) {
16125 std::string hostname = ss_gethostname();
16126 char str[256];
16127 sprintf(str, "%d", https_port);
16128 std::string s = hostname + ":" + std::string(str);
16129 nc->user_data = new std::string(s);
16130 mg_register_http_endpoint(nc, "/", handle_http_redirect);
16131 printf("mongoose web server is redirecting HTTP port %d to https://%s\n", http_port, s.c_str());
16132 } else {
16133 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16134 }
16135
16136 have_at_least_one_port = true;
16137 printf("mongoose web server is listening on the HTTP port %d\n", http_port);
16138 }
16139
16140 if (https_port) {
16141#ifdef MG_ENABLE_SSL
16142 char str[256];
16143 sprintf(str, "%d", https_port);
16144 struct mg_connection* nc = mg_bind(&mgr_mg, str, handle_event_mg);
16145 if (nc == NULL) {
16146 cm_msg(MERROR, "mongoose", "Cannot bind to port %d", https_port);
16147 return SS_SOCKET_ERROR;
16148 }
16149
16150 mg_set_ssl(nc, cert_file.c_str(), NULL);
16151#ifdef MG_ENABLE_THREADS
16153#endif
16155 mg_register_http_endpoint(nc, "/", handle_http_event_mg);
16156
16157 have_at_least_one_port = true;
16158 printf("mongoose web server is listening on the HTTPS port %d\n", https_port);
16159#else
16160 cm_msg(MERROR, "mongoose", "https port %d requested, but mhttpd compiled without MG_ENABLE_SSL", https_port);
16161 return SS_SOCKET_ERROR;
16162#endif
16163 }
16164
16165 if (!have_at_least_one_port) {
16166 cm_msg(MERROR, "mongoose", "cannot start: no ports defined");
16167 return SS_FILE_ERROR;
16168 }
16169
16170 return SUCCESS;
16171}
16172
16173int stop_mg()
16174{
16175 if (trace_mg)
16176 printf("stop_mg!\n");
16177
16178 // Stop the server.
16179 mg_mgr_free(&mgr_mg);
16180
16181 if (trace_mg)
16182 printf("stop_mg done!\n");
16183 return SUCCESS;
16184}
16185
16186int loop_mg()
16187{
16188 int status = SUCCESS;
16189
16190 /* establish Ctrl-C handler - will set _abort to TRUE */
16192
16193 while (!_abort) {
16194
16195 /* cm_yield() is not thread safe, need to take a lock */
16196
16197#ifdef HAVE_MONGOOSE6
16198 status = ss_mutex_wait_for(request_mutex, 0);
16199#endif
16200 gMutex.lock();
16201
16202 /* check for shutdown message */
16203 status = cm_yield(0);
16204 if (status == RPC_SHUTDOWN)
16205 break;
16206
16207 gMutex.unlock();
16208#ifdef HAVE_MONGOOSE6
16209 status = ss_mutex_release(request_mutex);
16210#endif
16211
16212 //ss_sleep(10);
16213
16214 mg_mgr_poll(&mgr_mg, 10);
16215 }
16216
16217 return status;
16218}
16219#endif
16220
16221static MJsonNode* get_http_trace(const MJsonNode* params)
16222{
16223 if (!params) {
16224 MJSO *doc = MJSO::I();
16225 doc->D("get current value of mhttpd http_trace");
16226 doc->P(NULL, 0, "there are no input parameters");
16227 doc->R(NULL, MJSON_INT, "current value of http_trace");
16228 return doc;
16229 }
16230
16231 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16232}
16233
16234static MJsonNode* set_http_trace(const MJsonNode* params)
16235{
16236 if (!params) {
16237 MJSO* doc = MJSO::I();
16238 doc->D("set new value of mhttpd http_trace");
16239 doc->P(NULL, MJSON_INT, "new value of http_trace");
16240 doc->R(NULL, MJSON_INT, "new value of http_trace");
16241 return doc;
16242 }
16243
16244 http_trace = params->GetInt();
16245 return mjsonrpc_make_result("http_trace", MJsonNode::MakeInt(http_trace));
16246}
16247
16249{
16250 mjsonrpc_add_handler("set_http_trace", set_http_trace);
16251 mjsonrpc_add_handler("get_http_trace", get_http_trace);
16252}
16253
16254/*------------------------------------------------------------------*/
16255
16256int main(int argc, const char *argv[])
16257{
16258 int status;
16259 int daemon = FALSE;
16260#ifdef HAVE_MONGOOSE6
16261 int user_http_port = 0;
16262 int user_https_port = 0;
16263#endif
16264#ifdef HAVE_MONGOOSE616
16265 bool no_passwords = false;
16266 bool no_hostlist = false;
16267#endif
16268 const char *myname = "mhttpd";
16269
16270 setbuf(stdout, NULL);
16271 setbuf(stderr, NULL);
16272#ifdef SIGPIPE
16273 /* avoid getting killed by "Broken pipe" signals */
16274 signal(SIGPIPE, SIG_IGN);
16275#endif
16276
16277#ifdef HAVE_MONGOOSE6
16278 //
16279 // if running setuid-root, unconditionally bind to port 80.
16280 //
16281
16282 int socket_priviledged_port = -1;
16283
16284#ifdef OS_UNIX
16285 // in setuid-root mode bind to priviledged port
16286 if (getuid() != geteuid()) {
16287 int port80 = 80;
16288
16289 printf("mhttpd is running in setuid-root mode.\n");
16290
16291 socket_priviledged_port = open_listening_socket(port80);
16292 if (socket_priviledged_port < 0) {
16293 printf("Cannot open listening socket on TCP port %d, aborting.\n", port80);
16294 exit(1);
16295 }
16296
16297 // give up root privilege
16298 status = setuid(getuid());
16299 if (status != 0) {
16300 printf("Cannot give up root privelege, aborting.\n");
16301 exit(1);
16302 }
16303 status = setuid(getuid());
16304 if (status != 0) {
16305 printf("Cannot give up root privelege, aborting.\n");
16306 exit(1);
16307 }
16308 }
16309#endif
16310#endif
16311
16312 char midas_hostname[256];
16313 char midas_expt[256];
16314
16315 /* get default from environment */
16316 cm_get_environment(midas_hostname, sizeof(midas_hostname), midas_expt, sizeof(midas_expt));
16317
16318 /* parse command line parameters */
16319#ifdef HAVE_MONGOOSE6
16320 gUserAllowedHosts.clear();
16321#else
16322 std::vector<std::string> user_hostlist;
16323#endif
16324 for (int i = 1; i < argc; i++) {
16325 if (argv[i][0] == '-' && argv[i][1] == 'D')
16326 daemon = TRUE;
16327 else if (argv[i][0] == '-' && argv[i][1] == 'v')
16328 verbose = TRUE;
16329 else if (argv[i][0] == '-' && argv[i][1] == 'E')
16330 elog_mode = TRUE;
16331 else if (argv[i][0] == '-' && argv[i][1] == 'H') {
16333#ifdef HAVE_MONGOOSE6
16334 } else if (strcmp(argv[i], "--http") == 0) {
16335 if (argv[i+1]) {
16336 user_http_port = atoi(argv[i+1]);
16337 }
16338 } else if (strcmp(argv[i], "--https") == 0) {
16339 if (argv[i+1]) {
16340 user_https_port = atoi(argv[i+1]);
16341 }
16342#endif
16343 } else if (strcmp(argv[i], "--trace-mg") == 0) {
16344 trace_mg = true;
16345 trace_mg_recv = true;
16346 trace_mg_send = true;
16347 } else if (strcmp(argv[i], "--trace-mg-verbose") == 0) {
16348 trace_mg_verbose = true;
16349 } else if (strcmp(argv[i], "--no-trace-mg-recv") == 0) {
16350 trace_mg_recv = false;
16351 } else if (strcmp(argv[i], "--no-trace-mg-send") == 0) {
16352 trace_mg_send = false;
16353 } else if (strcmp(argv[i], "--verbose-mg") == 0) {
16354 verbose_mg = true;
16355#ifdef HAVE_MONGOOSE616
16356 } else if (strcmp(argv[i], "--no-multithread") == 0) {
16357 multithread_mg = false;
16358 } else if (strcmp(argv[i], "--no-passwords") == 0) {
16359 no_passwords = true;
16360 } else if (strcmp(argv[i], "--no-hostlist") == 0) {
16361 no_hostlist = true;
16362#endif
16363 } else if (argv[i][0] == '-') {
16364 if (i + 1 >= argc || argv[i + 1][0] == '-')
16365 goto usage;
16366 if (argv[i][1] == 'h')
16367 mstrlcpy(midas_hostname, argv[++i], sizeof(midas_hostname));
16368 else if (argv[i][1] == 'e')
16369 mstrlcpy(midas_expt, argv[++i], sizeof(midas_hostname));
16370 else if (argv[i][1] == 'a') {
16371#ifdef HAVE_MONGOOSE6
16372 gUserAllowedHosts.push_back(argv[++i]);
16373#else
16374 user_hostlist.push_back(argv[++i]);
16375#endif
16376 } else if (argv[i][1] == 'p') {
16377 printf("Option \"-p port_number\" for the old web server is obsolete.\n");
16378 printf("mongoose web server is the new default, port number is set in ODB or with \"--http port_number\".\n");
16379 printf("To run the obsolete old web server, please use \"--oldserver\" switch.\n");
16380 return 1;
16381 } else {
16382 usage:
16383 printf("usage: %s [-h Hostname[:port]] [-e Experiment] [-v] [-D] [-a Hostname]\n\n", argv[0]);
16384 printf(" -a add hostname to the hostlist of hosts allowed to connect to mhttpd\n");
16385 printf(" -e experiment to connect to\n");
16386 printf(" -h connect to midas server (mserver) on given host\n");
16387 printf(" -v display verbose HTTP communication\n");
16388 printf(" -D become a daemon\n");
16389 printf(" -E only display ELog system\n");
16390 printf(" -H only display history plots\n");
16391#ifdef HAVE_MONGOOSE6
16392 printf(" --http port - bind to specified HTTP port (default is ODB \"/Experiment/midas http port\")\n");
16393 printf(" --https port - bind to specified HTTP port (default is ODB \"/Experiment/midas https port\")\n");
16394#endif
16395 printf(" --verbose-mg - trace mongoose web requests\n");
16396 printf(" --trace-mg - trace mongoose events\n");
16397 printf(" --no-trace-mg-recv - do not trace mongoose recv events\n");
16398 printf(" --no-trace-mg-send - dop not trace mongoose send events\n");
16399#ifdef HAVE_MONGOOSE616
16400 printf(" --no-multithread - disable mongoose multithreading\n");
16401 printf(" --no-passwords - disable password protection\n");
16402 printf(" --no-hostlist - disable access control host list\n");
16403#endif
16404 return 0;
16405 }
16406 }
16407 }
16408
16409 if (daemon) {
16410 printf("Becoming a daemon...\n");
16412 }
16413
16414#ifdef OS_LINUX
16415 /* write PID file */
16416 FILE *f = fopen("/var/run/mhttpd.pid", "w");
16417 if (f != NULL) {
16418 fprintf(f, "%d", ss_getpid());
16419 fclose(f);
16420 }
16421#endif
16422
16423 if (history_mode)
16424 myname = "mhttpd_history";
16425
16426 /*---- connect to experiment ----*/
16427 status = cm_connect_experiment1(midas_hostname, midas_expt, myname, NULL,
16430 return 1;
16431 else if (status == DB_INVALID_HANDLE) {
16432 std::string s = cm_get_error(status);
16433 puts(s.c_str());
16434 } else if (status != CM_SUCCESS) {
16435 std::string s = cm_get_error(status);
16436 puts(s.c_str());
16437 return 1;
16438 }
16439
16440 /* mhttpd needs the watchdog thread until we are sure
16441 * we do not have any long sleeps anywhere in the mhttpd code.
16442 * this includes reads from the history files or databases,
16443 * that can take arbitrary long time */
16445
16446 /* Get ODB handles */
16447
16448 HNDLE hDB;
16449
16451
16452 MVOdb *odb = MakeMidasOdb(hDB);
16453 gOdb = odb;
16454
16455 /* do ODB record checking */
16456 if (!check_odb_records(odb)) {
16457 // check_odb_records() fails with nothing printed to the terminal
16458 // because mhttpd does not print cm_msg(MERROR, ...) messages to the terminal.
16459 // At least print something!
16460 printf("check_odb_records() failed, see messages and midas.log, bye!\n");
16462 return 1;
16463 }
16464
16465#ifdef HAVE_MONGOOSE6
16466 if (init_allowed_hosts() != SUCCESS) {
16467 printf("init_allowed_hosts() failed, see messages and midas.log, bye!\n");
16469 return 1;
16470 }
16471
16472 if (verbose) {
16473 if (gAllowedHosts.size() > 0) {
16474 printf("mhttpd allowed hosts list: ");
16475 for (unsigned int i=0; i<gAllowedHosts.size(); i++) {
16476 if (i>0)
16477 printf(", ");
16478 printf("%s", gAllowedHosts[i].c_str());
16479 }
16480 printf("\n");
16481 } else {
16482 printf("mhttpd allowed hosts list is empty\n");
16483 }
16484 }
16485
16486 // populate the MIME.types table
16487 SaveMimetypes(odb->Chdir("WebServer/mime.types", true));
16488#endif
16489
16490 /* initialize odb entries needed for mhttpd and midas web pages */
16491 init_mhttpd_odb(odb);
16492
16493 /* initialize menu buttons */
16494 init_menu_buttons(odb);
16495
16496 /* initialize elog odb entries */
16497 init_elog_odb();
16498
16499 /* initialize the JSON RPC handlers */
16500 mjsonrpc_init();
16502
16504
16505#ifdef HAVE_MONGOOSE6
16506 status = start_mg(user_http_port, user_https_port, socket_priviledged_port, verbose);
16507 if (status != SUCCESS) {
16508 // At least print something!
16509 printf("could not start the mongoose web server, see messages and midas.log, bye!\n");
16511 return 1;
16512 }
16513#endif
16514
16515#ifdef HAVE_MONGOOSE616
16516
16517#ifdef SIGPIPE
16518#ifdef SIG_IGN
16519 signal(SIGPIPE, SIG_IGN);
16520#endif
16521#endif
16522
16523 if (!gTraceBuf) {
16525 }
16526
16527 //if (!request_mutex) {
16528 // status = ss_mutex_create(&request_mutex, FALSE);
16529 // assert(status==SS_SUCCESS || status==SS_CREATED);
16530 //}
16531
16532 /* establish Ctrl-C handler - will set _abort to TRUE */
16534
16535 MVOdb* o = odb->Chdir("WebServer", true);
16536 status = mongoose_init(o, no_passwords, no_hostlist, user_hostlist);
16537 if (status != SUCCESS) {
16538 // At least print something!
16539 printf("Error: Could not start the mongoose web server, see messages and midas.log, bye!\n");
16541 return 1;
16542 }
16543
16544 delete o;
16545#endif
16546
16547#ifdef HAVE_MONGOOSE6
16548 loop_mg();
16549 stop_mg();
16550#endif
16551
16552#ifdef HAVE_MONGOOSE616
16553 while (!_abort) {
16554
16555 /* cm_yield() is not thread safe, need to take a lock */
16556
16557 //status = ss_mutex_wait_for(request_mutex, 0);
16558 gMutex.lock();
16559
16560 /* check for shutdown message */
16561 status = cm_yield(0);
16562 if (status == RPC_SHUTDOWN)
16563 break;
16564
16565 gMutex.unlock();
16566 //status = ss_mutex_release(request_mutex);
16567
16568 //ss_sleep(10);
16569
16570 mongoose_poll(10);
16571 }
16572
16573 mongoose_cleanup();
16574#endif
16575
16576 if (gMh) {
16577 delete gMh;
16578 gMh = NULL;
16579 gMhkey = 0;
16580 }
16581
16582 mjsonrpc_exit();
16584 return 0;
16585}
16586
16587/* emacs
16588 * Local Variables:
16589 * tab-width: 8
16590 * c-basic-offset: 3
16591 * indent-tabs-mode: nil
16592 * End:
16593 */
#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:13759
std::string passwd_filename
Definition mhttpd.cxx:13758
std::string realm
Definition mhttpd.cxx:13757
int Init()
Definition mhttpd.cxx:13766
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_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
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
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
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:14205
static bool trace_mg
Definition mhttpd.cxx:13737
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:13739
#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:16248
#define RESPONSE_501
Definition mhttpd.cxx:14288
INT check_odb_records(MVOdb *odb)
Definition mhttpd.cxx:13421
static int handle_http_post(struct mg_connection *nc, const http_message *msg, const char *uri, RequestTrace *t)
Definition mhttpd.cxx:14916
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:14174
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:13787
#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:14239
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:13227
static MJsonNode * get_http_trace(const MJsonNode *params)
Definition mhttpd.cxx:16221
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:13829
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:13485
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:14760
std::string time_to_string(time_t t)
Definition mhttpd.cxx:8166
static std::string mgstr(const mg_str *s)
Definition mhttpd.cxx:14169
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:13736
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:13704
void decode_query(Param *pp, const char *query_string)
Definition mhttpd.cxx:13202
static bool gDoReloadHistory
Definition mhttpd.cxx:8176
static std::string check_digest_auth(struct http_message *hm, Auth *auth)
Definition mhttpd.cxx:13925
static MidasHistoryInterface * gMh
Definition mhttpd.cxx:8185
static bool trace_mg_verbose
Definition mhttpd.cxx:13740
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:13495
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:13808
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:12275
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:14287
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:14833
#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:12217
static BOOL elog_mode
Definition mhttpd.cxx:94
void Lock(RequestTrace *t)
Definition mhttpd.cxx:12269
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:13265
#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:14187
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:14290
void gen_odb_attachment(Return *r, const char *path, std::string &bout)
Definition mhttpd.cxx:2164
#define RESPONSE_SENT
Definition mhttpd.cxx:14286
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:16234
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:13483
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:13671
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:13819
void interprete(Param *p, Return *r, Attachment *a, const Cookies *c, const char *dec_path, RequestTrace *t)
Definition mhttpd.cxx:12283
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:15042
#define DELETEA(x, n)
Definition mhttpd.cxx:8269
static Auth * gAuthMg
Definition mhttpd.cxx:13785
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:15112
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:13738
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:13749
std::string password
Definition mhttpd.cxx:13752
std::string username
Definition mhttpd.cxx:13750
std::string realm
Definition mhttpd.cxx:13751
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:12260
int refresh
Definition mhttpd.cxx:12263
std::string cookie_wpwd
Definition mhttpd.cxx:12261
std::string cookie_cpwd
Definition mhttpd.cxx:12262
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