otsdaq  v2_04_01
RemoteWebUsers.cc
1 #include "otsdaq-core/WebUsersUtilities/RemoteWebUsers.h"
2 
3 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
4 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h"
5 #include "otsdaq-core/SOAPUtilities/SOAPParameters.h" //must include in .h for static function
6 #include "otsdaq-core/SOAPUtilities/SOAPUtilities.h"
7 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
8 
9 #include <cstdio>
10 #include <cstdlib>
11 #include <vector>
12 
13 #include "otsdaq-core/SupervisorInfo/AllSupervisorInfo.h"
14 
15 using namespace ots;
16 
17 #undef __MF_SUBJECT__
18 #define __MF_SUBJECT__ "RemoteWebUsers"
19 
20 //========================================================================================================================
21 // User Notes:
22 // - use xmlRequestGateway to check security from outside the Supervisor and Wizard
23 //
24 // Example usage:
25 //
26 //
27 //
28 // void exampleClass::exampleRequestHandler(xgi::Input * in, xgi::Output * out)
29 //
30 // {
31 // cgicc::Cgicc cgi(in);
32 //
33 // //...
34 //
35 // HttpXmlDocument xmldoc;
36 // std::string userWithLock, userName, displayName;
37 // uint64_t activeSessionIndex;
38 // uint8_t userPermissions;
39 //
40 // //**** start LOGIN GATEWAY CODE ***//
41 // //check cookieCode, sequence, userWithLock, and permissions access all in
42 // one shot!
43 // {
44 // bool automaticCommand = 0; //automatic commands should not refresh
45 // cookie code.. only user initiated commands should! bool checkLock =
46 // true; bool lockRequired = true;
47 //
48 // if(!theRemoteWebUsers_.xmlRequestToGateway(
49 // cgi,out,&xmldoc,theSupervisorsConfiguration_
50 // ,&userPermissions //acquire user's access level
51 //(optionally null pointer)//
52 // ,!automaticCommand //true/false refresh cookie code
53 // ,USER_PERMISSIONS_THRESHOLD //set access level requirement to
54 // pass gateway
55 // ,checkLock //true/false enable check that
56 // system is unlocked or this user has the lock ,lockRequired
58 // ,&userWithLock //acquire username with lock
59 //(optionally null pointer)
60 // ,&userName //acquire username of this user
61 //(optionally
62 // null pointer) ,0//,&displayName //acquire user's
63 // Display Name
64 // ,0//,&activeSessionIndex //acquire user's session index
65 // associated with the cookieCode
66 // ))
67 // { //failure
68 // //std::cout << out->str() << std::endl; //could print out return
69 // string on failure return;
70 // }
71 // }
72 // //done checking cookieCode, sequence, userWithLock, and permissions access
73 // all in one shot!
74 // //**** end LOGIN GATEWAY CODE ***//
75 //
76 // //Success! if here.
77 // //
78 // //... use acquired values below
79 // //...
80 //
81 // //add to xml document, for example:
82 // //DOMElement* parentEl;
83 // //parentEl = xmldoc.addTextElementToData("ExampleTag", "parent-data");
84 // //xmldoc.addTextElementToParent("ExampleChild", "child-data", parentEl);
85 //
86 // //return xml doc holding server response
87 // //xmldoc.outputXmlDocument((std::ostringstream*) out, true); //true to
88 // also print to std::cout
89 // }
90 //
91 //
92 //========================================================================================================================
93 
94 RemoteWebUsers::RemoteWebUsers(xdaq::Application* application)
95  : SOAPMessenger(application)
96 {
97  ActiveUserLastUpdateTime_ = 0; // init to never
98  ActiveUserList_ = ""; // init to empty
99 }
100 
101 //========================================================================================================================
102 // xmlRequestGateway
103 // if false, user code should just return.. out is handled on false; on true, out is
104 // untouched
105 bool RemoteWebUsers::xmlRequestToGateway(cgicc::Cgicc& cgi,
106  std::ostringstream* out,
107  HttpXmlDocument* xmldoc,
108  const AllSupervisorInfo& allSupervisorInfo,
109  WebUsers::RequestUserInfo& userInfo)
110 {
111  //__COUT__ << std::endl;
112  // initialize user info parameters to failed results
113  WebUsers::initializeRequestUserInfo(cgi, userInfo);
114 
115  // const_cast away the const
116  // so that this line is compatible with slf6 and slf7 versions of xdaq
117  // where they changed to XDAQ_CONST_CALL xdaq::ApplicationDescriptor* in slf7
118  //
119  // XDAQ_CONST_CALL is defined in "otsdaq-core/Macros/CoutMacros.h"
120  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisor;
121 
122  SOAPParameters parameters;
123  xoap::MessageReference retMsg;
124 
125  //**** start LOGIN GATEWAY CODE ***//
126  // If TRUE, cookie code is good, and refreshed code is in cookieCode
127  // Else, error message is returned in cookieCode
128  // tmpCookieCode_ = CgiDataUtilities::getOrPostData(cgi,"CookieCode"); //from GET or
129  // POST
130 
131  // __COUT__ << cookieCode.length() << std::endl;
132  // __COUT__ << "cookieCode=" << cookieCode << std::endl;
133  //__COUT__ << std::endl;
134 
136  // have CookieCode, try it out
137  if(allSupervisorInfo.isWizardMode())
138  {
139  // if missing CookieCode... check if in Wizard mode and using sequence
140  std::string sequence =
141  CgiDataUtilities::getOrPostData(cgi, "sequence"); // from GET or POST
142  //__COUT__ << "sequence=" << sequence << std::endl;
143  if(!sequence.length())
144  {
145  __COUT_ERR__ << "Invalid access attempt (@" << userInfo.ip_ << ")."
146  << std::endl;
147  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
148  // invalid cookie and also invalid sequence
149  goto HANDLE_ACCESS_FAILURE; // return false, access failed
150  }
151 
152  // have sequence, try it out
153 
154  gatewaySupervisor = allSupervisorInfo.getWizardInfo().getDescriptor();
155  if(!gatewaySupervisor)
156  {
157  __COUT_ERR__ << "Missing wizard supervisor." << std::endl;
158  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
159  // sequence code present, but no wizard supervisor
160  goto HANDLE_ACCESS_FAILURE; // return false, access failed
161  }
162 
163  parameters.addParameter("sequence", sequence);
164  parameters.addParameter("IPAddress", userInfo.ip_);
165  retMsg = SOAPMessenger::sendWithSOAPReply(
166  gatewaySupervisor, "SupervisorSequenceCheck", parameters);
167  parameters.clear();
168  parameters.addParameter("Permissions");
169  SOAPUtilities::receive(retMsg, parameters);
170 
171  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
172 
173  if(WebUsers::checkRequestAccess(
174  cgi, out, xmldoc, userInfo, true /*isWizardMode*/))
175  return true;
176  else
177  goto HANDLE_ACCESS_FAILURE; // return false, access failed
178 
179  // if(userInfo.permissionLevel_ < userInfo.permissionsThreshold_)
180  // {
181  // *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
182  // __COUT__ << "User (@" << userInfo.ip_ << ") has insufficient
183  // permissions: " << userInfo.permissionLevel_ << "<" <<
184  // userInfo.permissionsThreshold_ << std::endl;
185  // return false; //invalid cookie and present sequence, but not correct
186  // sequence
187  // }
188  //
189  // userInfo.setUsername("admin");
190  // userInfo.setDisplayName("Admin");
191  // userInfo.setUsernameWithLock("admin");
192  // userInfo.setActiveUserSessionIndex(0);
193  // userInfo.setGroupMemebership("admin");
194  //
195  // return true; //successful sequence login!
196  }
197 
198  // else proceed with inquiry to Gateway Supervisor
199 
200  gatewaySupervisor = allSupervisorInfo.getGatewayInfo().getDescriptor();
201 
202  if(!gatewaySupervisor)
203  {
204  __COUT_ERR__ << "Missing gateway supervisor." << std::endl;
205  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
206  goto HANDLE_ACCESS_FAILURE; // return false, access failed
207  }
208 
209  //__COUT__ << std::endl;
210 
211  parameters.clear();
212  parameters.addParameter("CookieCode", userInfo.cookieCode_);
213  parameters.addParameter("RefreshOption", userInfo.automatedCommand_ ? "0" : "1");
214  parameters.addParameter("IPAddress", userInfo.ip_);
215 
216  retMsg = SOAPMessenger::sendWithSOAPReply(
217  gatewaySupervisor, "SupervisorCookieCheck", parameters);
218 
219  parameters.clear();
220  parameters.addParameter("CookieCode");
221  parameters.addParameter("Permissions");
222  parameters.addParameter("UserGroups");
223  parameters.addParameter("UserWithLock");
224  parameters.addParameter("Username");
225  parameters.addParameter("DisplayName");
226  parameters.addParameter("ActiveSessionIndex");
227  SOAPUtilities::receive(retMsg, parameters);
228 
229  //__COUT__ << std::endl;
230 
231  // first extract a few things always from parameters
232  // like permissionLevel for this request... must consider allowed groups!!
233  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
234  userInfo.cookieCode_ = parameters.getValue("CookieCode");
235  userInfo.username_ = parameters.getValue("Username");
236  userInfo.displayName_ = parameters.getValue("DisplayName");
237  userInfo.usernameWithLock_ = parameters.getValue("UserWithLock");
238  userInfo.activeUserSessionIndex_ =
239  strtoul(parameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
240 
241  if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
242  goto HANDLE_ACCESS_FAILURE; // return false, access failed
243  // else successful access request!
244 
245  return true; // request granted
246  // if(!userInfo.checkLock_ && !userInfo.requireLock_)
247  // return true; //done, no need to get user info for this cookie
248  // code
249  //
250 
252  // get user info for cookie code and check lock (now that username is available)
253 
254  // parameters.clear();
255  // parameters.addParameter("CookieCode",userInfo.cookieCode_);
256  // retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
257  // "SupervisorGetUserInfo", parameters);
258  //
259  // parameters.clear();
260  // parameters.addParameter("Username");
261  // parameters.addParameter("DisplayName");
262  // parameters.addParameter("ActiveSessionIndex");
263  // SOAPUtilities::receive(retMsg, parameters);
264 
265  // if(WebUsers::finalizeRequestAccess(out,xmldoc,userInfo,
266  // parameters.getValue("Username"),
267  // parameters.getValue("DisplayName"),
268  // strtoul(parameters.getValue("ActiveSessionIndex").c_str(),0,0)))
269  // return true;
270  // else
271  // goto HANDLE_ACCESS_FAILURE; //return false, access failed
272 
273 HANDLE_ACCESS_FAILURE:
274 
275  // print out return string on failure
276  if(!userInfo.automatedCommand_)
277  __COUT_ERR__ << "Failed request (requestType = " << userInfo.requestType_
278  << "): " << out->str() << __E__;
279  return false; // access failed
280 
281  // tmpUserWithLock_ = parameters.getValue("UserWithLock");
282  // tmpUserGroups_ = parameters.getValue("UserGroups");
283  // sscanf(parameters.getValue("Permissions").c_str(),"%hhu",&userInfo.permissionLevel_);
285  // userInfo.setGroupMemebership(parameters.getValue("UserGroups"));
286  // tmpCookieCode_ = parameters.getValue("CookieCode");
287 
288  // else access granted
289 
290  //__COUT__ << "cookieCode=" << cookieCode << std::endl;
291  //
292  // if(!allowNoUser && cookieCode.length() != WebUsers::COOKIE_CODE_LENGTH)
293  // {
294  // __COUT__ << "User (@" << ip << ") has invalid cookie code: " << cookieCode <<
295  // std::endl; *out << WebUsers::REQ_NO_LOGIN_RESPONSE; return false;
297  // }
298  //
299  // if(!allowNoUser && tmpUserPermissions_ < permissionsThreshold)
300  // {
301  // *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
302  // __COUT__ << "User (@" << ip << ") has insufficient permissions: " <<
303  // tmpUserPermissions_ << "<" << permissionsThreshold << std::endl;
304  // return false;
305  // }
306 
307  // check group membership
308  // if(!allowNoUser)
309  // {
310  // //check groups allowed
311  // // i.e. if user is a member of one of the groups allowed
312  // // then grant access
313  //
314  // std::set<std::string> userMembership;
315  // StringMacros::getSetFromString(
316  // tmpUserGroups_,
317  // userMembership);
318  //
319  // bool accept = false;
320  // for(const auto& userGroup:userMembership)
321  // if(StringMacros::inWildCardSet(
322  // userGroup,
323  // groupsAllowed))
324  // {
325  // accept = true;
326  // break;
327  // }
328  //
329  // if(!accept && userMembership.size())
330  // {
331  // *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
332  // std::stringstream ss;
333  // bool first = true;
334  // for(const auto& group:groupsAllowed)
335  // if(first && (first=false))
336  // ss << group;
337  // else
338  // ss << " | " << group;
339  //
340  // __COUT__ << "User (@" << ip << ") has insufficient group permissions: " <<
341  // tmpUserGroups_ << " != " << ss.str() << std::endl; return
342  // false;
343  // }
344  //
345  // //if no access groups specified, then check groups disallowed
346  // if(!userMembership.size())
347  // {
348  // for(const auto& userGroup:userMembership)
349  // if(StringMacros::inWildCardSet(
350  // userGroup,
351  // groupsDisallowed))
352  // {
353  // *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
354  // std::stringstream ss;
355  // bool first = true;
356  // for(const auto& group:groupsDisallowed)
357  // if(first && (first=false))
358  // ss << group;
359  // else
360  // ss << " | " << group;
361  //
362  // __COUT__ << "User (@" << ip << ") is in in a disallowed group
363  // permissions:
364  //" << tmpUserGroups_ << " == " << ss.str() << std::endl;
365  // return false;
366  // }
367  // }
368  // } //end group membership check
369  //
370  // if(xmldoc) //fill with cookie code tag
371  // {
372  // if(!allowNoUser)
373  // xmldoc->setHeader(cookieCode);
374  // else
375  // xmldoc->setHeader(WebUsers::REQ_ALLOW_NO_USER);
376  // }
377  //
378  //
379  //
380  // if(!userName && !displayName && !activeSessionIndex && !checkLock &&
382  //
383  // //__COUT__ << "User with Lock: " << tmpUserWithLock_ << std::endl;
384  //
385  //
386  // /////////////////////////////////////////////////////
387  // //get user info
388  // parameters.clear();
389  // parameters.addParameter("CookieCode",cookieCode);
390  // retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
391  // "SupervisorGetUserInfo", parameters);
392  //
393  // parameters.clear();
394  // parameters.addParameter("Username");
395  // parameters.addParameter("DisplayName");
396  // parameters.addParameter("ActiveSessionIndex");
397  // SOAPUtilities::receive(retMsg, parameters);
398  //
399  //
400  //
401  //
402  // userInfo.setActiveUserSessionIndex(0);
403  //
404  //
405  // tmpUsername_ = parameters.getValue("Username");
406  // userInfo.setUsername(tmpUsername_);
407  // userInfo.setDisplayName(parameters.getValue("DisplayName"));
408  // userInfo.setActiveUserSessionIndex(
409  // strtoul(parameters.getValue("ActiveSessionIndex").c_str(),0,0));
410  //
411  // if(userInfo.checkLock_ && tmpUserWithLock_ != "" && tmpUserWithLock_ !=
412  // tmpUsername_)
413  // {
414  // *out << WebUsers::REQ_USER_LOCKOUT_RESPONSE;
415  // __COUT__ << "User " << tmpUsername_ << " is locked out. " << tmpUserWithLock_
416  //<< " has lock." << std::endl; return false;
417  // }
418  //
419  // if(userInfo.lockRequired_ && tmpUserWithLock_ != tmpUsername_)
420  // {
421  // *out << WebUsers::REQ_LOCK_REQUIRED_RESPONSE;
422  // __COUT__ << "User " << tmpUsername_ << " must have lock to proceed. (" <<
423  // tmpUserWithLock_ << " has lock.)" << std::endl; return false;
424  // }
425  //
426  // return true;
427 }
428 
429 //========================================================================================================================
430 // getActiveUserList
431 // if lastUpdateTime is not too recent as spec'd by ACTIVE_USERS_UPDATE_THRESHOLD
432 // if server responds with
433 std::string RemoteWebUsers::getActiveUserList(
434  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor)
435 {
436  if(1 || time(0) - ActiveUserLastUpdateTime_ >
437  ACTIVE_USERS_UPDATE_THRESHOLD) // need to update
438  {
439  __COUT__ << "Need to update " << std::endl;
440 
441  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
442  supervisorDescriptor, "SupervisorGetActiveUsers");
443 
444  SOAPParameters retParameters("UserList");
445  SOAPUtilities::receive(retMsg, retParameters);
446 
447  ActiveUserLastUpdateTime_ = time(0);
448  return (ActiveUserList_ = retParameters.getValue("UserList"));
449  }
450  else
451  return ActiveUserList_;
452 }
453 
454 //========================================================================================================================
455 // getLastConfigGroup
456 // request last "Configured" or "Started" group, for example
457 // returns empty "" for actionTimeString on failure
458 // returns "Wed Dec 31 18:00:01 1969 CST" for actionTimeString (in CST) if action never
459 // has occurred
460 std::pair<std::string /*group name*/, TableGroupKey> RemoteWebUsers::getLastConfigGroup(
461  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
462  const std::string& actionOfLastGroup,
463  std::string& actionTimeString)
464 {
465  actionTimeString = "";
466  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
467  supervisorDescriptor,
468  "SupervisorLastConfigGroupRequest",
469  SOAPParameters("ActionOfLastGroup", actionOfLastGroup));
470 
471  SOAPParameters retParameters;
472  retParameters.addParameter("GroupName");
473  retParameters.addParameter("GroupKey");
474  retParameters.addParameter("GroupAction");
475  retParameters.addParameter("GroupActionTime");
476  SOAPUtilities::receive(retMsg, retParameters);
477 
478  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
479  if(retParameters.getValue("GroupAction") !=
480  actionOfLastGroup) // if action doesn't match.. weird
481  {
482  __COUT_WARN__ << "Returned group action '"
483  << retParameters.getValue("GroupAction")
484  << "' does not match requested group action '" << actionOfLastGroup
485  << ".'" << std::endl;
486  return theGroup; // return empty and invalid
487  }
488  // else we have an action match
489 
490  theGroup.first = retParameters.getValue("GroupName");
491  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(), 0, 0);
492  actionTimeString = retParameters.getValue("GroupActionTime");
493  return theGroup;
494 }
495 
496 //========================================================================================================================
497 // getUserInfoForCookie
498 // get username and display name for user based on cookie code
499 // return true, if user info gotten successfully
500 // else false
501 bool RemoteWebUsers::getUserInfoForCookie(
502  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
503  std::string& cookieCode,
504  std::string* userName,
505  std::string* displayName,
506  uint64_t* activeSessionIndex)
507 {
508  __COUT__ << std::endl;
509  if(cookieCode.length() != WebUsers::COOKIE_CODE_LENGTH)
510  return false; // return if invalid cookie code
511 
512  // SOAPParametersV parameters(1);
513  // parameters[0].setName("CookieCode"); parameters[0].setValue(cookieCode);
514  xoap::MessageReference retMsg =
515  SOAPMessenger::sendWithSOAPReply(supervisorDescriptor,
516  "SupervisorGetUserInfo",
517  SOAPParameters("CookieCode", cookieCode));
518 
519  SOAPParameters retParameters;
520  retParameters.addParameter("Username");
521  retParameters.addParameter("DisplayName");
522  retParameters.addParameter("ActiveSessionIndex");
523  SOAPUtilities::receive(retMsg, retParameters);
524  if(userName)
525  *userName = retParameters.getValue("Username");
526  if(displayName)
527  *displayName = retParameters.getValue("DisplayName");
528  if(activeSessionIndex)
529  *activeSessionIndex =
530  strtoul(retParameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
531 
532  __COUT__ << "userName " << *userName << std::endl;
533 
534  return true;
535 }
536 
537 //========================================================================================================================
538 // cookieCodeIsActiveForRequest
539 // for external supervisors to check with Supervisor for login
540 bool RemoteWebUsers::cookieCodeIsActiveForRequest(
541  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
542  std::string& cookieCode,
543  uint8_t* userPermissions,
544  std::string ip,
545  bool refreshCookie,
546  std::string* userWithLock)
547 {
548  //__COUT__ << "CookieCode: " << cookieCode << " " << cookieCode.length() << std::endl;
549  if(cookieCode.length() != WebUsers::COOKIE_CODE_LENGTH)
550  return false; // return if invalid cookie code
551 
552  //
553 
554  SOAPParameters parameters;
555  parameters.addParameter("CookieCode", cookieCode);
556  parameters.addParameter("RefreshOption", refreshCookie ? "1" : "0");
557 
558  //__COUT__ << "CookieCode: " << cookieCode << std::endl;
559  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
560  supervisorDescriptor, "SupervisorCookieCheck", parameters);
561 
562  SOAPParameters retParameters;
563  retParameters.addParameter("CookieCode");
564  retParameters.addParameter("Permissions");
565  retParameters.addParameter("UserWithLock");
566  SOAPUtilities::receive(retMsg, retParameters);
567 
568  if(userWithLock)
569  *userWithLock = retParameters.getValue("UserWithLock");
570  if(userPermissions)
571  sscanf(retParameters.getValue("Permissions").c_str(),
572  "%hhu",
573  userPermissions); // unsigned char
574 
575  cookieCode = retParameters.getValue("CookieCode");
576 
577  return cookieCode.length() ==
578  WebUsers::COOKIE_CODE_LENGTH; // proper cookieCode has length
579  // WebUsers::COOKIE_CODE_LENGTH
580 }
581 //========================================================================================================================
582 // sendSystemMessage
583 // send system message to toUser through Supervisor
584 // toUser wild card * is to all users
585 void RemoteWebUsers::sendSystemMessage(
586  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
587  const std::string& toUser,
588  const std::string& msg)
589 {
590  SOAPParameters parameters;
591  parameters.addParameter("ToUser", toUser);
592  parameters.addParameter("Message", msg);
593 
594  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
595  supervisorDescriptor, "SupervisorSystemMessage", parameters);
596 }
597 
598 //========================================================================================================================
599 // makeSystemLogbookEntry
600 // make system logbook through Supervisor
601 void RemoteWebUsers::makeSystemLogbookEntry(
602  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
603  const std::string& entryText)
604 {
605  SOAPParameters parameters;
606  parameters.addParameter("EntryText", entryText);
607 
608  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
609  supervisorDescriptor, "SupervisorSystemLogbookEntry", parameters);
610 }
bool xmlRequestToGateway(cgicc::Cgicc &cgi, std::ostringstream *out, HttpXmlDocument *xmldoc, const AllSupervisorInfo &allSupervisorInfo, WebUsers::RequestUserInfo &userInfo)