ARB
trackers.cxx
Go to the documentation of this file.
1 // ============================================================= //
2 // //
3 // File : trackers.cxx //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in March 2013 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // ============================================================= //
11 
12 #include "trackers.hxx"
13 #include "macros.hxx"
14 #include "recmac.hxx"
15 #include "dbserver.hxx"
16 
17 #include <aw_msg.hxx>
18 #include <arb_strarray.h>
19 #include <arb_sleep.h>
20 #include <ad_remote.h>
21 #include <unistd.h>
22 #include <ad_cb.h>
23 
24 bool BoundActionTracker::reconfigure(const char *application_id, GBDATA *IF_ASSERTION_USED(gb_main)) {
25  ma_assert(gb_main == gbmain);
26  ma_assert(strcmp(id, "ARB_IMPORT") == 0); // currently only ARB_IMPORT-tracker gets reconfigured
27  freedup(id, application_id);
28  return true;
29 }
30 
31 void BoundActionTracker::set_recording(bool recording) {
33  {
36  GBDATA *gb_recAuth = GB_searchOrCreate_int(get_gbmain(), remote.recAuth(), 0);
37 
38  if (!gb_recAuth) {
39  error = GB_await_error();
40  }
41  else {
42  pid_t pid = getpid();
43  pid_t recPid = GB_read_int(gb_recAuth);
44 
45  if (recording) {
46  if (recPid == 0) {
47  error = GB_write_int(gb_recAuth, pid); // allocate permission to record
48  }
49  else {
50  error = GBS_global_string("Detected two recording clients with id '%s'", get_application_id());
51  }
52  }
53  else {
54  if (recPid == pid) { // this is the authorized process
55  error = GB_write_int(gb_recAuth, 0); // clear permission
56  }
57  }
58  }
59 
60  if (error) {
61  error = GB_set_macro_error(get_gbmain(), error);
62  if (error) GBK_terminatef("Failed to set macro-error: %s", error);
63  }
64  }
65  set_tracking(recording);
66 }
67 
68 static GB_ERROR announce_recording(GBDATA *gb_main, int record) {
69  GB_transaction ta(gb_main);
70  GBDATA *gb_recording = GB_searchOrCreate_int(gb_main, MACRO_TRIGGER_RECORDING, record);
71  return gb_recording ? GB_write_int(gb_recording, record) : GB_await_error();
72 }
73 
74 GB_ERROR MacroRecorder::start_recording(const char *file, const char *stop_action_name, bool expand_existing) {
76  if (is_tracking()) error = "Already recording macro";
77  else {
78  recording = new RecordingMacro(file, get_application_id(), stop_action_name, expand_existing);
79  set_recording(true);
80 
81  error = recording->has_error();
82  if (!error) error = announce_recording(get_gbmain(), 1);
83  if (error) {
84  GB_ERROR stop_error = stop_recording();
85  if (stop_error) fprintf(stderr, "Error while stopping macro recording: %s\n", stop_error);
86  }
87  }
88  return error;
89 }
90 
93  if (!is_tracking()) {
94  error = "Not recording macro";
95  }
96  else {
97  error = recording->stop();
98 
99  delete recording;
100  recording = NULp;
101  set_recording(false);
102 
103  GB_ERROR ann_error = announce_recording(get_gbmain(), 0);
104  if (error) {
105  if (ann_error) fprintf(stderr, "Error in announce_recording: %s\n", ann_error);
106  }
107  else {
108  error = ann_error;
109  }
110  }
111  return error;
112 }
113 
114 static void getKnownMacroClients(ConstStrArray& clientNames, GBDATA *gb_main) {
115  GB_transaction ta(gb_main);
116 
117  GBDATA *gb_remote = GB_search(gb_main, REMOTE_BASE, GB_FIND);
118  GBDATA *gb_control = GB_search(gb_main, MACRO_TRIGGER_CONTAINER, GB_FIND);
119 
120  clientNames.erase();
121  if (gb_remote) {
122  for (GBDATA *gb_client = GB_child(gb_remote); gb_client; gb_client = GB_nextChild(gb_client)) {
123  if (gb_client != gb_control) {
124  const char *client_id = GB_read_key_pntr(gb_client);
125  clientNames.put(client_id);
126  }
127  }
128  }
129 }
130 __ATTR__USERESULT inline GB_ERROR setIntEntryToZero(GBDATA *gb_main, const char *entryPath) {
131  GBDATA *gbe = GB_search(gb_main, entryPath, GB_INT);
132  return gbe ? GB_write_int(gbe, 0) : GB_await_error();
133 }
134 
136  // clear all granted client authorizations
137  GB_transaction ta(gb_main);
138  GB_ERROR error = NULp;
139 
140  ConstStrArray clientNames;
141  getKnownMacroClients(clientNames, gb_main);
142 
143  for (size_t i = 0; i<clientNames.size() && !error; ++i) {
144  remote_awars remote(clientNames[i]);
145  error = setIntEntryToZero(gb_main, remote.authReq());
146  if (!error) error = setIntEntryToZero(gb_main, remote.authAck());
147  if (!error) error = setIntEntryToZero(gb_main, remote.granted());
148  // if (!error) error = setIntEntryToZero(gb_main, remote.recAuth()); // @@@ clear elsewhere
149  }
150  if (error) error = GBS_global_string("error in clearMacroExecutionAuthorization: %s", error);
151  return error;
152 }
153 
154 class ExecutingMacro : virtual Noncopyable {
155  RootCallback done_cb;
156 
157  ExecutingMacro *next;
158  static ExecutingMacro *head;
159 
160  ExecutingMacro(const RootCallback& execution_done_cb)
161  : done_cb(execution_done_cb),
162  next(head)
163  {
164  head = this;
165  }
166 
167  void call() const { done_cb(AW_root::SINGLETON); }
168  void destroy() { head = next; delete this; }
169 
170 public:
171 
172  static void add(const RootCallback& execution_done_cb) { new ExecutingMacro(execution_done_cb); }
173  static bool done() {
174  // returns true if the last macro (of all recursively called macros) terminates
175  if (head) {
176  head->call();
177  head->destroy();
178  }
179  return !is_active();
180  }
181  static void drop() {
182  if (head) head->destroy();
183  }
184  static bool is_active() {
185  // returns true if a macro is running.
186  return head != NULp;
187  }
188 };
189 
190 ExecutingMacro *ExecutingMacro::head = NULp;
191 
193  GB_transaction ta(gb_main);
194  GB_ERROR error = NULp;
195  GBDATA *gb_exec = GB_search(gb_main, MACRO_TRIGGER_EXECUTING, GB_FIND);
196 
197  if (gb_exec) {
198  error = GB_write_int(gb_exec, 0);
199  if (error) error = GBS_global_string("Warning: failed to clear macro execution flag (Reason: %s)", error);
200  }
201  // Note: interprets missing flag as "not set"
202 
203  error = ta.close(error);
204  return error;
205 }
206 
207 static void macro_terminated(GBDATA *gb_terminated, GB_CB_TYPE IF_ASSERTION_USED(cb_type)) {
208  ma_assert(cb_type == GB_CB_CHANGED);
209  fprintf(stderr, "macro_terminated called\n");
210  bool allMacrosTerminated = ExecutingMacro::done();
211  if (allMacrosTerminated) {
212  fprintf(stderr, "macro_terminated: allMacrosTerminated\n");
213  GBDATA *gb_main = GB_get_root(gb_terminated);
215  aw_message_if(error);
216 
217  // check for global macro error
218  GB_ERROR macro_error = GB_get_macro_error(gb_main);
219  if (macro_error) {
220  aw_message_if(macro_error);
221  aw_message("Warning: macro terminated (somewhere in the middle)");
222 
223  GB_ERROR clr_error = GB_clear_macro_error(gb_main);
224  if (clr_error) GB_informationf("Warning: failed to clear macro error (Reason: %s)\n", clr_error);
225  }
226 
227  GB_ERROR clr_error = clear_macro_execution_flag(gb_main);
228  aw_message_if(clr_error);
229  }
230 }
231 
232 GB_ERROR MacroRecorder::execute(const char *macroFile, bool loop_marked, const RootCallback& execution_done_cb) {
233  GB_ERROR error = NULp;
235  {
236  GB_transaction ta(gb_main);
237 
238  GBDATA *gb_term = GB_search(gb_main, MACRO_TRIGGER_TERMINATED, GB_FIND);
239  GBDATA *gb_exec = GB_search(gb_main, MACRO_TRIGGER_EXECUTING, GB_FIND);
240  if (!gb_term) {
241  gb_term = GB_search(gb_main, MACRO_TRIGGER_TERMINATED, GB_INT);
242  if (!gb_term) {
243  error = GB_await_error();
244  }
245  else {
246  error = GB_add_callback(gb_term, GB_CB_CHANGED, makeDatabaseCallback(macro_terminated));
247  }
248  if (!error) {
249  ma_assert(!gb_exec);
250  gb_exec = GB_search(gb_main, MACRO_TRIGGER_EXECUTING, GB_INT);
251  if (!gb_exec) error = GB_await_error();
252  }
253  }
254  if (!error) {
255  ma_assert(gb_exec);
256  error = GB_write_int(gb_exec, 1);
257  }
258  error = ta.close(error);
259  }
260 
261  if (!error) {
262  ExecutingMacro::add(execution_done_cb);
263  error = GBT_macro_execute(macroFile, loop_marked, true);
264  if (error) {
265  ExecutingMacro::drop(); // avoid double free
266  }
267  }
268 
269  if (error) {
270  GB_ERROR clr_error = clear_macro_execution_flag(gb_main);
271  if (clr_error) GB_information(clr_error);
272  }
273 
274  return error;
275 }
276 
277 void MacroRecorder::track_action(const char *action_id) {
279  recording->track_action(action_id);
280 }
281 
284  recording->track_awar_change(awar);
285 }
286 
288  ma_assert(tracked && tracked[0]);
289 
290  GB_ERROR error = NULp;
291  if (tracked && tracked[0]) {
292  char *saveptr = NULp;
293  const char *app_id = strtok_r(tracked, "*", &saveptr);
294  const char *cmd = strtok_r(NULp, "*", &saveptr);
295  char *rest = strtok_r(NULp, "", &saveptr);
296 
297  if (recording) {
298  if (strcmp(cmd, "AWAR") == 0) {
299  const char *awar_name = strtok_r(rest, "*", &saveptr);
300  const char *content = strtok_r(NULp, "", &saveptr);
301 
302  if (!content) content = "";
303 
304  recording->write_awar_change(app_id, awar_name, content);
305  }
306  else if (strcmp(cmd, "ACTION") == 0) {
307  recording->write_action(app_id, rest);
308  }
309  else {
310  error = GBS_global_string("Unknown client action '%s'", cmd);
311  }
312  }
313  else {
314  fprintf(stderr, "Warning: tracked action '%s' from client '%s' (dropped because not recording)\n", cmd, app_id);
315  }
316  }
317 
318  return error;
319 }
320 
321 void MacroRecorder::add_planned_interruption(const char *displayed_text) {
323  recording->write_planned_interruption(displayed_text);
324 }
325 
327  return ExecutingMacro::is_active();
328 }
329 
330 // -----------------------------
331 // ClientActionTracker
332 
334  bool recording = GB_read_int(gb_recording);
335  if (is_tracking() != recording) set_recording(recording);
336 }
337 
339  cat->set_tracking_according_to(gb_recording);
340 }
341 
342 void ClientActionTracker::bind_callbacks(bool install) {
344  GB_ERROR error = NULp;
346 
347  if (!gb_recording) {
348  error = GB_await_error();
349  }
350  else {
351  if (install) {
352  error = GB_add_callback(gb_recording, GB_CB_CHANGED, makeDatabaseCallback(record_state_changed_cb, this));
353  record_state_changed_cb(gb_recording, this); // call once
354  }
355  else {
356  GB_remove_callback(gb_recording, GB_CB_CHANGED, makeDatabaseCallback(record_state_changed_cb, this));
357  }
358  }
359 
360  if (error) {
361  aw_message(GBS_global_string("Failed to %s ClientActionTracker: %s", install ? "init" : "cleanup", error));
362  }
363 }
364 
365 
366 void ClientActionTracker::track_action(const char *action_id) {
367  if (!action_id) {
368  warn_unrecordable("anonymous GUI element");
369  }
370  else {
371  ma_assert(!strchr(action_id, '*'));
372  send_client_action(GBS_global_string("ACTION*%s", action_id));
373  }
374 }
375 
377  // see also recmac.cxx@AWAR_CHANGE_TRACKING
378 
379  char *svalue = awar->read_as_string();
380  if (!svalue) {
381  warn_unrecordable(GBS_global_string("change of '%s'", awar->awar_name));
382  }
383  else {
384  ma_assert(!strchr(awar->awar_name, '*'));
385  send_client_action(GBS_global_string("AWAR*%s*%s", awar->awar_name, svalue));
386  free(svalue);
387  }
388 }
389 
390 void ClientActionTracker::send_client_action(const char *action) {
391  // action is either
392  // "ACTION*<actionId>" or
393  // "AWAR*<awarName>*<awarValue>"
394 
395  // send action
396  GB_ERROR error;
397  GBDATA *gb_clientTrack = NULp;
398  {
399  error = GB_begin_transaction(get_gbmain());
400  if (!error) {
402  if (!gb_clientTrack) error = GB_await_error();
403  else {
404  const char *prev_track = GB_read_char_pntr(gb_clientTrack);
405 
406  if (!prev_track) error = GB_await_error();
407  else if (prev_track[0]) error = GBS_global_string("Cant send_client_action: have pending client action (%s)", prev_track);
408 
409  if (!error) {
410  ma_assert(!strchr(get_application_id(), '*'));
411  error = GB_write_string(gb_clientTrack, GBS_global_string("%s*%s", get_application_id(), action));
412  }
413  }
414  }
415  error = GB_end_transaction(get_gbmain(), error);
416  }
417 
418  if (!error) {
419  // wait for recorder to consume action
420  bool consumed = false;
421  int count = 0;
422  MacroTalkSleep increasing;
423 
424  while (!consumed && !error) {
425  increasing.sleep();
426  ++count;
427  if ((count%25) == 0) {
428  fprintf(stderr, "[Waiting for macro recorder to consume action tracked by %s]\n", get_application_id());
429  }
430 
431  error = GB_begin_transaction(get_gbmain());
432 
433  const char *track = GB_read_char_pntr(gb_clientTrack);
434  if (!track) error = GB_await_error();
435  else consumed = !track[0];
436 
437  error = GB_end_transaction(get_gbmain(), error);
438  }
439  }
440 
441  if (error) {
442  aw_message(GBS_global_string("Failed to record client action (Reason: %s)", error));
443  }
444 }
445 
446 void ClientActionTracker::ungrant_client_and_confirm_quit_action() {
447  // shutdown macro client
448  // - confirm action (needed in case the quit has been triggered by a macro; otherwise macro hangs forever)
449  // - unauthorize this process for macro execution
450 
452  GB_transaction ta(gb_main);
454  GB_ERROR error = NULp;
455 
456  GBDATA *gb_granted = GB_search(gb_main, remote.granted(), GB_FIND);
457  if (gb_granted) {
458  pid_t pid = getpid();
459  pid_t granted_pid = GB_read_int(gb_granted);
460 
461  if (pid == granted_pid) { // this is the client with macro execution rights
462  GBDATA *gb_action = GB_search(gb_main, remote.action(), GB_FIND);
463  if (gb_action) error = GB_write_string(gb_action, ""); // signal macro, that action was executed
464  if (!error) error = GB_write_int(gb_granted, 0); // un-authorize this process
465  }
466  }
467 
468  if (error) {
469  error = GB_set_macro_error(gb_main, GBS_global_string("error during client quit: %s", error));
470  if (error) fprintf(stderr, "Error in ungrant_client_and_confirm_quit_action: %s\n", error);
471  }
472 
473  if (is_tracking()) set_recording(false);
474 }
475 
476 // -------------------------
477 // tracker factory
478 
479 static UserActionTracker *make_macro_recording_tracker(const char *client_id, GBDATA *gb_main) {
480  // 'client_id' has to be a unique id (used to identify the program which will record/playback).
481  // If multiple programs (or multiple instances of one) use the same id, macro recording shall abort.
482  // If a program is used for different purposes by starting multiple instances (like e.g. arb_ntree),
483  // each purpose/instance should use a different 'client_id'.
484 
485  ma_assert(gb_main);
486  ma_assert(client_id && client_id[0]);
487 
488  BoundActionTracker *tracker;
489  if (GB_is_server(gb_main)) {
490  tracker = new MacroRecorder(client_id, gb_main);
491  }
492  else {
493  tracker = new ClientActionTracker(client_id, gb_main);
494  }
495  return tracker;
496 }
497 
499  return new RequiresActionTracker;
500 }
501 
502 GB_ERROR configure_macro_recording(AW_root *aw_root, const char *client_id, GBDATA *gb_main) {
503  ma_assert(aw_root);
504 
506  GB_ERROR error = NULp;
507  if (existing && existing->reconfigure(client_id, gb_main)) {
508  error = reconfigure_dbserver(client_id, gb_main);
509  }
510  else {
511  aw_root->setUserActionTracker(make_macro_recording_tracker(client_id, gb_main));
512  error = startup_dbserver(aw_root, client_id, gb_main);
513  }
514 
515  return error;
516 }
517 
520  if (tracker) tracker->release();
521 }
522 
523 bool got_macro_ability(AW_root *aw_root) {
524  // return true if aw_root has a BoundActionTracker
525  return get_active_macro_recording_tracker(aw_root);
526 }
527 
#define ma_assert(bed)
Definition: macro_gui.cxx:28
GB_ERROR GB_begin_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2528
void track_action(const char *action_id)
Definition: recmac.cxx:161
const char * GB_ERROR
Definition: arb_core.h:25
GB_ERROR start_recording(const char *file, const char *stop_action_name, bool expand_existing)
Definition: trackers.cxx:74
#define MACRO_TRIGGER_TRACKED
Definition: arbdbt.h:28
bool is_executing_macro() const
Definition: trackers.cxx:326
void put(const char *elem)
Definition: arb_strarray.h:188
size_t size() const
Definition: arb_strarray.h:85
GB_ERROR GB_set_macro_error(GBDATA *gb_main, const char *curr_error)
Definition: adtools.cxx:670
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:729
GBDATA * GB_child(GBDATA *father)
Definition: adquery.cxx:322
static void macro_terminated(GBDATA *gb_terminated, GB_CB_TYPE cb_type)
Definition: trackers.cxx:207
bool is_tracking() const
Definition: aw_root.hxx:70
bool GB_is_server(GBDATA *gbd)
Definition: adcomm.cxx:1697
const char * granted() const
Definition: ad_remote.h:80
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
GBDATA * GB_searchOrCreate_string(GBDATA *gb_container, const char *fieldpath, const char *default_value)
Definition: adquery.cxx:546
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:356
void track_awar_change(AW_awar *awar)
Definition: recmac.cxx:180
GB_ERROR GBT_macro_execute(const char *macro_name, bool loop_marked, bool run_async)
Definition: adtools.cxx:919
static GB_ERROR clear_macro_execution_flag(GBDATA *gb_main)
Definition: trackers.cxx:192
GB_ERROR GB_end_transaction(GBDATA *gbd, GB_ERROR error)
Definition: arbdb.cxx:2561
GB_ERROR execute(const char *macroFile, bool loop_marked, const RootCallback &execution_done_cb)
Definition: trackers.cxx:232
void sleep()
Definition: arb_sleep.h:94
static UserActionTracker * make_macro_recording_tracker(const char *client_id, GBDATA *gb_main)
Definition: trackers.cxx:479
const char * authAck() const
Definition: ad_remote.h:79
#define MACRO_TRIGGER_TERMINATED
Definition: arbdbt.h:24
void track_awar_change(AW_awar *awar) OVERRIDE
Definition: trackers.cxx:282
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
void track_awar_change(AW_awar *awar) OVERRIDE
Definition: trackers.cxx:376
UserActionTracker * need_macro_ability()
Definition: trackers.cxx:498
void track_action(const char *action_id) OVERRIDE
Definition: trackers.cxx:277
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
void shutdown_macro_recording(AW_root *aw_root)
Definition: trackers.cxx:518
static bool is_active()
Definition: trackers.cxx:184
const char * authReq() const
Definition: ad_remote.h:78
#define MACRO_TRIGGER_EXECUTING
Definition: arbdbt.h:26
virtual void release()=0
GB_ERROR stop()
Definition: recmac.cxx:199
void setUserActionTracker(UserActionTracker *user_tracker)
Definition: AW_root.cxx:210
GB_ERROR reconfigure_dbserver(const char *application_id, GBDATA *gb_main)
Definition: dbserver.cxx:298
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
static AW_root * SINGLETON
Definition: aw_root.hxx:102
void add_planned_interruption(const char *displayed_text)
Definition: trackers.cxx:321
void track_action(const char *action_id) OVERRIDE
Definition: trackers.cxx:366
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1656
void set_tracking_according_to(GBDATA *gb_recording)
Definition: trackers.cxx:333
static void add(const RootCallback &execution_done_cb)
Definition: trackers.cxx:172
bool got_macro_ability(AW_root *aw_root)
Definition: trackers.cxx:523
static void error(const char *msg)
Definition: mkptypes.cxx:96
GBDATA * GB_get_root(GBDATA *gbd)
Definition: arbdb.cxx:1740
GBDATA * GB_searchOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value)
Definition: adquery.cxx:569
char * read_as_string() const
static __ATTR__USERESULT GB_ERROR clearMacroExecutionAuthorization(GBDATA *gb_main)
Definition: trackers.cxx:135
bool reconfigure(const char *application_id, GBDATA *gb_main)
Definition: trackers.cxx:24
static void record_state_changed_cb(GBDATA *gb_recording, ClientActionTracker *cat)
Definition: trackers.cxx:338
void write_awar_change(const char *app_id, const char *awar_name, const char *content)
Definition: recmac.cxx:144
#define REMOTE_BASE
Definition: arbdbt.h:22
static GB_ERROR announce_recording(GBDATA *gb_main, int record)
Definition: trackers.cxx:68
GB_ERROR startup_dbserver(AW_root *aw_root, const char *application_id, GBDATA *gb_main)
Definition: dbserver.cxx:258
static void getKnownMacroClients(ConstStrArray &clientNames, GBDATA *gb_main)
Definition: trackers.cxx:114
Definition: arbdb.h:86
#define MACRO_TRIGGER_CONTAINER
Definition: arbdbt.h:23
static char * cat(char *toBuf, const char *s1, const char *s2)
Definition: ED4_root.cxx:1023
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1250
static void drop()
Definition: trackers.cxx:181
void set_recording(bool recording)
Definition: trackers.cxx:31
char * awar_name
Definition: aw_awar.hxx:103
void write_planned_interruption(const char *displayed_text)
Definition: recmac.cxx:153
GB_ERROR configure_macro_recording(AW_root *aw_root, const char *client_id, GBDATA *gb_main)
Definition: trackers.cxx:502
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:35
static bool done()
Definition: trackers.cxx:173
const char * get_application_id() const
Definition: trackers.hxx:67
GB_ERROR handle_tracked_client_action(char *&tracked)
Definition: trackers.cxx:287
#define __ATTR__USERESULT
Definition: attributes.h:58
#define MACRO_TRIGGER_RECORDING
Definition: arbdbt.h:25
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:360
BoundActionTracker * get_active_macro_recording_tracker(AW_root *aw_root)
Definition: trackers.hxx:143
void write_action(const char *app_id, const char *action_name)
Definition: recmac.cxx:104
void aw_message(const char *msg)
Definition: AW_status.cxx:1142
const char * recAuth() const
Definition: ad_remote.h:82
GB_ERROR GB_clear_macro_error(GBDATA *gb_main)
Definition: adtools.cxx:699
#define NULp
Definition: cxxforward.h:116
void GB_information(const char *message)
Definition: arb_msg.cxx:548
GB_ERROR stop_recording()
Definition: trackers.cxx:91
void GB_informationf(const char *templat,...)
Definition: arb_msg.cxx:555
__ATTR__USERESULT GB_ERROR setIntEntryToZero(GBDATA *gb_main, const char *entryPath)
Definition: trackers.cxx:130
GB_ERROR has_error() const
Definition: recmac.hxx:52
GBDATA * GB_nextChild(GBDATA *child)
Definition: adquery.cxx:326
void warn_unrecordable(const char *what)
Definition: recmac.cxx:30
GBDATA * get_gbmain()
Definition: trackers.hxx:66
GB_transaction ta(gb_var)
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:904
GBDATA * gb_main
Definition: adname.cxx:32
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
GB_CB_TYPE
Definition: arbdb_base.h:46
GB_ERROR GB_get_macro_error(GBDATA *gb_main)
Definition: adtools.cxx:687
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
Definition: arbdb.h:66