liboaa.c

Go to the documentation of this file.
00001 /****************************************************************************
00002  *   File    : liboaa.c
00003  *   Author  : Adam Cheyer, David Martin
00004  *   Purpose : Contains C version of library for the Open Agent Architecture
00005  *   Updated : 5/21/97
00006  */
00007 /*
00008  * Copyright (C) 2006  SRI International
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00023  *
00024  * SRI International: 333 Ravenswood Ave, Menlo Park, CA 94025
00025  */
00026  /*
00027  ****************************************************************************
00028  * Note: internal functions use the naming convention oaa_function_name(),
00029  *     while public predicates use oaa_PublicPredicate().
00030  *****************************************************************************/
00031 #define EXPORT_BORLAND
00032 
00033 #ifdef IS_DLL
00034 #define EXPORT_MSCPP __declspec(dllexport)
00035 #else
00036 #define EXPORT_MSCPP
00037 #endif
00038 
00039 
00040 /****************************************************************************
00041  * RCS Header
00042  ****************************************************************************/
00043 #ifndef lint
00044 /*static char *rcsid= "$Header: /home/zuma1/OAA/CVSRepository/oaa2/src/oaalib/c/src/liboaa.c,v 1.77 2006/12/20 15:21:21 agno Exp $";*/
00045 #endif
00046 
00047 
00048 /****************************************************************************
00049  *Include files
00050  ****************************************************************************/
00051 
00052 #include <string.h> /* string functions     */
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 
00056 #ifndef _WINDOWS
00057 #include <sys/param.h>  /* used by getlocalhostname     */
00058 #include <sys/time.h>   /* used by oaa_Ping     */
00059 #include <stdarg.h>   /* used by oaa_Ping   */
00060 #else
00061 #include <time.h>   /* used by oaa_Ping     */
00062 #include <stdarg.h>   /* used by oaa_Ping   */
00063 #include <windows.h>   /* used by oaa_Ping    */
00064 #include <winsock.h> /* bzero, bcopy */
00065 #endif
00066 
00067 #include "libicl_private.h"
00068 #include "libicl.h" /* ICL term parsing/generating library  */
00069 #include "libdb.h"  /* Database library       */
00070 #include "libcom_tcp.h" /* coms library       */
00071 #include "liboaa.h" /* OAA library headers      */
00072 #include "dictionary.h" /* utility collection data type */
00073 #include "testers.h"
00074 
00075 /* Some param.h versions don't have this defined? */
00076 #ifndef MAXHOSTNAMELEN
00077 #define MAXHOSTNAMELEN 256
00078 #endif
00079 
00080 // forward declarations
00081 int oaa_SeqNumLessThan(int a, int b);
00082 
00083 /****************************************************************************
00084  * Global variables
00085  ****************************************************************************/
00086 
00087 char const* oaa_library_version_str = "[2,3,2]";
00088 
00089 /* DEBUG */
00090 extern ICLDatabase *commdb;
00091 
00092 static ICLTerm  *oaa_solvables = NULL;                /* list of agent capabilities */
00093 static int      oaa_trace_on  = FALSE;      /* Tracing on         */
00094 static int      oaa_com_trace_on  = FALSE;  /* COM Tracing on         */
00095 static int      oaa_debug_on  = FALSE;      /* Debugging on       */
00096 static double   oaa_timeout = 0.0;          /* Idle timeout value */
00097 
00098 /* Queue of events    */
00099 ICLTerm  *oaa_saved_events = NULL;
00100 
00101 static ICLDatabase *local_db = NULL;                  /* C equivalent of prolog db */
00102 
00103 /* This list contains the terms to be printed by oaa_TraceMsg */
00104 /*static ICLTerm* trace_messages_list = NULL;*/
00105 
00106 static char * oaa_built_in_solvables_str =
00107 "[solvable(oaa_trigger(_TriggerId, _Type, _Condition, _Action, _Params), [type(data)], [write(true)])]";
00108 
00109 static ICLTerm *oaa_built_in_solvables_term = NULL;
00110 
00111 static ICLTerm* oaa_outSeqNum_matcher = NULL;
00112 
00113 static ICLTerm* oaa_lastSeenSeqNum_matcher = NULL;
00114 
00115 int oaa_argc = 0;
00116 char** oaa_argv = NULL;
00117 
00118 /* For unique goal and trigger IDs */
00119 static int globalCounter = 1;
00120 
00121 /*
00122 ************************  TABLES   *****************************
00123 * these substitute for various lists of things that are
00124 * stored in the generic database in the prolog version.
00125 */
00126 
00127 /*
00128  * context_table is used to store current contexts in the absence of
00129  * asserta and retract predicates
00130  */
00131 static DICTIONARY *context_table = (DICTIONARY *)NULL;
00132 /*
00133  * oaa_delay is a table to record requests for delayed solutions to particular
00134  * goals
00135  */
00136 static DICTIONARY *oaa_delay = (DICTIONARY *)NULL;
00137 /*
00138  * oaa_delay_table records the detailed results of a delayed goal
00139  */
00140 static DICTIONARY *oaa_delay_table = (DICTIONARY *)NULL;
00141 /*
00142  * oaa_callback stores asserted callbacks.  takes the place of
00143  * oaa_callback/2 predicates
00144  */
00145 static DICTIONARY *oaa_callback = (DICTIONARY *)NULL;
00146 /*
00147  * oaa_cache stores cached solutions.  This is a alternative to asserting
00148  * oaa_cache(Goal,Solutions) terms in the general DB.
00149  */
00150 static DICTIONARY *oaa_cache = (DICTIONARY *)NULL;
00151 /*
00152  * oaa_waiting_for is used to associate event lists with unique ids
00153  */
00154 static DICTIONARY *oaa_waiting_for = (DICTIONARY *)NULL;
00155 /*
00156  * oaa_waiting_event stores the events themselves
00157  */
00158 static DICTIONARY *oaa_waiting_event = (DICTIONARY *)NULL;
00159 
00164 EXTERN int oaa_Init(int argc, char* argv[]) {
00165   oaa_argc = argc;
00166   oaa_argv = argv;
00167   return TRUE;
00168 }
00169 
00170 static ICLTerm* getEvSolvedGoal(ICLTerm* goal)
00171 {
00172   static int useVar = -1;
00173   ICLTerm* resolved;
00174   if(useVar == -1) {
00175     if(oaa_ResolveVariable("return_goal_with_solutions", &resolved)) {
00176       if(resolved && icl_IsStr(resolved) && strcmp("true", icl_Str(resolved))) {
00177         useVar = 0;
00178       }
00179       else {
00180         useVar = 1;
00181       }
00182       icl_Free(resolved);
00183     }
00184     else {
00185       useVar = 1;
00186     }
00187   }
00188 
00189   if(useVar) {
00190     return icl_NewVar("_");
00191   }
00192   else {
00193     return icl_CopyTerm(goal);
00194   }
00195 }
00196 
00201 int oaa_compare_terms(void *t1, void *t2) {
00202   ICLTerm *term1 = (ICLTerm *)t1;
00203   ICLTerm *term2 = (ICLTerm *)t2;
00204 
00205   /* DEBUG */
00206   /*
00207     printDebug(1, "oaa_compare_terms : %s VS %s \n",
00208     icl_NewStringFromTerm(term1),
00209     icl_NewStringFromTerm(term2));
00210   */
00211 
00212   if(icl_Unify(term1, term2, NULL)) {
00213     return 1;
00214   }
00215   return 0;
00216 }
00217 
00223 int oaa_assert_current_contexts(ICLTerm *id, ICLTerm *contexts) {
00224   /*
00225    * if this is the first use of this function, create a dictionary
00226    * that uses unification to determine key equivalency
00227    */
00228   if(context_table == NULL)
00229     context_table = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
00230   dict_put_nonunique(context_table, (void *)icl_CopyTerm(id), (void *)contexts);
00231   return TRUE;
00232 }
00233 
00239 int oaa_retrieve_current_contexts(ICLTerm *id, ICLTerm **contexts) {
00240   if(context_table != NULL) {
00241     *contexts = (ICLTerm *)dict_get(context_table, (void *)id);
00242     if(*contexts)
00243       return TRUE;
00244   }
00245   return FALSE;
00246 }
00247 
00254 int oaa_retrieve_nth_current_contexts(ICLTerm **id, ICLTerm **contexts,
00255                                       int n) {
00256   /*
00257    * if this is the first use of this function, create a dictionary
00258    * that uses unification to determine key equivalency
00259    */
00260   if(context_table != NULL) {
00261     if(dict_get_nth(context_table, (void **)id, (void **)contexts, n))
00262       return TRUE;
00263   }
00264   return FALSE;
00265 }
00266 
00272 int oaa_retractall_current_contexts(ICLTerm *id) {
00273   if(context_table != NULL) {
00274     void **values;
00275     int    num_found, i;
00276 
00277     values = dict_remove_all(context_table, id, &num_found);
00278     if (values != NULL) {
00279       for (i=0; i<num_found; i++) {
00280   free((values[i]));
00281       }
00282       free(values);
00283       return TRUE;
00284     }
00285   }
00286   return FALSE;
00287 }
00288 
00293 int oaa_assert_delay(ICLTerm *id, ICLTerm *user_id) {
00294   if(oaa_delay == NULL) {
00295     oaa_delay = dict_new(oaa_compare_terms, NULL);
00296   }
00297   dict_put(oaa_delay, (void *)id, (void *)user_id);
00298   return TRUE;
00299 }
00300 
00305 int oaa_retract_delay(ICLTerm *id, ICLTerm **user_id) {
00306   if(oaa_delay != NULL) {
00307     *user_id = (ICLTerm *)dict_remove(oaa_delay, (void *)id);
00308     if(*user_id)
00309       return TRUE;
00310   }
00311   return FALSE;
00312 }
00313 
00317 int oaa_assert_delay_table(ICLTerm *goal_id, ICLTerm *user_id,
00318                            ICLTerm *full_goal, ICLTerm *solve_params,
00319                            ICLTerm *all_params) {
00320   ICLTerm *value_list = icl_NewList(NULL);
00321   /* first make sure the table exists */
00322   if(oaa_delay_table == NULL) {
00323     oaa_delay_table = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
00324   }
00325   /*
00326    * Now make a list out of the value terms.  Lookups will be done based
00327    * on the user_id, so make that the key and put the rest of the terms
00328    * into a list
00329    */
00330   icl_AddToList(value_list, goal_id, TRUE);
00331   icl_AddToList(value_list, full_goal, TRUE);
00332   icl_AddToList(value_list, solve_params, TRUE);
00333   icl_AddToList(value_list, all_params, TRUE);
00334   /*
00335    * put nonunique since there may be more than one delayed solution
00336    * per user_id
00337    */
00338   dict_put_nonunique(oaa_delay_table, (void *)icl_CopyTerm(user_id), (void *)value_list);
00339   return TRUE;
00340 }
00341 
00346 int oaa_retract_delay_table(ICLTerm **goal_id, ICLTerm *user_id,
00347                             ICLTerm **full_goal, ICLTerm **solve_params,
00348                             ICLTerm **all_params) {
00349   /* first make sure the table exists */
00350   if(oaa_delay_table != NULL) {
00351     ICLTerm *value_list =
00352       dict_remove(oaa_delay_table, (void *)user_id);
00353     if(value_list) {
00354       *goal_id = icl_CopyTerm(icl_NthTerm(value_list, 1));
00355       *full_goal = icl_CopyTerm(icl_NthTerm(value_list, 2));
00356       *solve_params = icl_CopyTerm(icl_NthTerm(value_list, 3));
00357       *all_params = icl_CopyTerm(icl_NthTerm(value_list, 4));
00358       icl_Free(value_list);
00359       return TRUE;
00360     }
00361   }
00362   return FALSE;
00363 }
00364 
00368 int oaa_assert_callback(ICLTerm *id, int (*user_callback)(ICLTerm*, ICLTerm*, ICLTerm*)) {
00369   {
00370     ICLTerm *key;
00371     if(oaa_callback == NULL) {
00372       oaa_callback = dict_new(oaa_compare_terms, NULL);
00373     }
00374     if(dict_index_for_key(oaa_callback, id) >= 0) {
00375       key = id;
00376     }
00377     else {
00378       key = icl_CopyTerm(id);
00379     }
00380     dict_put(oaa_callback, key, user_callback);
00381   }
00382   CHECK_LEAKS();
00383   return TRUE;
00384 }
00385 
00389 int oaa_retrieve_callback(ICLTerm *id,  int (**user_callback)(ICLTerm*, ICLTerm*, ICLTerm*)) {
00390   if(oaa_callback != NULL) {
00391     *user_callback = dict_get(oaa_callback, (void*)id);
00392     if(*user_callback) {
00393       return TRUE;
00394     }
00395   }
00396   return FALSE;
00397 }
00398 
00402 int oaa_retract_callback(ICLTerm *id, int (*user_callback)(ICLTerm*, ICLTerm*, ICLTerm*)) {
00403   if(oaa_callback != NULL) {
00404     user_callback = dict_remove(oaa_callback, (void *)id);
00405     if(user_callback != NULL) {
00406       return TRUE;
00407     }
00408   }
00409   return FALSE;
00410 }
00411 
00415 int oaa_retractall_callback(ICLTerm *id, ICLTerm **proc) {
00416 
00417   if(oaa_callback != NULL) {
00418     void **values;
00419     int    num_found, i;
00420 
00421     values = dict_remove_all(oaa_callback, id, &num_found);
00422     if (values != NULL) {
00423       *proc = (ICLTerm *)*values; /* ?? */
00424       for (i=0; i<num_found; i++) {
00425         free((values[i]));
00426       }
00427       free(values);
00428       return TRUE;
00429     }
00430   }
00431   return FALSE;
00432 }
00433 
00437 int oaa_assert_cache(ICLTerm *goal, ICLTerm *solutions) {
00438   if(oaa_cache == NULL) {
00439     oaa_cache = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
00440   }
00441   dict_put_nonunique(oaa_cache, (void *)icl_CopyTerm(goal), (void *)solutions);
00442   return TRUE;
00443 }
00444 
00448 int oaa_retrieve_cache(ICLTerm *goal, ICLTerm **solutions) {
00449   if(oaa_cache != NULL) {
00450     *solutions = (ICLTerm *)dict_get(oaa_cache, (void *)goal);
00451     if(*solutions != NULL) {
00452       return TRUE;
00453     }
00454   }
00455   return FALSE;
00456 }
00457 
00462 int oaa_retractall_cache(ICLTerm *goal) {
00463 
00464   if(oaa_cache != NULL) {
00465     int    num_found = 0;
00466     int    i = 0;
00467     void **values = dict_remove_all(oaa_cache, goal, &num_found);
00468 
00469     if (values != NULL) {
00470       for (i=0; i<num_found; i++) {
00471         free((values[i]));
00472       }
00473       free(values);
00474       return TRUE;
00475     }
00476   }
00477   return FALSE;
00478 }
00479 
00483 int oaa_retrieve_all_cache(ICLTerm *goal, ICLTerm **solutions) {
00484   int i = 0, n = 0, inited = FALSE, res = FALSE;
00485   if(oaa_cache != NULL) {
00486     /* loop through cache table */
00487     for(i=0, n=oaa_cache->size; i<n; i++) {
00488       ICLTerm *test_goal = oaa_cache->key[i];
00489       /* compare keys */
00490       if(!(oaa_cache->compar)((void *)goal, (void *)test_goal)) {
00491         ICLTerm *tmpsoln = oaa_cache->value[i];
00492         /* add tmpsoln to solutions list */
00493         if(inited)
00494           icl_AddToList(*solutions, tmpsoln, TRUE);
00495         else {
00496           *solutions = icl_NewList(icl_NewCons(tmpsoln, NULL));
00497           inited = TRUE;
00498         }
00499         res = TRUE;
00500       }
00501     }
00502   }
00503   return res;
00504 }
00505 
00509 int oaa_retract_cache(ICLTerm *goal, ICLTerm **solutions) {
00510   if(oaa_cache != NULL) {
00511     *solutions = (ICLTerm *)dict_remove(oaa_cache, (void *)goal);
00512     if(*solutions != NULL) {
00513       return TRUE;
00514     }
00515   }
00516   return FALSE;
00517 }
00518 
00522 int oaa_assert_waiting_for(ICLTerm *id, ICLTerm *event_list) {
00523   if(oaa_waiting_for == NULL)
00524     oaa_waiting_for = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
00525   dict_put(oaa_waiting_for, (void *)icl_CopyTerm(id), (void *)event_list);
00526   return TRUE;
00527 }
00528 
00532 int oaa_retrieve_waiting_for(ICLTerm *id, ICLTerm **event_list) {
00533   if(oaa_waiting_for != NULL) {
00534     *event_list = (ICLTerm *)dict_get(oaa_waiting_for, (void *)id);
00535     if(*event_list != NULL) {
00536       return TRUE;
00537     }
00538   }
00539   return FALSE;
00540 }
00541 
00545 int oaa_retrieve_all_waiting_for(ICLTerm *id, ICLTerm **event_list) {
00546   int res = FALSE, inited = FALSE, i = 0, n = 0;
00547   if(oaa_waiting_for != NULL) {
00548     for(i=0, n=oaa_waiting_for->size; i<n; i++) {
00549       ICLTerm *test_id = oaa_waiting_for->key[i];
00550       /* compare keys */
00551       if((oaa_waiting_for->compar)((void *)id, (void *)test_id)) {
00552         ICLTerm *tmpel = oaa_waiting_for->value[i];
00553         /* add tmpel to events list */
00554         if(inited) {
00555           icl_AppendCopy(*event_list, tmpel);
00556         }
00557         else {
00558           *event_list = icl_CopyTerm(tmpel);
00559           inited = TRUE;
00560         }
00561         res = TRUE;
00562       }
00563     }
00564   }
00565   return res;
00566 }
00567 
00568 
00572 int oaa_retract_waiting_for(ICLTerm *id, ICLTerm **event_list) {
00573   if(oaa_waiting_for != NULL) {
00574     *event_list = (ICLTerm *)dict_remove(oaa_waiting_for, (void *)id);
00575     if(*event_list != NULL) {
00576       return TRUE;
00577     }
00578   }
00579   return FALSE;
00580 }
00581 
00585 int oaa_assert_waiting_event(ICLTerm *event){
00586   if(oaa_waiting_event == NULL) {
00587     oaa_waiting_event = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
00588   }
00589   /* store term under both key and value */
00590   dict_put(oaa_waiting_event, (void *)icl_CopyTerm(event), (void *)icl_CopyTerm(event));
00591   return TRUE;
00592 }
00593 
00597 int oaa_retrieve_all_waiting_events(ICLTerm **event_list) {
00598   int i = 0, n = 0;
00599   *event_list = icl_NewList(NULL);
00600   if(oaa_waiting_event != NULL) {
00601     for(i=0, n=oaa_waiting_event->size; i<n; i++) {
00602       ICLTerm *event = oaa_waiting_event->value[i];
00603       /* add event to events list */
00604       icl_AddToList(*event_list, icl_CopyTerm(event), TRUE);
00605     }
00606   }
00607   return TRUE;
00608 }
00609 
00610 
00614 int oaa_retract_waiting_event(ICLTerm *event) {
00615   ICLTerm *retracted = NULL;
00616   if(oaa_waiting_event != NULL) {
00617     retracted = (ICLTerm *)dict_remove(oaa_waiting_event, (void *)event);
00618     if(retracted != NULL) {
00619       icl_Free(retracted);
00620       return TRUE;
00621     }
00622   }
00623   return FALSE;
00624 }
00625 
00629 ICLTerm * oaa_built_in_solvables()
00630 {
00631   if (oaa_built_in_solvables_term == NULL) {
00632     oaa_built_in_solvables_term =
00633       icl_NewTermFromString(oaa_built_in_solvables_str);
00634   }
00635 
00636   return oaa_built_in_solvables_term;
00637 }
00638 
00639 
00640 /*****************************************************************************
00641  * Forward function declarations
00642  *****************************************************************************/
00643 
00644 EXTERN void icl_param_standard_form(ICLTerm *param, ICLListType **SList);
00645 EXTERN int icl_param_default(ICLTerm *param, ICLTerm **result);
00646 EXTERN void icl_perm_standard_form(ICLTerm *perm, ICLTerm **Standard);
00647 EXTERN int icl_perm_default(ICLTerm *perm, ICLTerm **result);
00648 EXTERN int icl_address_to_id(ICLTerm* inFullAddress, ICLTerm** result);
00649 EXTERN int icl_standardize_address(ICLTerm *Addr, ICLTerm **StandardAddr);
00650 EXTERN int icl_standardize_solvables(ICLTerm *ShorthandSolvables, ICLTerm **StandardSolvables);
00651 EXTERN int icl_readable_solvables(ICLTerm *StandardSolvables, ICLTerm **ShorthandSolvables);
00652 EXTERN int icl_readable_solvable(ICLTerm *StandardSolvable, ICLTerm **ShorthandSolvable);
00653 EXTERN int oaa_goal_in_solvables(ICLTerm *Goal, ICLTerm *Solvables, ICLTerm **MatchedSolvable);
00654 EXTERN int oaa_call_callback(char* callback_id, ICLTerm *goal, ICLTerm *params, ICLTerm* solutions);
00655 EXTERN int oaa_sort_and_get_event(ICLTerm *EventList, int LowestPriority, ICLTerm **Event, ICLTerm **Params);
00656 EXTERN int oaa_extract_event(ICLTerm *raw_event, ICLTerm **content, ICLTerm **params);
00657 
00658 EXTERN int oaa_class(char *class);
00659 EXTERN char *oaa_name_string(void);
00660 EXTERN int oaa_Id(ICLTerm **Id);
00661 EXTERN ICLTerm *perm_default_list();
00662 EXTERN ICLTerm *param_default_list();
00663 EXTERN int oaa_priority_compare(ICLTerm *Elt1, ICLTerm *Elt2);
00664 EXTERN int oaa_extract_event_param(ICLTerm *event, char *param,
00665                                    ICLTerm **result);
00666 EXTERN int oaa_choose_event(int LowestPriority, ICLTerm *EventList,
00667                             ICLTerm **Event);
00668 EXTERN int oaa_read_all_events(double TimeOut, ICLListType **Events,
00669                                int *FlushPriority);
00670 EXTERN int oaa_select_event(double timeout, ICLTerm **event);
00671 EXTERN int oaa_flush_events(ICLTerm **original_events, int flush_priority);
00672 EXTERN int oaa_data_in_solvables(ICLTerm *Clause, ICLTerm *Solvables,
00673                                  ICLTerm *Perm, ICLTerm **MatchedSolvable);
00674 EXTERN int oaa_distribute_perms(ICLTerm *solvables, ICLTerm *common_perms,
00675                                 ICLTerm **new_solvables);
00676 EXTERN int oaa_distribute_params(ICLTerm *solvables, ICLTerm *common_params,
00677                                  ICLTerm **new_solvables);
00678 
00679 EXTERN int oaa_declare_aux(char *mode, ICLTerm *solvables, ICLTerm *params,
00680                            ICLTerm **declared_solvables);
00681 EXTERN int icl_standardize_addressee(ICLTerm *Addr, ICLTerm **StandardAddr);
00682 EXTERN int oaa_address_to_comm_id(ICLTerm *inAddress, char **commId);
00683 EXTERN char* new_goal_id();
00684 EXTERN char* new_trigger_id();
00685 EXTERN int select_elements(ICLTerm *list, int (*test_function)(ICLTerm*),
00686                            ICLTerm** result);
00687 EXTERN int oaa_handle_user_event(ICLTerm *event,  ICLTerm *params,
00688                                  ICLTerm **solutions);
00689 EXTERN int oaa_exec_event(ICLTerm *goal, ICLTerm *params, ICLTerm **solutions);
00690 EXTERN int oaa_cont_solve(ICLTerm* goal_id, ICLTerm *goal,
00691                           ICLTerm *global_params, ICLTerm **solutions,
00692                           ICLTerm **out_params);
00693 EXTERN ICLTerm *remove_element(ICLTerm *elt, ICLTerm *list, ICLTerm **rest);
00694 EXTERN int oaa_cont_poll_until_all_events(ICLTerm *event_list, ICLTerm *event,
00695                                           ICLTerm *params, int priority,
00696                                           ICLTerm **solutions);
00697 EXTERN int oaa_handle_ev_update_data(ICLTerm *goal, ICLTerm *params);
00698 
00699 EXTERN int oaa_ComTraceMsg(char *format_string, ...);
00700 EXTERN int oaa_flush_notification(ICLTerm *raw_event);
00701 EXTERN int oaa_event_param(ICLTerm *event, ICLTerm *param);
00702 EXTERN int oaa_get_flush_notify(ICLTerm *event, ICLTerm **notify_event);
00703 EXTERN int oaa_translate_incoming_event(ICLTerm *raw_event_in, ICLTerm **raw_event_out);
00704 EXTERN int oaa_unwrap_event(ICLTerm *in_event, char **connection_id, ICLTerm **out_event);
00705 EXTERN int oaa_from_param(ICLTerm *event);
00706 EXTERN int oaa_content_fac_id(ICLTerm *content, ICLTerm **id);
00707 EXTERN int oaa_is_parent_fac_id(char *connection_id, ICLTerm **id);
00708 EXTERN int oaa_is_oaa_id(char *connection_id, ICLTerm **id);
00709 EXTERN int oaa_remove_data_owned_by(ICLTerm *id);
00710 EXTERN int oaa_handle_ev_update_trigger(ICLTerm *goal, ICLTerm *params);
00711 EXTERN int oaa_handle_ev_solve(ICLTerm *goal, ICLTerm *params, ICLTerm **solutions);
00712 EXTERN int oaa_handle_ev_solved(ICLTerm *goal, ICLTerm *params);
00713 EXTERN int oaa_add_data_local(ICLTerm *clause1, ICLTerm *params);
00714 EXTERN int oaa_remove_data_local(ICLTerm *clause1, ICLTerm *params);
00715 EXTERN int oaa_replace_data_local(ICLTerm *clause1_in, ICLTerm *params);
00716 EXTERN int oaa_Inform(ICLTerm *type_info, char *format_string, ICLTerm *args);
00717 EXTERN int oaa_solve_local(ICLTerm *full_goal, ICLTerm *params, ICLTerm **solutions);
00718 EXTERN int oaa_turn_on_debug();
00719 EXTERN int oaa_turn_off_debug();
00720 EXTERN int predicate_skeleton(ICLTerm *goal, ICLTerm **skeleton);
00721 EXTERN int oaa_is_waiting_for(ICLTerm *event);
00722 EXTERN int oaa_translate_outgoing_event(ICLTerm *event, ICLTerm *dest_id, char* commId,
00723                                         ICLTerm **new_event);
00724 EXTERN int oaa_poll_until_event(ICLTerm *event, ICLTerm **solution);
00725 EXTERN int oaa_declare_local(char *mode, ICLTerm *solvable0, ICLTerm *params,
00726                              ICLTerm **returned_solvables);
00727 EXTERN int solvables_to_be_added(ICLTerm *solvables, ICLTerm *current,
00728                                  ICLTerm **ok_solvables);
00729 EXTERN int solvables_to_be_removed(ICLTerm *solvables, ICLTerm *current,
00730                                    ICLTerm **ok_solvables);
00731 EXTERN int oaa_remove_solvables_data(ICLTerm *solvables);
00732 EXTERN int icl_subtract(ICLTerm *list1, ICLTerm *list2, ICLTerm **result);
00733 EXTERN int replace_element(ICLTerm *elt, ICLTerm *old_list, ICLTerm *new,
00734                            ICLTerm **new_list);
00735 EXTERN int oaa_update(char *mode, ICLTerm *clause, ICLTerm *initial_params,
00736                       ICLTerm **out_params);
00737 EXTERN int oaa_retractall(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback);
00738 EXTERN int retract_all(ICLTerm *clause);
00739 EXTERN int oaa_data_owner(ICLTerm *params, ICLTerm **owner);
00740 EXTERN int oaa_asserta(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback);
00741 EXTERN int oaa_assertz(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback);
00742 EXTERN int oaa_retract(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback);
00743 EXTERN int oaa_replace_all(ICLTerm *clause1, ICLTerm *clause2, ICLTerm *owner,
00744                            ICLTerm *callback);
00745 EXTERN int oaa_poll_until_event_priority(ICLTerm *event, int priority,
00746                                          ICLTerm **solutions);
00747 EXTERN int oaa_poll_until_all_events(ICLTerm *event_list, int priority,
00748                                      ICLTerm **solutions);
00749 EXTERN int oaa_grab_waiting_event(ICLTerm *event_list, ICLTerm **event);
00750 EXTERN int replace_all(ICLTerm *clause1, ICLTerm *clause2);
00751 
00752 // added for direct_connect
00753 static int ensure_direct_connection(ICLTerm *AgentAddress, char **ConnectionId);
00754 static int isClientConnection(char *ConnectionId);
00755 static char* new_direct_connection_id(void);
00756 static int oaa_cont_solve_direct(ICLTerm* goal_id,
00757                                  ICLTerm *goal,
00758                                  ICLTerm *SingleAgentAddress,
00759                                  ICLTerm *global_params,
00760                                  ICLTerm **solutions,
00761                                  ICLTerm **out_params);
00762 static int oaa_cont_plan(ICLTerm* goal_id,
00763                          ICLTerm *templateGoal,
00764                          ICLTerm *actualGoal,
00765                          ICLTerm *global_params,
00766                          ICLTerm **solutions,
00767                          ICLTerm **out_params);
00768 static int oaa_get_single_address_from_plan(ICLTerm *ev_planned_term,
00769                                             ICLTerm **SingleAgentAddress);
00770 static int oaa_handshake(char *ConnectionId, char *InitialAgentName, ICLTerm *Params);
00771 
00772 /*****************************************************************************
00773  * Initialization and connection functions
00774  *****************************************************************************/
00775 
00776 
00780 char *getlocalhostname(void) {
00781   char buf[MAXHOSTNAMELEN + 1];
00782   if (gethostname(buf, MAXHOSTNAMELEN) == 0) { /* success! */
00783     return(strdup(buf));
00784   }
00785   else return(NULL);
00786 }
00787 
00788 
00822 EXPORT_MSCPP
00823 int EXPORT_BORLAND
00824 oaa_Register(char *ConnectionId, char *AgentName, ICLTerm *Solvables)
00825 {
00826   ICLTerm *Params = NULL;
00827   ICLTerm *t1   = NULL;
00828   ICLTerm *t2   = NULL;
00829   ICLTerm *t3   = NULL;
00830   ICLTerm *declared_solvables = NULL;
00831   /* If the agent's name is read from the command line */
00832   char    *host = (char *)NULL;
00833   int      result = TRUE;
00834   int      isClient = TRUE;
00835 
00836   /* Determine whether connection is server or client type */
00837   isClient = isClientConnection(ConnectionId);
00838   if (!isClient) {
00839     printf("oaa_Register: server type\n");
00840     return FALSE;
00841   }
00842 
00843   /* Make sure there's a valid connection id */
00844   if (!ConnectionId || !*ConnectionId ||
00845       !com_GetInfo(ConnectionId,
00846                    (t1 = icl_NewStruct("status",
00847                                        1,
00848                                        icl_NewStr("connected"))), NULL)){
00849 
00850     printf("oaa_Register: No Connection\n");
00851     icl_Free(t1);
00852     return FALSE;
00853   }
00854 
00855   /* DEBUG */
00856   /*db_PrintDB(commdb);*/
00857 
00858   icl_Free(t1);
00859 
00860   // Check if handshaking has already occurred.
00861   // The internal logic of com_getInfo() does not
00862   // seem to work if the final parameter is NULL.
00863   t1 = icl_NewStruct("other_name", 1, icl_NewVar("_"));
00864   if (!com_GetInfo(ConnectionId, t1, &t2)) {
00865     oaa_handshake(ConnectionId, AgentName, Params);
00866   }
00867   icl_Free(t1);
00868   icl_Free(t2);
00869 
00870   /* Register local host */
00871   host = getlocalhostname();
00872   if (host != NULL) {
00873     ICLTerm *agent_host = NULL;
00874     ICLTerm *agent_listener = NULL;
00875     ICLTerm *myAddress = NULL;
00876     ICLTerm *myListenAddress = NULL;
00877     ICLTerm *named_address = NULL;
00878     ICLTerm* tempTerm = NULL;
00879     oaa_Address("parent", NULL, &myAddress);
00880     oaa_Address("client_listener", NULL, &myListenAddress);
00881 
00882     agent_host     = icl_NewStruct("agent_host", 3,
00883                icl_CopyTerm(icl_NthTerm(myAddress,1)),
00884                icl_NewStr(AgentName), icl_NewStr(host));
00885     if (isClient) {
00886       tempTerm = icl_NewTermFromData("[address(parent)]", 17);
00887       oaa_AddData(agent_host, tempTerm, NULL);
00888 
00889       // add agent_listener fact if I am a direct-connect client
00890       if (!STREQ(icl_Str(icl_NthTerm(myListenAddress,1)), "no_address")) {
00891         agent_listener = icl_NewStruct("agent_listener", 2,
00892                                        icl_CopyTerm(icl_NthTerm(myAddress,1)),
00893                                        icl_CopyTerm(icl_NthTerm(myListenAddress,1)));
00894         oaa_AddData(agent_listener, tempTerm, NULL);
00895         icl_Free(agent_listener);
00896         named_address = icl_NewStruct("name", 1, icl_NewStr(AgentName));
00897 
00898         agent_listener = icl_NewStruct("agent_listener", 2,
00899                                        icl_CopyTerm(named_address),
00900                                        icl_CopyTerm(icl_NthTerm(myListenAddress,1)));
00901         oaa_AddData(agent_listener, tempTerm, NULL);
00902         icl_Free(agent_listener);
00903       }
00904     }
00905 
00906     else{
00907       tempTerm = icl_NewTermFromData("[address(self)]", 15);
00908       oaa_AddData(agent_host, tempTerm, NULL);
00909     }
00910     icl_Free(tempTerm);
00911     icl_Free(agent_host);
00912     icl_Free(myAddress);
00913     icl_Free(myListenAddress);
00914     icl_Free(named_address);
00915   }
00916 
00917   t1 = icl_NewTermFromData("[if_exists(overwrite)]", 22);
00918   t2 = icl_NewList(NULL);
00919   t3 = icl_NewList(NULL);
00920   oaa_Declare(Solvables, t2, t2, t1, &declared_solvables);
00921 
00922   icl_Free(t1);
00923   icl_Free(t2);
00924   icl_Free(t3);
00925   icl_Free(declared_solvables);
00926   icl_stFree(host);
00927 
00928   return result;
00929 
00930 } // end of oaa_Register
00931 
00932 
00933 
00939 EXPORT_MSCPP
00940 void EXPORT_BORLAND
00941 oaa_Ready(int ShouldPrint)
00942 {
00943   char *name = NULL;
00944 
00945   /* If client, send ready message to Facilitator */
00946   if (!oaa_class("root") && (name = oaa_name_string())) {
00947     ICLTerm* toBePosted = icl_NewStruct("ev_ready", 1, icl_NewStr(name));
00948     oaa_PostEvent(toBePosted, ICL_EMPTY);
00949     icl_Free(toBePosted);
00950   }
00951   if(name != NULL) {
00952     icl_stFree(name);
00953   }
00954 
00955   if (ShouldPrint)
00956     printf("Ready.\n");
00957 }
00958 
00959 
00960 
00961 /*****************************************************************************
00962  * Classifying and Manipulating ICL expressions
00963  *****************************************************************************/
00964 
00976 EXPORT_MSCPP
00977 int EXPORT_BORLAND
00978 icl_BuiltIn(ICLTerm *goal)
00979 {
00980   int isStruct = icl_IsStruct(goal);
00981 
00982   if (isStruct) {
00983     char *s = icl_Str(goal);
00984     int arity = icl_NumTerms(goal);
00985     return (
00986      ((arity == 2) && STREQ(s, "="))
00987      || ((arity == 2) && STREQ(s, "=="))
00988      || ((arity == 2) && STREQ(s, "\\=="))
00989      || ((arity == 2) && STREQ(s, "=<"))
00990      || ((arity == 2) && STREQ(s, ">="))
00991      || ((arity == 2) && STREQ(s, "<"))
00992      || ((arity == 2) && STREQ(s, ">"))
00993      || ((arity == 2) && STREQ(s, "member"))
00994      || ((arity == 2) && STREQ(s, "memberchk"))
00995      || ((arity == 3) && STREQ(s, "findall"))
00996      || ((arity == 3) && STREQ(s, "icl_ConsistentParams"))
00997      );
00998   }
00999   else return FALSE;
01000 }
01001 
01002 
01006 int
01007 icl_compound_goal(ICLTerm *goal)
01008 {
01009   char *s = NULL;
01010 
01011   s = icl_Str(goal);
01012 
01013   return ((s != NULL) &&
01014           (
01015            STREQ(s, ":") ||
01016            STREQ(s, "::") ||
01017            STREQ(s, "\\+") ||
01018            STREQ(s, "->") ||
01019            STREQ(s, ":") ||
01020            STREQ(s, ",") ||
01021            STREQ(s, ";")
01022            )
01023           );
01024 }
01025 
01036 EXPORT_MSCPP
01037 int EXPORT_BORLAND
01038 icl_BasicGoal(ICLTerm *goal)
01039 {
01040   return (icl_IsStruct(goal) && !icl_compound_goal(goal));
01041 }
01042 
01043 
01044 
01060 EXPORT_MSCPP
01061 int EXPORT_BORLAND
01062 icl_GoalComponents(ICLTerm* fullgoal, ICLTerm** address,
01063        ICLTerm** goal, ICLTerm** param)
01064 {
01065   int res = FALSE;
01066   if (icl_IsStruct(fullgoal)&&(STREQ(icl_Str(fullgoal),"::"))) {
01067     /* Full goal a::g:p */
01068     if (icl_IsStruct(icl_NthTerm(fullgoal, 1)) &&
01069   (STREQ(icl_Str(icl_NthTerm(fullgoal, 1)),"::"))) {
01070       *address =  icl_CopyTerm(icl_NthTerm(icl_NthTerm(fullgoal, 1),1));
01071       *goal =  icl_CopyTerm(icl_NthTerm(icl_NthTerm(fullgoal, 1),2));
01072       *param = icl_CopyTerm(icl_NthTerm(fullgoal, 2));
01073       res = TRUE;
01074     }else{
01075       /* Simple goal goal::param */
01076       *address = icl_NewStr("unknown");
01077       *goal =  icl_CopyTerm(icl_NthTerm(fullgoal, 1));
01078       *param = icl_CopyTerm(icl_NthTerm(fullgoal, 2));
01079       res = TRUE;
01080     }
01081   }else {
01082     if (icl_IsStruct(fullgoal)&&(STREQ(icl_Str(fullgoal),":"))) {
01083       *address = icl_CopyTerm(icl_NthTerm(fullgoal, 1));
01084       *goal = icl_CopyTerm(icl_NthTerm(fullgoal, 2));
01085       *param = icl_NewList(NULL);
01086       res = TRUE;
01087     } else {
01088       *address = icl_NewStr("unknown");
01089       *goal = icl_CopyTerm(fullgoal);
01090       *param = icl_NewList(NULL);
01091       res = TRUE;
01092     }
01093   }
01094   return res;
01095 }
01096 
01097 /****************************************************************************
01098  * Permissions and parameter lists
01099  *
01100  * These procedures are used in processing solvables permissions, and
01101  * parameter lists of all kinds (including those used with solvables,
01102  * those contained in events, and those used in calls to various
01103  * library procedures).
01104  *
01105  * All permissions and many parameters have default values.
01106  *
01107  * Permissions and parameters lists have a standard form, as defined by
01108  * the predicates below.  To save bandwidth and promote readability, a
01109  * "perm" or "param" list in standard form OMITS default values.  For
01110  * easier processing (e.g., comparing/merging param lists), boolean
01111  * params in standard form always include a single argument 'true' or
01112  * 'false'.
01113  *
01114  * In definitions of solvables and calls to documented library
01115  * procedures, it's OK to include default params in a Params list, if
01116  * desired.  For boolean params, when the intended value is 'true', it's
01117  * OK just to specify the functor, for example, instead of
01118  * cache(true), it's OK just to include 'cache'.
01119  *
01120  *
01121  ***************************************************************************/
01122 
01129 int
01130 icl_standardize_perms(ICLTerm *Perms, int KeepDefaults, ICLTerm **Standardized)
01131 {
01132 
01133   if (icl_IsList(Perms)) {
01134     ICLListType *args = NULL;
01135     ICLListType *newArgs = NULL;
01136     ICLListType *endp = NULL;
01137     ICLTerm *standard = NULL;
01138 
01139     args = icl_List(Perms);
01140     while (args) {
01141       icl_perm_standard_form(args->elt, &standard);
01142       if (KeepDefaults || !icl_perm_default(standard, NULL)) {
01143         /* Keep: add to result list */
01144         if (!newArgs) {
01145           newArgs = icl_NewCons(standard, NULL);
01146           endp = newArgs;
01147         }
01148         else {
01149           endp->next = icl_NewCons(standard, NULL);
01150           endp = endp->next;
01151         }
01152       }
01153       else icl_Free(standard);
01154 
01155       args = args->next;
01156     }
01157     *Standardized = icl_NewList(newArgs);
01158     return TRUE;
01159   }
01160   else return FALSE;
01161 }
01162 
01163 
01167 /*
01168  * remarks: call --> call(true)
01169  */
01170 void
01171 icl_perm_standard_form(ICLTerm *perm, ICLTerm **Standard)
01172 {
01173   if (icl_IsStr(perm))
01174     *Standard = icl_NewStruct(icl_Str(perm), 1, icl_NewStr("true"));
01175   else *Standard = icl_CopyTerm(perm);
01176 }
01177 
01178 
01183 ICLTerm * perm_default_list()
01184 {
01185   static ICLTerm *perm_defaults = NULL;
01186 
01187   /* check to see if first time or somehow invalidated */
01188   if (!icl_IsValid(perm_defaults)) {
01189     perm_defaults =
01190       icl_NewTermFromString("[call(true),read(false),write(false)]");
01191     return perm_defaults;
01192   }
01193   else return perm_defaults;
01194 }
01195 
01196 
01202 int
01203 icl_perm_default(ICLTerm *perm, ICLTerm **result)
01204 {
01205   return (icl_IsStruct(perm) && (icl_NumTerms(perm) == 1) &&
01206           icl_ParamValue(icl_Str(perm), icl_NthTerm(perm, 1),
01207                          perm_default_list(), result));
01208 }
01209 
01210 
01218 int
01219 icl_standardize_params(ICLTerm *Params,int KeepDefaults,ICLTerm **Standardized)
01220 {
01221   if (icl_IsList(Params)) {
01222     ICLListType *args = NULL;
01223     ICLListType *newArgs = NULL;
01224     ICLListType *endp = NULL;
01225     ICLListType *slist = NULL;
01226     ICLListType *next = NULL;
01227 
01228     args = icl_List(Params);
01229     while (args) {
01230 
01231       icl_param_standard_form(args->elt, &slist);
01232 
01233       while (slist) {
01234         if (KeepDefaults || !icl_param_default(slist->elt,NULL)) {
01235           /* Keep: add to result list */
01236           if (!newArgs) {
01237             newArgs = icl_NewCons(slist->elt, NULL);
01238             endp = newArgs;
01239           }
01240           else {
01241             endp->next = icl_NewCons(slist->elt, NULL);
01242             endp = endp->next;
01243           }
01244         }
01245         /* Free list as we go, but don't free elements
01246    * Very ugly.  Be careful if you happen to be changing this.
01247    */
01248         next = slist->next;
01249         free(slist);
01250         slist = next;
01251       }
01252       args = args->next;
01253     }
01254     *Standardized = icl_NewList(newArgs);
01255     return TRUE;
01256   }
01257   else {
01258     *Standardized = NULL;
01259     return FALSE;
01260   }
01261 }
01262 
01263 
01268 ICLTerm * param_default_list()
01269 {
01270   static ICLTerm *param_defaults = NULL;
01271 
01272   /* check to see if first time or somehow invalidated */
01273   if (!icl_IsValid(param_defaults)) {
01274     param_defaults =
01275       icl_NewTermFromString("[from(unknown),priority(5),utility(5),if_exists(append),type(procedure),callback(app_do_event),private(false),single_value(false),unique_values(false),rules_ok(false),bookkeeping(true),persistent(false),at_beginning(false),do_all(false),reflexive(true),parallel_ok(true),reply(true),block(true),cache(false),flush_events(false),recurrence(when)]");
01276     return param_defaults;
01277   }
01278   else return param_defaults;
01279 }
01280 
01281 
01285 void
01286 icl_param_standard_form(ICLTerm *param, ICLListType **SList)
01287 {
01288   int isStruct = icl_IsStruct(param);
01289   int arity = icl_NumTerms(param);
01290   if (isStruct && (arity == 1) && STREQ(icl_Str(param), "block")) {
01291     *SList = icl_NewCons(icl_NewStruct("blocking", 1, icl_CopyTerm(icl_NthTerm(param, 1))),NULL);
01292   }
01293   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "reply") &&
01294            STREQ(icl_Str(icl_NthTerm(param, 1)), "false")) {
01295     *SList = icl_NewCons(icl_NewStruct("reply", 1, icl_NewStr("none")),NULL);
01296   }
01297   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "broadcast") &&
01298            STREQ(icl_Str(icl_NthTerm(param, 1)), "false")) {
01299     *SList = icl_NewCons(icl_NewStruct("reply", 1, icl_NewStr("true")),NULL);
01300   }
01301   else if ((arity == 0) && STREQ(icl_Str(param), "broadcast")) {
01302     *SList = icl_NewCons(icl_NewStruct("reply", 1, icl_NewStr("none")),NULL);
01303   }
01304   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "address")) {
01305     ICLTerm *newAddr;
01306     icl_standardize_address(icl_NthTerm(param, 1), &newAddr);
01307     *SList = icl_NewCons(icl_NewStruct("address", 1, newAddr),NULL);
01308   }
01309   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "strategy") &&
01310            STREQ(icl_Str(icl_NthTerm(param, 1)), "query")) {
01311     *SList = icl_NewCons(icl_NewStruct("parallel_ok", 1, icl_NewStr("true")),
01312                          NULL);
01313   }
01314   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "strategy") &&
01315            STREQ(icl_Str(icl_NthTerm(param, 1)), "action")) {
01316     *SList = icl_NewCons(icl_NewStruct("parallel_ok", 1, icl_NewStr("false")),
01317                          icl_NewCons(icl_NewStruct("solution_limit", 1, icl_NewInt(1)),NULL));
01318   }
01319   else if (isStruct && (arity == 1) && STREQ(icl_Str(param), "strategy") &&
01320            STREQ(icl_Str(icl_NthTerm(param, 1)), "inform")) {
01321     *SList = icl_NewCons(icl_NewStruct("parallel_ok", 1, icl_NewStr("true")),
01322                          icl_NewCons(icl_NewStruct("reply", 1, icl_NewStr("none")),NULL));
01323   }
01324   else if (icl_IsStr(param)) {
01325     *SList = icl_NewCons(icl_NewStruct(icl_Str(param), 1, icl_NewStr("true")),
01326                          NULL);
01327   }
01328   else {
01329     *SList = icl_NewCons(icl_CopyTerm(param), NULL);
01330   }
01331 }
01332 
01333 
01339 int
01340 icl_param_default(ICLTerm *param, ICLTerm **result)
01341 {
01342   return (icl_IsStruct(param) && (icl_NumTerms(param) == 1) &&
01343     icl_ParamValue(icl_Str(param), icl_NthTerm(param, 1),
01344        param_default_list(), result));
01345 }
01346 
01353 int icl_param_arg(char *param, ICLTerm *value, ICLTerm *paramlist,
01354                   ICLTerm **result) {
01355   ICLTerm *bigresult;
01356   int res = FALSE;
01357   if(icl_ParamValue(param, value, paramlist, &bigresult)) {
01358     res = TRUE;
01359     if (bigresult) {
01360       *result = icl_CopyTerm(icl_NthTerm(bigresult, 1));
01361       icl_Free(bigresult);
01362     }
01363   }
01364   return res;
01365 }
01366 
01379 EXPORT_MSCPP
01380 int EXPORT_BORLAND
01381 icl_GetParamValue(ICLTerm *Param, ICLTerm *ParamList, ICLTerm **Result)
01382 {
01383   int res = FALSE;
01384 
01385   if (icl_IsStruct(Param) && (icl_NumTerms(Param) == 1) &&
01386       icl_IsList(ParamList)) {
01387     ICLTerm *p;
01388 
01389     if (icl_ParamValue(icl_Str(Param), NULL, ParamList, &p)) {
01390       res = icl_Unify(Param, p, Result);
01391       icl_Free(p);
01392     } else
01393 
01394       if (icl_ParamValue(icl_Str(Param), NULL, param_default_list(), &p)) {
01395         res = icl_Unify(Param, p, Result);
01396         icl_Free(p);
01397       }
01398 
01399     return res;
01400   }
01401   else {
01402     return FALSE;
01403   }
01404 }
01405 
01419 EXPORT_MSCPP
01420 int EXPORT_BORLAND
01421 icl_GetPermValue(ICLTerm *Perm, ICLTerm *PermList, ICLTerm **Result)
01422 {
01423   int res = FALSE;
01424   if (icl_IsStruct(Perm) && (icl_NumTerms(Perm) == 1) &&
01425       icl_IsList(PermList)) {
01426     ICLTerm *p;
01427 
01428     if (icl_ParamValue(icl_Str(Perm), NULL, PermList, &p)) {
01429       res = icl_Unify(Perm, p, Result);
01430       icl_Free(p);
01431     } else
01432 
01433       if (icl_ParamValue(icl_Str(Perm), NULL, perm_default_list(), &p)) {
01434         res = icl_Unify(Perm, p, Result);
01435         icl_Free(p);
01436       }
01437 
01438     return res;
01439   }
01440   else return FALSE;
01441 }
01442 
01443 
01444 /* NOT IMPLEMENTED YET
01445    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01446    % name:    icl_RestrictParam(+ParamList, +ParamName, +ParamValue)
01447    % purpose: Often used in solvable declarations to filter on a certain
01448    %          condition.
01449    % definition:
01450    %          Test a param list: if one or more values are given in a parameter
01451    %          list for parameter ParamName, then ParamValue must be defined as
01452    %          one of the values to succeed.  If ParamValue is NOT defined, then
01453    %          icl_RestrictParam succeeds.
01454    % example:
01455    %    A natural language parser agent can only handle English definitions:
01456    %
01457    %        convert(nl, icl,Input,Params,Output) :-
01458    %               icl_RestrictParams(Params, language, english).
01459    %
01460    %    if "language(english)" is defined in parameter list of a solve request,
01461    %       the nl agent will receive the request.
01462    %    if "language(spanish)" is defined in the parameter list, the nl agent
01463    %       WILL NOT receive the request.
01464    %    if no language parameter is specified, the request WILL be sent
01465    %    if "language(X)" is specified, the request WILL be sent to the nl agent
01466    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01467    icl_RestrictParam(ParamList, Param, Value) :-
01468 */
01469 
01470 
01471 
01472 /****************************************************************************
01473  * Agent identity and addressing
01474  *
01475  * Every agent (including facilitators) has a symbolic name, a full address,
01476  * and a local address (or "local ID").  A full address has the form:
01477  *     addr(tcp(Host,Port))              for a facilitator (if TCP is protocol)
01478  *     addr(tcp(Host,Port), LocalID)     for a client agent.
01479  *
01480  * Even though it doesn't appear in the full address, a facilitator also
01481  * has a local ID, for consistency and convenient reference. The
01482  * local ID of a client agent is assigned to it by its facilitator.
01483  * This, and the facilitator's local ID, are passed to the client at
01484  * connection time.
01485  *
01486  * Full addresses are globally unique, and local addresses are unique with
01487  * respect to a facilitator.  Symbolic names are NOT unique in any sense.
01488  *
01489  * The local ID happens to be an integer, but developers should not rely
01490  * on this.
01491  *
01492  * When specifying addresses, in address/1 params for calls to
01493  * oaa_AddData, oaa_Solve, etc., either names or addresses may be used.
01494  * In addition, for convenience, reserved terms 'self', 'parent', and
01495  * 'facilitator' may also be used.
01496  *
01497  * More precisely, the address parameter may contain any of the following:
01498  * a full address; a local ID (when the addressee is known to be either
01499  * the facilitator or a peer client); a name, enclosed in the name/1 functor;
01500  * 'self'; 'parent'; or 'facilitator'.  ('parent' and 'facilitator are
01501  * synonymous.)
01502  *
01503  * Address parameters are standardized as follows: A full address for the
01504  * local facilitator or a peer client is changed to the local ID; all
01505  * other full addresses are left as is.  Names are left as is.  'self',
01506  * 'parent', and 'facilitator' are changed to the appropriate local ID.
01507  *
01508  ***************************************************************************/
01509 
01514 int icl_name(ICLTerm *term)
01515 {
01516   if (icl_IsStr(term)) {
01517     char *s = icl_Str(term);
01518 
01519     return (!(STREQ(s,"self") ||
01520               STREQ(s,"parent") ||
01521               STREQ(s,"facilitator")));
01522   }
01523   else return FALSE;
01524 }
01525 
01526 
01531 int icl_true_id(ICLTerm *term, ICLTerm **Id)
01532 {
01533   int res = TRUE;
01534 
01535   if (icl_IsInt(term))
01536     *Id = icl_CopyTerm(term);
01537   else
01538 
01539     if (icl_IsStr(term)) {
01540 
01541       if STREQ(icl_Str(term), "self") {
01542         res = oaa_PrimaryAddress(Id);
01543       }
01544       else
01545   if (STREQ(icl_Str(term), "parent") ||
01546       STREQ(icl_Str(term), "facilitator")) {
01547     ICLTerm *fid, *t1;
01548 
01549     res = com_GetInfo("parent",
01550           (t1 = icl_NewStruct("fac_id",
01551             1,
01552             icl_NewVar("FId"))),
01553           &fid);
01554 
01555     icl_Free(t1);
01556     if (res) {
01557       *Id = icl_CopyTerm(icl_NthTerm(fid, 1));
01558       icl_Free(fid);
01559     }
01560   }
01561   else res = FALSE;
01562     }
01563     else res = FALSE;
01564 
01565   return res;
01566 }
01567 
01568 
01574 int
01575 icl_standardize_addressee(ICLTerm *Addr, ICLTerm **StandardAddr)
01576 {
01577   ICLTerm *tempRequest = icl_NewTermFromData("other_address(A)",16);
01578   ICLTerm *result = NULL;
01579   ICLTerm *fid = NULL;
01580   ICLTerm *t1;
01581   int freeResult = FALSE;
01582   int    returnValue = 0;
01583 
01584   /* -- self */
01585   if (icl_IsStr(Addr) && (STREQ(icl_Str(Addr),"self"))) {
01586     oaa_PrimaryAddress(&result);
01587     // need to icl_Free() result below...
01588     freeResult = TRUE;
01589   }else
01590     /* -- parent */
01591     if (icl_IsStr(Addr) && (STREQ(icl_Str(Addr),"parent"))) {
01592       com_GetInfo("parent", tempRequest, &fid);
01593       if (fid != NULL) {
01594         result = icl_CopyTerm(icl_NthTerm(fid, 1));
01595         // need to icl_Free() result below...
01596         freeResult = TRUE;
01597         icl_Free(fid);
01598       }
01599     }else
01600 
01601       /* -- facilitator */
01602       if (icl_IsStr(Addr) && (STREQ(icl_Str(Addr),"facilitator"))) {
01603         com_GetInfo("parent", tempRequest, &fid);
01604         if (fid != NULL) {
01605           result = icl_CopyTerm(icl_NthTerm(fid, 1));
01606           // need to icl_Free() result below...
01607           freeResult = TRUE;
01608           icl_Free(fid);
01609         }
01610       }else
01611 
01612         /* -- tcp(A,B) */
01613         if (icl_IsStruct(Addr) &&  (STREQ(icl_Str(Addr),"tcp")) &&
01614             (icl_NumTerms(Addr)==2)) {
01615           result = Addr;
01616           // don't free result below...
01617           freeResult = FALSE;
01618         }else
01619 
01620           /* addr(FacAddr, Id) */
01621           if (icl_IsStruct(Addr) && STREQ(icl_Str(Addr),"addr")) {
01622             ICLTerm *res, *fid;
01623             int arity = icl_NumTerms(Addr);
01624 
01625             if (com_GetInfo("parent",
01626                             (t1 = icl_NewStruct("addr",
01627                                                 1,
01628                                                 icl_NewVar("Addr"))),
01629                             &res)) {
01630 
01631               icl_Free(t1);
01632               if ((arity == 1) && icl_Unify(Addr, res, NULL)) {
01633                 if (com_GetInfo("parent",
01634                                 (t1 = icl_NewStruct("fac_id",
01635                                                     1,
01636                                                     icl_NewVar("FId"))),
01637                                 &fid)) {
01638 
01639                   result = icl_CopyTerm(icl_NthTerm(fid, 1));
01640                   // need to icl_Free() result below...
01641                   freeResult = TRUE;
01642                   icl_Free(fid);
01643                   icl_Free(t1);
01644                 }
01645               } 
01646               else {
01647                 icl_Free(t1);
01648               }
01649 
01650               if ((arity == 2) && icl_Unify(icl_NthTerm(Addr,1),
01651                                             icl_NthTerm(res,1), NULL)) {
01652                 result = icl_NthTerm(Addr, 2);
01653                 // don't free result below...
01654                 freeResult = FALSE;
01655               }
01656               icl_Free(res);
01657             }
01658             icl_Free(t1);
01659 
01660             if ((!result) && (icl_NumTerms(Addr) == 2)) {
01661               result = Addr;
01662               // don't free result below...
01663               freeResult = FALSE;
01664             }
01665           } 
01666             /* Here the incoming address may be a name and has to be left as is.
01667                -- name(Name)
01668             */
01669           else if (icl_IsStruct(Addr) && STREQ(icl_Str(Addr),"name")) {
01670               if (icl_name(icl_NthTerm(Addr, 1)))
01671                 result = Addr;
01672                 // don't free result below...
01673                 freeResult = FALSE;
01674           } 
01675           else if (icl_name(Addr)) {
01676                 result = icl_NewStruct("name", 1, icl_CopyTerm(Addr));
01677                 // need to icl_Free() result below...
01678                 freeResult = TRUE;
01679                 printf("WARNING (liboaa.c): addressee name, in address/1 param, should be "
01680                        "specified as:\n  name(%s)\n", icl_Str(Addr));
01681           } 
01682           else if (!icl_true_id(Addr, &result)) {
01683                   printf("WARNING (liboaa.c): Illegal addressee, in address/1 param, discarded:\n   ");
01684                   icl_WriteTerm(Addr);
01685                   printf("\n");
01686                   icl_Free(result);
01687                   // don't need to free result again below...
01688                   freeResult = FALSE;
01689           }
01690 
01691   if (result)
01692     *StandardAddr = icl_CopyTerm(result);
01693 
01694   returnValue = (result != NULL) ? 1 : 0;
01695 
01696   if (freeResult) {
01697     icl_Free(result);
01698   }
01699 
01700   icl_Free(tempRequest);
01701 
01702   return (returnValue);
01703 } // end of icl_standardize_addressee
01704 
01705 
01706 
01712 int
01713 icl_standardize_address(ICLTerm *Addr, ICLTerm **StandardAddr)
01714 {
01715   ICLListType *args = NULL, *newArgs = NULL, *endp = NULL;
01716   ICLTerm *elt = NULL, *standard = NULL;
01717 
01718   if (!icl_IsList(Addr))
01719     elt = Addr;
01720   else
01721     args = icl_List(Addr);
01722 
01723   while (args || elt) {
01724 
01725     if (!elt) elt = args->elt;
01726 
01727     if (icl_standardize_addressee(elt, &standard)) {
01728       /* Keep: add to result list */
01729       if (!newArgs) {
01730         newArgs = icl_NewCons(standard, NULL);
01731         endp = newArgs;
01732       }
01733       else {
01734         endp->next = icl_NewCons(standard, NULL);
01735         endp = endp->next;
01736       }
01737     }
01738 
01739     if (args)
01740       args = args->next;
01741     elt = NULL;
01742   }
01743   if (args)
01744     *StandardAddr = icl_NewList(newArgs);
01745   else {
01746     *StandardAddr = newArgs->elt;
01747 
01748     /* Must free (iclListType *)newArgs and any elements in that list */
01749     if (newArgs->next == (ICLListType *)NULL)
01750       free(newArgs);
01751     else {
01752       ICLListType *list = newArgs->next, *next;
01753 
01754       free(newArgs);
01755       while (list) {
01756         icl_Free(list->elt);
01757         next = list->next;
01758         free(list);
01759         list = next;
01760       }
01761     }
01762   }
01763 
01764   return TRUE;
01765 }
01766 
01767 
01768 
01769 
01811 /*     - (@@DLM) This might be the place to check the validity of solvables,
01812  *       such as using only built-ins in tests.  Also, check for dependencies
01813  *       between solvables; e.g., when persistent(false) is there,
01814  *       bookkeeping(true) must also be there.
01815  */
01816 EXPORT_MSCPP
01817 int EXPORT_BORLAND
01818 icl_ConvertSolvables(int toStandard,
01819          ICLTerm *ShorthandSolvables, ICLTerm **StandardSolvables)
01820 {
01821   if (toStandard) {
01822     return icl_standardize_solvables(ShorthandSolvables, StandardSolvables);
01823   }
01824   else {
01825     return icl_readable_solvables(ShorthandSolvables, StandardSolvables);
01826   }
01827 }
01828 
01829 int
01830 icl_standardize_solvable(ICLTerm *Shorthand,
01831                          ICLTerm **Standard)
01832 {
01833   int isStruct = icl_IsStruct(Shorthand);
01834   int arity = icl_NumTerms(Shorthand);
01835   int res = TRUE;
01836   ICLTerm *tmp;
01837   ICLTerm *perms, *params;
01838 
01839   *Standard = NULL;
01840   /* solvable(Goal), solvable(Goal,Params), solvable(Goal,Params,Perms) */
01841   /* Goal may be simple or (G :- Test) */
01842   if (isStruct && STREQ(icl_Str(Shorthand), "solvable")) {
01843     ICLTerm *goal = icl_NthTerm(Shorthand, 1);
01844 
01845     if (arity > 1) {
01846       icl_standardize_params(icl_NthTerm(Shorthand, 2), FALSE, &params);
01847     }
01848     else {
01849       params = icl_NewList(NULL);
01850     }
01851 
01852     if (arity == 3) {
01853       icl_standardize_perms(icl_NthTerm(Shorthand, 3), FALSE, &perms);
01854     }
01855     else {
01856       perms = icl_NewList(NULL);
01857     }
01858 
01859     /* Handles all cases where goal is (Goal :- Test) */
01860     if (icl_IsStruct(goal) && (icl_NumTerms(goal) == 2) &&
01861         STREQ(icl_Str(goal), ":-")) {
01862 
01863       ICLTerm *g = icl_CopyTerm(icl_NthTerm(goal, 1));
01864       icl_AddToList(params,
01865         icl_NewStruct("test", 1,
01866           icl_CopyTerm(icl_NthTerm(goal, 2))), FALSE);
01867 
01868       tmp = icl_NewStruct("solvable", 3, g, params, perms);
01869       res = icl_standardize_solvable(tmp, Standard);
01870       icl_Free(tmp);
01871     }
01872     else {  /* Normal "simple" goal */
01873       *Standard = icl_NewStruct("solvable", 3,
01874         icl_CopyTerm(icl_NthTerm(Shorthand, 1)), params, perms);
01875     }
01876   }
01877   else if (isStruct && (arity == 2) && STREQ(icl_Str(Shorthand), ":-")) {
01878     /* (Goal :- Test) */
01879     ICLTerm *goal = icl_NthTerm(Shorthand, 1);
01880 
01881     *Standard =
01882       icl_NewStruct("solvable", 3, icl_CopyTerm(icl_NthTerm(goal, 1)),
01883         icl_NewList(icl_NewCons(icl_CopyTerm(icl_NthTerm(goal, 2)), NULL)),
01884         icl_NewList(NULL));
01885   }
01886   else {  /* goal */
01887     *Standard = icl_NewStruct("solvable", 3, icl_CopyTerm(Shorthand),
01888             icl_NewList(NULL), icl_NewList(NULL));
01889   }
01890   return res;
01891 }
01892 
01896 int
01897 icl_standardize_solvables(ICLTerm *ShorthandSolvables,
01898         ICLTerm **StandardSolvables)
01899 {
01900 
01901   if (icl_IsList(ShorthandSolvables)) {
01902     ICLListType *args, *newArgs = NULL, *endp = NULL;
01903     ICLTerm *standard = NULL;
01904 
01905     args = icl_List(ShorthandSolvables);
01906     while (args) {
01907       if (icl_standardize_solvable(args->elt, &standard)) {
01908         /* Keep: add to result list */
01909         if (!newArgs) {
01910           newArgs = icl_NewCons(standard, NULL);
01911           endp = newArgs;
01912         }
01913   else {
01914     endp->next = icl_NewCons(standard, NULL);
01915     endp = endp->next;
01916   }
01917       }
01918 
01919       args = args->next;
01920     }
01921     *StandardSolvables = icl_NewList(newArgs);
01922 
01923     return TRUE;
01924   }
01925   return FALSE;
01926 }
01927 
01931 /*
01932  * remarks:
01933  *    icl_readable_solvable(solvable(Goal, [], []), Goal).
01934  *    icl_readable_solvable(solvable(Goal, Params, []), solvable(Goal, Params)).
01935  *    icl_readable_solvable(solvable(Goal, Params, Perms),
01936  *                       solvable(Goal, Params, Perms)).
01937  */
01938 int
01939 icl_readable_solvable(ICLTerm *StandardSolvable,
01940           ICLTerm **ShorthandSolvable)
01941 {
01942   int isStruct = icl_IsStruct(StandardSolvable);
01943   int arity = icl_NumTerms(StandardSolvable);
01944 
01945   if (isStruct && (arity == 3) &&
01946       STREQ(icl_Str(StandardSolvable),"solvable")) {
01947     ICLTerm *params = icl_NthTerm(StandardSolvable, 2);
01948     ICLTerm *perms  = icl_NthTerm(StandardSolvable, 2);
01949 
01950     if (icl_IsList(perms) && (icl_NumTerms(perms) == 0)) {
01951       if (icl_IsList(params) && (icl_NumTerms(params) == 0))
01952         *ShorthandSolvable = icl_CopyTerm(icl_NthTerm(StandardSolvable,1));
01953       else
01954         *ShorthandSolvable = icl_NewStruct("solvable", 2,
01955                                            icl_CopyTerm(icl_NthTerm(StandardSolvable,1)),
01956                                            icl_CopyTerm(icl_NthTerm(StandardSolvable,2)));
01957     }
01958     else
01959       *ShorthandSolvable = icl_CopyTerm(StandardSolvable);
01960   }
01961   else
01962     *ShorthandSolvable = icl_CopyTerm(StandardSolvable);
01963   return TRUE;
01964 }
01965 
01966 
01971 int
01972 icl_readable_solvables(ICLTerm *StandardSolvables,
01973                        ICLTerm **ShorthandSolvables)
01974 {
01975   if (icl_IsList(StandardSolvables)) {
01976     ICLListType *args, *newArgs = NULL, *endp = NULL;
01977     ICLTerm *shortsolve = NULL;
01978 
01979     args = icl_List(StandardSolvables);
01980     while (args) {
01981 
01982       if (icl_readable_solvable(args->elt, &shortsolve)) {
01983         /* Keep: add to result list */
01984         if (!newArgs) {
01985           newArgs = icl_NewCons(shortsolve, NULL);
01986           endp = newArgs;
01987         }
01988         else {
01989           endp->next = icl_NewCons(shortsolve, NULL);
01990           endp = endp->next;
01991         }
01992       }
01993 
01994       args = args->next;
01995     }
01996     *ShorthandSolvables = icl_NewList(newArgs);
01997     return TRUE;
01998   }
01999   else return FALSE;
02000 }
02001 
02002 
02003 
02018 int
02019 icl_minimally_instantiate_solvable(ICLTerm *Shorthand,
02020                                    ICLTerm **Minimal)
02021 {
02022   int isStruct = icl_IsStruct(Shorthand);
02023   int arity = icl_NumTerms(Shorthand);
02024   int res = TRUE;
02025   ICLTerm *perms, *params;
02026 
02027   /* solvable(Goal), solvable(Goal,Params), solvable(Goal,Params,Perms) */
02028   /* Goal may be simple or (G :- Test) */
02029   if (isStruct && STREQ(icl_Str(Shorthand), "solvable")) {
02030     ICLTerm *goal = icl_NthTerm(Shorthand, 1);
02031     ICLTerm *g;
02032 
02033     params = icl_NewVar("Params");
02034     perms = icl_NewVar("Perms");
02035 
02036     /* Handles all cases where goal is (Goal :- Test) */
02037     if (icl_IsStruct(goal) && (icl_NumTerms(goal) == 2) &&
02038         STREQ(icl_Str(goal), ":-")) {
02039 
02040       g = icl_CopyTerm(icl_NthTerm(goal, 1));
02041     }
02042     else  /* Normal "simple" goal */
02043       g = icl_CopyTerm(goal);
02044     *Minimal = icl_NewStruct("solvable", 3, g, params, perms);
02045   }
02046   else
02047 
02048     /* (Goal :- Test) */
02049     if (isStruct && (arity == 2) && STREQ(icl_Str(Shorthand), ":-")) {
02050       ICLTerm *goal = icl_NthTerm(Shorthand, 1);
02051 
02052       *Minimal = icl_NewStruct("solvable", 3, icl_CopyTerm(icl_NthTerm(goal, 1)),
02053                                icl_NewVar("Params"), icl_NewVar("Perms"));
02054     }
02055     else  /* goal */
02056       *Minimal = icl_NewStruct("solvable", 3, icl_CopyTerm(Shorthand),
02057                                icl_NewVar("Params"), icl_NewVar("Perms"));
02058 
02059   return res;
02060 }
02061 
02062 
02063 
02067 int
02068 icl_minimally_instantiate_solvables(ICLTerm *ShorthandSolvables,
02069               ICLTerm **MinimalSolvables)
02070 {
02071   if (icl_IsList(ShorthandSolvables)) {
02072     ICLListType *args, *newArgs = NULL, *endp = NULL;
02073     ICLTerm *minimal = NULL;
02074 
02075     args = icl_List(ShorthandSolvables);
02076     while (args) {
02077 
02078       if (icl_minimally_instantiate_solvable(args->elt, &minimal)) {
02079         /* Keep: add to result list */
02080         if (!newArgs) {
02081           newArgs = icl_NewCons(minimal, NULL);
02082           endp = newArgs;
02083         }
02084         else {
02085           endp->next = icl_NewCons(minimal, NULL);
02086           endp = endp->next;
02087         }
02088       }
02089 
02090       args = args->next;
02091     }
02092     *MinimalSolvables = icl_NewList(newArgs);
02093     return TRUE;
02094   }
02095   else return FALSE;
02096 }
02097 
02098 
02136 int
02137 oaa_goal_matches_solvables(ICLTerm *Goal, ICLTerm *Solvables,
02138          ICLTerm **RealGoal, ICLTerm **RealMatched)
02139 {
02140 
02141   ICLTerm *Matched = NULL;
02142   ICLTerm *allSolvables = NULL;
02143   ICLTerm *t1;
02144   int result = TRUE;
02145 
02146   icl_Union(oaa_built_in_solvables(), Solvables, &allSolvables);
02147   /*
02148   {
02149     char* alls = icl_NewStringFromTerm(allSolvables);
02150     printf("All solvables: %s\n", alls);
02151     icl_stFree(alls);
02152   }
02153   */
02154 
02155   CHECK_LEAKS();
02156   if (oaa_goal_in_solvables(Goal, allSolvables, &Matched)) {
02157     /* Matched = solvable(Goal,Params,Perms) */
02158     ICLTerm *Params = icl_NthTerm(Matched, 2);
02159     ICLTerm *Value = NULL;
02160 
02161     icl_Free(allSolvables);
02162     /* See if Goal is a synonym predicate */
02163     t1 = icl_NewStruct("synonym",
02164            2,
02165            icl_CopyTerm(Goal),
02166            icl_NewVar("SynGoal"));
02167     if (icl_GetParamValue(t1, Params, &Value)) {
02168       result = oaa_goal_matches_solvables(icl_NthTerm(Value, 2),
02169             Solvables,
02170             RealGoal,
02171             RealMatched);
02172       icl_Free(Matched);
02173       icl_Free(Value);
02174     }
02175     else {
02176       *RealGoal = icl_CopyTerm(Goal);
02177       *RealMatched = Matched;
02178       /* Doesn't free Matched: OK */
02179     }
02180     icl_Free(t1);
02181   }
02182   else {
02183     icl_Free(allSolvables);
02184     result = FALSE;
02185   }
02186   /*icl_Free(allSolvables);*/
02187   return result;
02188 }
02189 
02203 int
02204 oaa_goal_in_solvables(ICLTerm *Goal, ICLTerm *Solvables,
02205           ICLTerm **MatchedSolvable)
02206 {
02207   int result = TRUE;
02208   int done = FALSE;
02209 
02210   if (icl_IsList(Solvables)) {
02211     ICLListType *args = NULL;
02212 
02213     args = icl_List(Solvables);
02214     while (args && !done) {
02215       /* Note: args->elt = solvable(G1,Params,Perms) */
02216       ICLTerm *G1     = icl_NthTerm(args->elt, 1);
02217       ICLTerm *Params = icl_NthTerm(args->elt, 2);
02218       ICLTerm *t1, *t2;
02219 
02220       if (icl_Unify(Goal, G1, NULL)) {
02221   t1 = icl_NewStruct("synonym",
02222          2,
02223          icl_CopyTerm(Goal),
02224          icl_NewVar("SynGoal"));
02225   if (icl_GetParamValue(t1, Params, NULL)) {
02226     done = TRUE;
02227     *MatchedSolvable = icl_CopyTerm(args->elt);
02228     icl_Free(t1);
02229   }
02230   else
02231 
02232     icl_Free(t1);
02233 
02234   /* Make sure calling permissions are OK */
02235   if (icl_GetPermValue((t1 = icl_NewTermFromData("call(true)",10)),
02236            Params,
02237            NULL)) {
02238     ICLTerm *Test;
02239     ICLTerm *WholeTest;
02240 
02241     /* If a test, then execute it... */
02242     t2 = icl_NewStruct("test",
02243            1,
02244            icl_NewVar("T"));
02245     if (icl_GetPermValue(t2,
02246              Params,
02247              &Test)) {
02248 
02249       /* Check test: */
02250       /*    WholeTest = ( G1 = Goal, Test ) */
02251       WholeTest = icl_NewGroup(
02252        '(',
02253        ",",
02254        icl_NewCons(
02255         icl_NewStruct("=",
02256           2,
02257           icl_CopyTerm(G1),
02258           icl_CopyTerm(Goal)),
02259         icl_NewCons(icl_CopyTerm(Test), NULL)));
02260 
02261       /* MAKE SURE oaa_Interpret can handle compound goals
02262        * and '='(A,B)!!!
02263        */
02264       done = oaa_Interpret(WholeTest, ICL_EMPTY, NULL);
02265 
02266       if (done) {
02267         *MatchedSolvable = icl_CopyTerm(args->elt);
02268       }
02269 
02270       icl_Free(Test);
02271       icl_Free(WholeTest);
02272     } else {
02273       done = TRUE;
02274       *MatchedSolvable = icl_CopyTerm(args->elt);
02275     }
02276     icl_Free(t2);
02277   }
02278   icl_Free(t1);
02279       }
02280       args = args->next;
02281     }
02282     /* If we've come to the end of the list without success, failure */
02283     if (!done && !args) {
02284       result = FALSE;
02285     }
02286   }
02287   else {
02288     result = FALSE;
02289   }
02290   return result;
02291 }
02292 
02293 
02321 int
02322 oaa_data_matches_solvables(ICLTerm *Clause, ICLTerm *Solvables, ICLTerm *Perm,
02323          ICLTerm **RealClause, ICLTerm **RealMatched)
02324 {
02325 
02326   ICLTerm *Matched = NULL;
02327   ICLTerm *Head = NULL, *Body = NULL;
02328   ICLTerm *t1;
02329   int result = TRUE;
02330 
02331   if (oaa_data_in_solvables(Clause, oaa_built_in_solvables(),Perm,&Matched) ||
02332       oaa_data_in_solvables(Clause, Solvables,Perm,&Matched)) {
02333 
02334     /* Matched = solvable(Clause,Params,Perms) */
02335     ICLTerm *Params = icl_NthTerm(Matched, 2);
02336     ICLTerm *Value = NULL;
02337 
02338     if (icl_IsStruct(Clause) && STREQ(icl_Functor(Clause), ":-")) {
02339       Head = icl_NthTerm(Clause, 1);
02340       Body = icl_NthTerm(Clause, 2);
02341     }
02342     else {
02343       Head = Clause;
02344     }
02345 
02346     /* See if Clause is a synonym predicate */
02347     t1 = icl_NewStruct("synonym",
02348            2,
02349            icl_CopyTerm(Head),
02350            icl_NewVar("SynHead"));
02351     if (icl_GetParamValue(t1, Params, &Value)) {
02352       ICLTerm *SynClause;
02353 
02354       if (Body) {
02355   SynClause = icl_NewStruct(":-", 2,
02356           icl_CopyTerm(icl_NthTerm(Value, 2)),
02357           icl_CopyTerm(Body));
02358       }
02359       else {
02360   SynClause = icl_CopyTerm(icl_NthTerm(Value, 2));
02361       }
02362 
02363       result = oaa_data_matches_solvables(SynClause,
02364             Solvables,
02365             Perm,
02366             RealClause,
02367             RealMatched);
02368       icl_Free(SynClause);
02369       icl_Free(Matched);
02370       icl_Free(Value);
02371     }
02372     else {
02373       *RealClause = icl_CopyTerm(Clause);
02374       *RealMatched = Matched;
02375       /* Doesn't free Matched: OK */
02376     }
02377     icl_Free(t1);
02378   }
02379   else {
02380     result = FALSE;
02381   }
02382 
02383   return result;
02384 }
02385 
02386 
02387 
02397 int
02398 oaa_data_in_solvables(ICLTerm *Clause, ICLTerm *Solvables, ICLTerm *Perm,
02399                       ICLTerm **MatchedSolvable)
02400 {
02401   int result = TRUE;
02402   int done = FALSE;
02403 
02404   if (icl_IsList(Solvables)) {
02405     ICLListType *args = NULL;
02406     ICLTerm *Head = NULL, *Body = NULL;
02407 
02408     if (icl_IsStruct(Clause) && STREQ(icl_Functor(Clause), ":-")) {
02409       Head = icl_NthTerm(Clause, 1);
02410       Body = icl_NthTerm(Clause, 2);
02411     }
02412     else {
02413       Head = Clause;
02414     }
02415 
02416     args = icl_List(Solvables);
02417     while (args && !done) {
02418 
02419       /* Note: args->elt = solvable(G1,Params,Perms) */
02420       ICLTerm *G1     = icl_NthTerm(args->elt, 1);
02421       ICLTerm *Params = icl_NthTerm(args->elt, 2);
02422       ICLTerm *Perms = icl_NthTerm(args->elt, 3);
02423 
02424       if (icl_Unify(Head, G1, NULL)) {
02425   ICLTerm *t1;
02426 
02427   if (icl_GetParamValue((t1 = icl_NewStruct("synonym",
02428               2,
02429               icl_CopyTerm(Head),
02430               icl_NewVar("_RealHead"))),
02431             Params, NULL)) {
02432     done = TRUE;
02433     *MatchedSolvable = icl_CopyTerm(args->elt);
02434   }
02435   else { /* Perform a number of additional test */
02436     ICLTerm *t2;
02437 
02438     t2 = icl_NewTermFromData("type(data)",10);
02439     done = icl_GetParamValue(t2, Params, NULL);
02440     icl_Free(t2);
02441     if (done && Body) {
02442       t2 = icl_NewTermFromData("rules_ok(true)",14);
02443       done = icl_GetParamValue(t2,Params, NULL);
02444       icl_Free(t2);
02445     }
02446     if (done) {
02447       if(STREQ(icl_Str(Perm), "write")) {
02448         t2 = icl_NewTermFromData("write(true)",11);
02449         done = icl_GetPermValue(t2, Perms, NULL);
02450         icl_Free(t2);
02451       }
02452       else {
02453         t2 = icl_NewTermFromData("read(true)",10);
02454         done = icl_GetPermValue(t2, Perms, NULL);
02455         icl_Free(t2);
02456       }
02457     }
02458     if (done) { /* Passed all tests */
02459       *MatchedSolvable = icl_CopyTerm(args->elt);
02460     }
02461   }
02462   icl_Free(t1);
02463       }
02464       args = args->next;
02465     }
02466 
02467     /* If we've come to the end of the list without success, failure */
02468     if (!done && !args) {
02469       result = FALSE;
02470     }
02471   }
02472   else {
02473     result = FALSE;
02474   }
02475 
02476   return result;
02477 }
02478 
02479 
02480 /****************************************************************************
02481  * Retrieving and managing events
02482  ***************************************************************************/
02483 
02484 
02491 EXPORT_MSCPP
02492 void EXPORT_BORLAND
02493 oaa_MainLoop(int ShouldPrint)
02494 {
02495   ICLTerm *Event, *Params;
02496   oaa_Ready(ShouldPrint);
02497 
02498   while (TRUE) {
02499     oaa_GetEvent(&Event, &Params, 0);
02500     CHECK_LEAKS();
02501     oaa_ProcessEvent(Event, Params);
02502     CHECK_LEAKS();
02503     icl_Free(Event);
02504     icl_Free(Params);
02505   }
02506 }
02507 
02508 
02516 EXPORT_MSCPP
02517 void EXPORT_BORLAND
02518 oaa_ProcessAllEvents()
02519 {
02520   ICLTerm *Event = NULL, *Params = NULL;
02521   oaa_GetEvent(&Event, &Params, 0);
02522   oaa_ProcessEvent(Event, Params);
02523   icl_Free(Event);
02524   icl_Free(Params);
02525 }
02526 
02527 
02528 static char* oaa_getConnectionIdFromParams(ICLTerm *params)
02529 {
02530   ICLTerm* connId;
02531   char* toReturn;
02532   if(!icl_ParamValue("connection_id", NULL, params, &connId)) {
02533     char* paramString = icl_NewStringFromTerm(params);
02534     fprintf(stderr, "No connection_id in: %s", paramString);
02535     icl_stFree(paramString);
02536     return NULL;
02537   }
02538   toReturn = strdup(icl_Str(icl_NthTerm(connId, 1)));
02539   icl_Free(connId);
02540   return toReturn;
02541 }
02542 
02543 static void oaa_got_heartbeat(char* connection)
02544 {
02545   GTimeVal now;
02546   ICLTerm* hb;
02547 
02548   g_get_current_time(&now);
02549   hb = icl_NewStruct("last_heartbeat", 1, icl_NewInt(now.tv_sec));
02550   com_UpdateInfo(connection, hb);
02551   icl_Free(hb);
02552 }
02553 
02554 /*
02555 static int oaa_last_heartbeat(char* connection)
02556 {
02557   ICLTerm* toFind = icl_NewStruct("last_heartbeat", 1, icl_NewVar("_"));
02558   ICLTerm* last;
02559   if(!com_GetInfo(connection, toFind, &last)) {
02560     return 0;
02561   }
02562   else {
02563     return icl_Int(icl_NthTerm(last, 1));
02564   }
02565 }
02566 */
02567 
02568 static void oaa_send_heartbeat_reply(char* conn)
02569 {
02570   ICLTerm* reply = icl_NewStruct("event", 2, icl_NewStr("ev_heartbeat_reply"), icl_NewList(NULL));
02571   com_SendTerm(conn, reply);
02572 }
02573 
02574 static void oaa_resend_unacked(char* connId)
02575 {
02576   ICLTerm* unackedMatcher = icl_NewStruct("unacked", 1, icl_NewVar("_"));
02577   ICLTerm* unacked;
02578   if(com_GetInfo(connId, unackedMatcher, &unacked)) {
02579     ICLListType* toSend;
02580     for(toSend = icl_List(unacked); toSend; toSend = icl_ListNext(toSend)) {
02581       com_SendTerm(connId, icl_ListElt(toSend));
02582     }
02583     icl_Free(unacked);
02584   }
02585 
02586   icl_Free(unackedMatcher);
02587 }
02588 
02589 static void oaa_handle_reconnect_handshake(ICLTerm* reconnectEvent)
02590 {
02591   char* connId = icl_Str(icl_NthTerm(reconnectEvent, 1));
02592   char* name = icl_Str(icl_NthTerm(reconnectEvent, 2));
02593   ICLTerm* reconnectTerm = icl_CopyTerm(icl_NthTerm(reconnectEvent, 3));
02594   ICLTerm* addressTerm = icl_CopyTerm(icl_NthTerm(reconnectEvent, 4));
02595   ICLTerm* nameTerm = icl_CopyTerm(icl_NthTerm(reconnectEvent, 5));
02596   ICLTerm* params = icl_NewList(NULL);
02597   icl_AddToList(params, reconnectTerm, FALSE);
02598   icl_AddToList(params, addressTerm, FALSE);
02599   icl_AddToList(params, nameTerm, FALSE);
02600 
02601   if(oaa_handshake(connId, name, params)) {
02602     oaa_resend_unacked(connId);
02603   }
02604   icl_Free(params);
02605 }
02606 
02613 EXPORT_MSCPP
02614 void EXPORT_BORLAND
02615 oaa_ProcessEvent(ICLTerm *Event, ICLTerm *Params)
02616 {
02617   if (icl_IsStr(Event) && STREQ(icl_Str(Event),"timeout")) {
02618     oaa_CheckTriggers("task", NULL, NULL);
02619 
02620     /* TBD: fill-in appropriate 2nd and 3rd arguments; NULLs supplied
02621      * as a stop gap.  REL
02622      */
02623     oaa_call_callback("app_idle", (ICLTerm *)NULL, (ICLTerm *)NULL, (ICLTerm *)NULL);
02624   }
02625   if(icl_IsStr(Event) && STREQ(icl_Str(Event), "ev_heartbeat")) {
02626     char* conn = oaa_getConnectionIdFromParams(Params);
02627     oaa_send_heartbeat_reply(conn);
02628     oaa_got_heartbeat(conn);
02629     free(conn);
02630   }
02631   else if(icl_IsStr(Event) && STREQ(icl_Str(Event), "ev_heartbeat_reply")) {
02632     char* conn = oaa_getConnectionIdFromParams(Params);
02633     oaa_got_heartbeat(conn);
02634     free(conn);
02635   }
02636   else if(icl_IsStruct(Event) && STREQ(icl_Str(Event), "ev_reconnected_needs_handshake")) {
02637     oaa_handle_reconnect_handshake(Event);
02638   }
02639   else {
02640     /* oaa_Interpret will add to solutions */
02641     ICLTerm *solutions = NULL;
02642     oaa_Interpret(Event, Params, &solutions);
02643     if(solutions != NULL) {
02644       icl_Free(solutions);
02645     }
02646     /* TO BE IMPLEMENTED
02647        oaa_CheckTriggers("task", NULL, NULL);
02648     */
02649   }
02650 }
02651 
02652 
02656 EXPORT_MSCPP
02657 void EXPORT_BORLAND
02658 oaa_SetTimeout(double NSecs)
02659 {
02660   if (NSecs < 0)
02661     oaa_timeout = 0.0;
02662   else oaa_timeout = NSecs;
02663 
02664   //oaa_TraceMsg("\n Setting event timeout to : %f\n", oaa_timeout, NULL);
02665 }
02666 
02667 
02684 EXPORT_MSCPP
02685 void EXPORT_BORLAND
02686 oaa_GetEvent(ICLTerm **Event, ICLTerm **Params, int LowestPriority)
02687 {
02688 
02689   double   TimeoutSecs = 0;
02690   int    FlushPriority = 0;
02691   ICLTerm *MoreEvents = icl_NewList(NULL);
02692 #ifdef UNNEEDED_DEBUG
02693   char    *debugString = NULL;
02694 #endif
02695 
02696   *Event = NULL;
02697 
02698   /* If at least one event can be found with an appropriate priority
02699    * from among the saved events, no timeout needed -- flush tcp
02700    * buffer, and read_all available
02701    * In other words, oaa_choose_event is called to :
02702    *   - Check if there is an event that matches the priority constraint
02703    *   - Therefore, choosing the timeout policy to be utilised in
02704    *     oaa_read_all_events that will actually read the socket.
02705    */
02706   if(icl_ListLen(oaa_saved_events) > 0) {
02707     TimeoutSecs = 0.01; // Since we have an event to process, we make sure
02708                         // we don't block on the socket
02709   }
02710   else {
02711     TimeoutSecs = oaa_timeout;
02712   }
02713   oaa_read_all_events(TimeoutSecs, (ICLListType **)&(MoreEvents->p),
02714           &FlushPriority);
02715   CHECK_LEAKS();
02716 
02717 #ifdef UNNEEDED_DEBUG
02718   {
02719     char* debugString = icl_NewStringFromTerm(MoreEvents);
02720     debugPrint(1, "%s:%i MoreEvents %s\n", __PRETTY_FUNCTION__, __LINE__, debugString);
02721     icl_stFree(debugString);
02722   }
02723 #endif /* UNNEEDED_DEBUG */
02724 
02725   /* if one of the new events has a flush in it, see if it
02726    *    flushes any of the saved events
02727    *    % note: MoreEvents have already been flushed by FlushPriority
02728    */
02729 
02730   if (oaa_saved_events) {
02731     oaa_flush_events(&oaa_saved_events, FlushPriority);
02732     icl_AppendCopy(oaa_saved_events, MoreEvents);
02733   }
02734   CHECK_LEAKS();
02735 
02736   /* DEBUG */
02737   /* printf("Saved events %s\n", icl_NewStringFromTerm(oaa_saved_events)); */
02738 
02739   if (!oaa_sort_and_get_event(oaa_saved_events, LowestPriority,
02740                               Event, Params)){
02741     icl_Free(*Event);
02742     *Event = icl_NewStr("timeout");
02743     *Params = icl_CopyTerm(ICL_EMPTY);
02744   }
02745   else {
02746     ICLTerm *t1;
02747 
02748     t1 = icl_NewStruct("event",
02749            2,
02750            icl_CopyTerm(*Event),
02751            icl_CopyTerm(*Params));
02752     oaa_CheckTriggers("comm", t1, "receive");
02753     icl_Free(t1);
02754   }
02755   icl_Free(MoreEvents);
02756   CHECK_LEAKS();
02757 
02758 }
02759 
02760 
02768 int oaa_sort_and_get_event(ICLTerm *EventList, int LowestPriority,
02769                            ICLTerm **Event, ICLTerm **Params)
02770 {
02771 
02772   ICLTerm *RawEvent;
02773 
02774   icl_SortList(EventList, oaa_priority_compare);
02775 
02776   if (oaa_choose_event(LowestPriority, EventList, &RawEvent)) {
02777     oaa_extract_event(RawEvent, Event, Params);
02778     icl_Free(RawEvent);
02779     return TRUE;
02780   }
02781   else return FALSE;
02782 }
02783 
02784 
02788 int oaa_priority_compare(ICLTerm *Elt1, ICLTerm *Elt2)
02789 {
02790   ICLTerm *param1, *param2;
02791   int p1 = 0, p2 = 0;
02792 
02793   oaa_extract_event_param(Elt1, "priority", &param1);
02794   oaa_extract_event_param(Elt2, "priority", &param2);
02795 
02796   if (icl_IsInt(param1))
02797     p1 = icl_Int(param1);
02798   else p1 = 5;
02799   if (icl_IsInt(param2))
02800     p2 = icl_Int(param2);
02801   else p2 = 5;
02802 
02803   icl_Free(param1);
02804   icl_Free(param2);
02805 
02806   return p1 >= p2;
02807 }
02808 
02809 
02815 int oaa_choose_event(int LowestPriority, ICLTerm *EventList, ICLTerm **Event) {
02816 
02817   if (EventList) {
02818     ICLListType *list = icl_List(EventList);
02819     ICLListType *prev = list;
02820     ICLTerm *p = NULL;
02821     ICLTerm *pAsStruct = NULL;
02822     int found = FALSE;
02823 
02824     if (Event) {
02825       *Event = NULL;
02826     }
02827 
02828     while (list && (list->elt != NULL) && !found) {
02829       oaa_extract_event_param(list->elt, "priority", &pAsStruct);
02830       if (pAsStruct) {
02831   p = icl_NthTerm(pAsStruct,1);
02832       }
02833 
02834       if (icl_IsInt(p) && (icl_Int(p) > LowestPriority)) {
02835   if (Event) {
02836     *Event = icl_CopyTerm(list->elt);
02837   }
02838   found = TRUE;
02839   icl_Free(pAsStruct);
02840 
02841   /* remove elt from list */
02842   if (list == prev) {   /* first element in list */
02843     EventList->p = list->next;
02844     icl_Free(list->elt);
02845     free(list);
02846     return TRUE;
02847   }
02848   else {
02849     prev->next = list->next;
02850     icl_Free(list->elt);
02851     free(list);
02852     return TRUE;
02853   }
02854       }
02855       if (pAsStruct) {
02856   icl_Free(pAsStruct);
02857       }
02858 
02859       prev = list;
02860       list = list->next;
02861     }
02862     /*
02863       if (found)
02864       free(list);
02865     */
02866     return found;
02867   }
02868   return FALSE;
02869 }
02870 
02885 int oaa_read_all_events(double TimeOut, ICLListType **Events,
02886                         int *FlushPriority)
02887 {
02888   ICLTerm *e = NULL, *ok_event = NULL, *param = NULL, *paramAsStruct = NULL;
02889   ICLListType *RestEvents = NULL;
02890   int RestFlushPriority = 0, p;
02891 
02892   CHECK_LEAKS();
02893   if(oaa_select_event(TimeOut, &e) == FALSE) {
02894     if(e != NULL) {
02895       icl_Free(e);
02896     }
02897     *Events = NULL;
02898     *FlushPriority = 0; /* need to set this? */
02899     CHECK_LEAKS();
02900     return FALSE;
02901   }
02902   CHECK_LEAKS();
02903 
02904   /* select event must have succeeded, check to see if returned
02905      event is a timeout */
02906   if(icl_IsStr(e) && STREQ(icl_Str(e), "timeout")) {
02907     *Events = NULL;
02908     *FlushPriority = 0;
02909     CHECK_LEAKS();
02910     return FALSE;
02911   } else {
02912     /* read one event so read all the rest
02913        Note timeout forced to some value != zero, so we do not block.
02914     */
02915     // double TimeoutSecs = 0.0001;
02916 
02917     CHECK_LEAKS();
02918     //oaa_read_all_events(TimeoutSecs, &RestEvents, &RestFlushPriority);
02919     /* check if read Event is acceptable (security hook) */
02920     CHECK_LEAKS();
02921     if(oaa_ValidateEvent(e, &ok_event)) {
02922       /* For oaa_ComTraceMsg */
02923       // the icl_NewStringFromTerm() below
02924       // can be expensive, so only do it if
02925       // com_trace is actually on
02926       if (oaa_com_trace_on) {
02927         char *debugStr;
02928         CHECK_LEAKS();
02929         debugStr = icl_NewStringFromTerm(ok_event);
02930         oaa_ComTraceMsg("\n[COM received]:\n %s\n", debugStr,NULL);
02931         icl_stFree(debugStr);
02932       }
02933 
02934       icl_Free(e);
02935       /* get event's priority */
02936       oaa_extract_event_param(ok_event, "priority", &paramAsStruct);
02937       if (paramAsStruct) {
02938   param = icl_NthTerm(paramAsStruct,1);
02939       }
02940 
02941       if(icl_IsInt(param)) {
02942   p = icl_Int(param);
02943       }
02944       else {
02945   p = 0; /* ??? - what should default action be? */
02946       }
02947 
02948       CHECK_LEAKS();
02949       /* if less than some higher priority flush event, discard
02950    event and perhaps notify sender */
02951       if(p < RestFlushPriority) {
02952   CHECK_LEAKS();
02953   /* event will be removed */
02954   oaa_flush_notification(ok_event);
02955   *FlushPriority = RestFlushPriority;
02956   *Events = RestEvents;
02957   icl_Free(ok_event);
02958   CHECK_LEAKS();
02959       }
02960       else {
02961   ICLTerm *flushevents;
02962   CHECK_LEAKS();
02963   flushevents = icl_NewTermFromData("flush_events(true)",18);
02964   /* keep event: not flushed */
02965   *Events = icl_NewCons(ok_event, RestEvents);
02966   CHECK_LEAKS();
02967 
02968   /* see if this event adds a flush: if so, record new flush
02969      priority */
02970   if(oaa_event_param(ok_event, flushevents)) {
02971     *FlushPriority = p;
02972   }
02973   else {
02974     *FlushPriority = RestFlushPriority;
02975   }
02976   icl_Free(flushevents);
02977   CHECK_LEAKS();
02978       }
02979       icl_Free(paramAsStruct);
02980       CHECK_LEAKS();
02981     } else {
02982       /* Not validated, skip event */
02983       printf("Invalid event\n");
02984       *Events = RestEvents;
02985       if(ok_event != NULL) {
02986   icl_Free(ok_event);
02987       }
02988       icl_Free(e);
02989       CHECK_LEAKS();
02990     }
02991   }
02992   CHECK_LEAKS();
02993   return FALSE;
02994 }
02995 
03005 int oaa_ValidateEvent(ICLTerm *E, ICLTerm **OkEvent)
03006 {
03007   /* if oaa_AppValidateEvent is defined, use it */
03008   /* ??? - I think this comment should read ...
03009      if oaa_AppValidateProperty is defined, use it */
03010 
03011   /* ??? - how to handle this mechanism of determining if a predicate
03012      is defined?*/
03013   /*
03014     predicate_property(user:oaa_AppValidateProperty(_,_), _),
03015     !,
03016     user:oaa_AppValidateProperty(E, OkEvent).
03017   */
03018 
03019   /* currently, no security checks are performed */
03020   *OkEvent = icl_CopyTerm(E);
03021   return TRUE;
03022 }
03023 
03027 int oaa_flush_events(ICLTerm **original_events, int flush_priority)
03028 {
03029   ICLListType *eventlist;
03030   ICLTerm* events = NULL;
03031 
03032   /* Not sure what action to take when incorrect data is passed in */
03033   /*
03034     if(!icl_IsList(events)) {
03035     return FALSE;
03036     }
03037   */
03038 
03039   events = *original_events;
03040   /* create an empty list */
03041   *original_events = icl_NewList(NULL);
03042 
03043   eventlist = icl_List(events);
03044   while(icl_ListHasMoreElements(eventlist)) {
03045     ICLTerm *event = icl_ListElement(eventlist);
03046     ICLTerm *param = NULL, *paramAsStruct = NULL;
03047     int p=0;
03048     /* get event's priority */
03049     oaa_extract_event_param(event, "priority", &paramAsStruct);
03050     if (paramAsStruct) {
03051       param = icl_NthTerm(paramAsStruct,1);
03052     }
03053 
03054     if(icl_IsInt(param)) {
03055       p = icl_Int(param);
03056     }
03057     if(p < flush_priority) {
03058       oaa_flush_notification(event);
03059     }
03060     else {
03061       icl_AddToList(*original_events, icl_CopyTerm(event), TRUE);
03062     }
03063     eventlist = icl_ListNextElement(eventlist);
03064     icl_Free(paramAsStruct);
03065   }
03066   icl_Free(events);
03067   return TRUE;
03068 }
03069 
03075 int oaa_flush_notification(ICLTerm *raw_event)
03076 {
03077   ICLTerm *event, *params, *notify_event;
03078 
03079   oaa_extract_event(raw_event, &event, &params);
03080   if(oaa_get_flush_notify(event, &notify_event)) {
03081     ICLTerm *emptyParams = icl_NewList(NULL);
03082     oaa_PostEvent(notify_event, emptyParams);
03083     icl_Free(emptyParams);
03084   }
03085   icl_Free(event);
03086   icl_Free(params);
03087   icl_Free(notify_event);
03088   return TRUE;
03089 }
03090 
03096 int oaa_get_flush_notify(ICLTerm *event, ICLTerm **notify_event)
03097 {
03098   /* set default return values */
03099   int result = FALSE;
03100   *notify_event = NULL;
03101   /* check to make sure event is a structure term */
03102   if(icl_IsStr(event)) {
03103     /* check to make sure it's a real event to be solved */
03104     char *functor = icl_Functor(event);
03105     if(STREQ(functor, "ev_solve")) {
03106       ICLTerm *id = icl_NthTerm(event, 1);
03107       ICLTerm *goal = icl_NthTerm(event, 2);
03108       ICLTerm *params = icl_NthTerm(event, 3);
03109       ICLTerm *reply_none = icl_NewTermFromData("reply(none)",11);
03110       if(!icl_GetParamValue(reply_none, params, NULL)) {
03111         ICLTerm *my_id;
03112         result = oaa_PrimaryAddress(&my_id);
03113         if(result) {
03114           /* ??? - Copy these terms for reuse in another solveable? */
03115           *notify_event = icl_NewStruct("ev_solved", 5,
03116                                         icl_CopyTerm(id),
03117                                         icl_CopyTerm(id),
03118                                         my_id,
03119                                         getEvSolvedGoal(goal),
03120                                         icl_CopyTerm(params),
03121                                         icl_NewList(NULL));
03122         }
03123       }
03124       icl_Free(reply_none);
03125     }
03126   }
03127   return result;
03128 }
03129 
03130 static void oaa_acked(char* connId, int ackNum)
03131 {
03132   ICLTerm* unackedMatcher = icl_NewStruct("unacked", 1, icl_NewVar("_"));
03133   ICLTerm* unackedTerm;
03134   ICLTerm* unackedList;
03135   ICLTerm* nextUnackedTerm = icl_NewStruct("unacked", 1, icl_NewList(NULL));
03136   ICLTerm* remainder = icl_NthTerm(nextUnackedTerm, 1);
03137   ICLListType* listElt;
03138   ICLTerm* sequenceMatcher = icl_NewStruct("sequence", 1, icl_NewVar("_"));
03139   ICLTerm* sequenceTerm;
03140 
03141   if(!com_GetInfo(connId, unackedMatcher, &unackedTerm)) {
03142     goto cleanup;
03143   }
03144   unackedList = icl_NthTerm(unackedTerm, 1);
03145   for(listElt = icl_List(unackedList); listElt != NULL; listElt = icl_ListNext(listElt)) {
03146     if(icl_Member(sequenceMatcher, icl_NthTerm(icl_ListElt(listElt), 2), &sequenceTerm)) {
03147       int eltSeqNum = icl_Int(icl_NthTerm(sequenceTerm, 1));
03148       if(oaa_SeqNumLessThan(ackNum, eltSeqNum)) {
03149         break;
03150       }
03151     }
03152     icl_Free(sequenceTerm);
03153   }
03154   for(; listElt != NULL; listElt = icl_ListNext(listElt)) {
03155     icl_AddToList(remainder, icl_CopyTerm(icl_ListElt(listElt)), TRUE);
03156   }
03157   icl_Free(unackedTerm);
03158 
03159   com_UpdateInfo(connId, nextUnackedTerm);
03160 
03161 cleanup:
03162   icl_Free(nextUnackedTerm);
03163   icl_Free(unackedMatcher);
03164   icl_Free(sequenceMatcher);
03165 }
03166 
03167 static void oaa_record_outgoing_event(char* connId, ICLTerm* event)
03168 {
03169   ICLTerm* unackedMatcher = icl_NewStruct("unacked", 1, icl_NewVar("_"));
03170   ICLTerm* unackedTerm;
03171   ICLTerm* unackedList;
03172   
03173   if(!com_GetInfo(connId, unackedMatcher, &unackedTerm)) {
03174     unackedTerm = icl_NewStruct("unacked", 1, icl_NewList(NULL));
03175   }
03176   unackedList = icl_NthTerm(unackedTerm, 1);
03177   icl_AddToList(unackedList, icl_CopyTerm(event), TRUE);
03178   com_UpdateInfo(connId, unackedTerm);
03179   icl_Free(unackedTerm);
03180   icl_Free(unackedMatcher);
03181 }
03182 
03183 static void oaa_update_seq_num(ICLTerm* event)
03184 {
03185   char* connId;
03186   if(!icl_IsStruct(event) || icl_NumTerms(event) != 2 || !STREQ(icl_Functor(event), "event")) {
03187     return;
03188   }
03189   else {
03190     ICLTerm* eventParams = icl_NthTerm(event, 2);
03191     ICLTerm* connMatcher = icl_NewStruct("connection_id", 1, icl_NewVar("_"));
03192     ICLTerm* sequenceMatcher = icl_NewStruct("sequence", 1, icl_NewVar("_"));
03193     ICLTerm* sequenceTerm;
03194     ICLTerm* connTerm;
03195   
03196     if(!icl_Member(connMatcher, eventParams, &connTerm)) {
03197       goto cleanup;
03198     }
03199     connId = icl_Str(icl_NthTerm(connTerm, 1));
03200   
03201     if(icl_Member(sequenceMatcher, eventParams, &sequenceTerm)) {
03202       ICLTerm* otherSequenceTerm = icl_NewStruct("other_sequence", 1, icl_CopyTerm(icl_NthTerm(sequenceTerm, 1)));
03203       com_UpdateInfo(connId, otherSequenceTerm);
03204       icl_Free(otherSequenceTerm);
03205       icl_Free(sequenceTerm);
03206     }
03207     icl_Free(connTerm);
03208   
03209 cleanup:
03210     icl_Free(connMatcher);
03211     icl_Free(sequenceMatcher);
03212   }
03213 }
03214 
03215 static void oaa_update_last_acked(ICLTerm* event)
03216 {
03217   char* connId;
03218   if(!icl_IsStruct(event) || icl_NumTerms(event) != 2 || !STREQ(icl_Functor(event), "event")) {
03219     return;
03220   }
03221   else {
03222     ICLTerm* eventParams = icl_NthTerm(event, 2);
03223     ICLTerm* connMatcher = icl_NewStruct("connection_id", 1, icl_NewVar("_"));
03224     ICLTerm* ackMatcher = icl_NewStruct("ack", 1, icl_NewVar("_"));
03225     ICLTerm* ackTerm;
03226     ICLTerm* connTerm;
03227   
03228     if(!icl_Member(connMatcher, eventParams, &connTerm)) {
03229       goto cleanup;
03230     }
03231     connId = icl_Str(icl_NthTerm(connTerm, 1));
03232   
03233     if(icl_Member(ackMatcher, eventParams, &ackTerm)) {
03234       ICLTerm* otherAckTerm = icl_NewStruct("other_acked", 1, icl_CopyTerm(icl_NthTerm(ackTerm, 1)));
03235       com_UpdateInfo(connId, otherAckTerm);
03236       oaa_acked(connId, icl_Int(icl_NthTerm(ackTerm, 1)));
03237       icl_Free(otherAckTerm);
03238       icl_Free(ackTerm);
03239     }
03240     icl_Free(connTerm);
03241   
03242 cleanup:
03243     icl_Free(connMatcher);
03244     icl_Free(ackMatcher);
03245   }
03246 }
03247 
03248 
03258 int oaa_select_event(double timeout, ICLTerm **event)
03259 {
03260   ICLTerm *in_event = NULL;
03261   ICLTerm *translated_event = NULL;
03262   char *connection_id;
03263 
03264   int selected = FALSE;
03265 
03266   selected = com_SelectEventFromAllIds(timeout, &in_event);
03267   CHECK_LEAKS();
03268   /*
03269   {
03270     char* inevent;
03271     inevent = icl_NewStringFromTerm(in_event);
03272     printf("oaa_select_event got term [%s]\n", inevent);
03273     icl_stFree(inevent);
03274   }
03275   */
03276 
03277   if(selected) {
03278 #ifdef FACILITATOR_OK
03279     oaa_translate_incoming_event(in_event, &translated_event);
03280 #else
03281     translated_event = in_event;
03282 #endif
03283 
03284     oaa_unwrap_event(translated_event, &connection_id, event);
03285     oaa_update_seq_num(*event);
03286     oaa_update_last_acked(*event);
03287     icl_stFree(connection_id);
03288     /*
03289     {
03290       char* unwrapped;
03291       unwrapped = icl_NewStringFromTerm(*event);
03292       printf("oaa_select_event got unwrapped term [%s]\n", unwrapped);
03293       icl_stFree(unwrapped);
03294     }
03295     */
03296   }
03297 
03298 
03299   /* ??? - should in_event be freed? */
03300 #ifdef FACILITATOR_OK
03301   icl_Free(in_event);
03302 #endif
03303   icl_Free(translated_event);
03304   CHECK_LEAKS();
03305   return selected;
03306 }
03307 
03308 
03327 /* timeout is the ONLY event that doesn't get embedded in event/2: */
03328 int oaa_unwrap_event(ICLTerm *in_event,
03329                      char **connection_id,
03330                      ICLTerm **out_event)
03331 {
03332   ICLTerm *content, *new_params;
03333   char *errfmt =
03334     "%s: incoming event from an unrecognized connection (%s):\n  %s\n";
03335 
03336   /* check to see if event is a timeout */
03337   if(icl_IsStr(in_event) && STREQ(icl_Str(in_event), "timeout")) {
03338     *connection_id = strdup("unknown");
03339     *out_event = icl_CopyTerm(in_event);
03340     return TRUE;
03341   }
03342 
03343   /* Get connection ID */
03344   *connection_id = com_GetDefaultConnectionId();
03345 
03346   /*
03347    * check to make sure in_event is of the form:
03348    * term(Connection, event(Content, Params))
03349    */
03350   if(icl_IsStruct(in_event)) {
03351     char *functor = icl_Functor(in_event);
03352 
03353     if(STREQ(functor, "term")) {
03354       /*
03355     This handles ev_connected/2
03356       */
03357       if(icl_NumTerms(in_event) == 1) {
03358   if (strlen(*connection_id) < strlen("unknown")) {
03359     icl_stFree(*connection_id);
03360     *connection_id = strdup("unknown");
03361   }
03362   else {
03363     strcpy(*connection_id, "unknown");
03364   }
03365   *out_event = icl_CopyTerm(icl_NthTerm(in_event, 1));
03366       }
03367       else if(icl_NumTerms(in_event) == 2) {
03368   /* everything appears to be OK, extract terms and create
03369      the new_params list */
03370   ICLTerm *res;
03371   ICLTerm *connection = icl_NthTerm(in_event, 1);
03372   ICLTerm *event = icl_NthTerm(in_event, 2);
03373   ICLTerm *params = icl_NthTerm(event, 2);
03374   ICLTerm *cid;
03375   ICLTerm *t1;
03376 
03377   content = icl_NthTerm(event, 1);
03378   t1 = icl_NewStruct("connection", 1, connection);
03379   if(!com_GetInfo(*connection_id, t1, &res)) {
03380     char *debug1 = icl_NewStringFromTerm(connection);
03381     char *debug2 = icl_NewStringFromTerm(icl_NthTerm(in_event, 2));
03382     fprintf(stderr, errfmt, "INTERNAL ERROR",
03383       debug1, debug2);
03384     *connection_id = strdup("unknown");
03385     icl_stFree(debug1);
03386     icl_stFree(debug2);
03387   }
03388   icl_Free(t1);
03389   icl_Free(res);
03390 
03391   /* ??? - in the following if-then-else block, reverse the
03392      order of from() and connection_id() in the new_params
03393      list from the prolog version for more convenient and
03394      easier to read control flow */
03395   if(oaa_from_param(*out_event)) {
03396     new_params = icl_CopyTerm(params);
03397   }
03398   else {
03399     ICLTerm *id, *from_id;
03400     if(oaa_content_fac_id(content, &id)) {
03401     }
03402     else if(oaa_is_parent_fac_id(*connection_id, &id)) {
03403     }
03404     else if(oaa_is_oaa_id(*connection_id, &id)) {
03405     }
03406     else {
03407       id = icl_NewStr("unknown");
03408     }
03409     from_id = icl_NewStruct("from", 1, id);
03410     new_params = icl_NewList(icl_NewCons(from_id, icl_ListCopy(params)));
03411   }
03412   cid = icl_NewStruct("connection_id", 1,
03413           icl_NewStr(*connection_id));
03414   icl_AddToList(new_params, cid, FALSE);
03415   *out_event = icl_NewStruct("event", 2, icl_CopyTerm(content), new_params);
03416       } /* end term/2 */
03417     } /* end term(X) */
03418     else {
03419       if (strlen(*connection_id) < strlen("unknown")) {
03420   icl_stFree(*connection_id);
03421   *connection_id = strdup("unknown");
03422       }
03423       else {
03424   strcpy(*connection_id, "unknown");
03425       }
03426     }
03427   }
03428   return TRUE;
03429 }
03430 
03431 /*
03432  * Helper function for oaa_unwrap_event().
03433  */
03434 int oaa_from_param(ICLTerm *event)
03435 {
03436   ICLTerm *from = icl_NewStruct("from", 1, icl_NewVar("_"));
03437 
03438   if(oaa_event_param(event, from)) {
03439     icl_Free(from);
03440     return TRUE;
03441   }
03442 
03443   icl_Free(from);
03444   return FALSE;
03445 }
03446 
03447 /*
03448  * Helper function for oaa_unwrap_event().
03449  */
03450 int oaa_content_fac_id(ICLTerm *content, ICLTerm **id)
03451 {
03452   if(icl_IsStruct(content)) {
03453     char *functor = icl_Functor(content);
03454     if(STREQ(functor, "ev_connected")) {
03455       /* get the value of InfoList */
03456       ICLTerm *res = NULL;
03457       ICLTerm *fac_id = icl_NewStruct("fac_id", 1, icl_NewVar("Id"));
03458       ICLTerm *infolist = icl_NthTerm(content, 1);
03459       if(icl_GetParamValue(fac_id, infolist, &res)) {
03460         *id = res;
03461         icl_Free(fac_id);
03462         return TRUE;
03463       }
03464       icl_Free(fac_id);
03465     }
03466   }
03467   return FALSE;
03468 }
03469 
03470 /*
03471  * Helper function for oaa_unwrap_event().
03472  */
03473 int oaa_is_parent_fac_id(char *connection_id, ICLTerm **id)
03474 {
03475   ICLTerm *res = NULL;
03476   ICLTerm *fac_id = icl_NewStruct("fac_id", 1, icl_NewVar("Id"));
03477   if(STREQ(connection_id, "parent"))
03478     if(com_GetInfo(connection_id, fac_id, &res)) {
03479       *id = res;
03480       icl_Free(fac_id);
03481       return TRUE;
03482     }
03483   icl_Free(fac_id);
03484   return FALSE;
03485 }
03486 
03487 /*
03488  * Helper function for oaa_unwrap_event().
03489  */
03490 int oaa_is_oaa_id(char *connection_id, ICLTerm **id)
03491 {
03492   ICLTerm *res = NULL;
03493   ICLTerm *oaa_id = icl_NewStruct("oaa_id", 1, icl_NewVar("Id"));
03494 
03495   if(com_GetInfo(connection_id, oaa_id, &res)) {
03496     *id = res;
03497     icl_Free(oaa_id);
03498     return TRUE;
03499   }
03500 
03501   icl_Free(oaa_id);
03502   return FALSE;
03503 }
03504 
03505 
03506 /***************************************************************************
03507  * name:    oaa_translate_incoming_event(+InEvent, -OutEvent).
03508  * NOT FULLY IMPLEMENTED YET
03509  * THIS FUNCTION IS ONLY FULLY NEEDED IF WE PORT THE FACILITATOR TO JAVA
03510  * purpose:
03511  *  Just makes a copy of the incoming raw_event.
03512  *****************************************************************************/
03513 int oaa_translate_incoming_event(ICLTerm *raw_event_in,
03514                                  ICLTerm **raw_event_out)
03515 {
03516 #ifdef FACILITATOR_OK
03517   /* check to see if raw_event_in is of the form term(_, event(_,_)) */
03518   ICLTerm *event_in, *contents;
03519   if(icl_IsStruct(raw_event_in) &&
03520      STREQ(icl_Functor(raw_event_in), "term")) {
03521     if((icl_IsStruct(event_in = icl_NthTerm(raw_event_in, 2))) &&
03522        (strcmp(icl_Functor(event_in), "event") == 0) &&
03523        (contents = icl_NthTerm(event_in, 1)) &&
03524        (icl_IsStruct(contents)) &&
03525        (strcmp(icl_Functor(contents), "ev_connect") == 0)) {
03526       /* ??? not sure whether to copy incoming event or just repackage it */
03527       ICLTerm *params = icl_NthTerm(event_in, 2);
03528       ICLTerm *arglist = icl_NewList(icl_Arguments(contents));
03529       /* alter contents slightly */
03530       ICLTerm *event_out =
03531         icl_NewStruct("event", 2,
03532                       icl_NewStructFromList("ev_connected", arglist),
03533                       params);
03534       *raw_event_out =
03535         icl_NewStruct("term", 2, icl_NthTerm(raw_event_in, 1), event_out);
03536       return;
03537     }
03538   } else {
03539     /* take care of case for generic input event */
03540     /* ??? what do to here */
03541   }
03542 #endif
03543   *raw_event_out = icl_CopyTerm(raw_event_in);
03544   return TRUE;
03545 }
03546 
03552 int oaa_extract_event(ICLTerm *raw_event, ICLTerm **content, ICLTerm **params)
03553 
03554 {
03555   /* check to make sure this is a structure term */
03556   if(icl_IsStruct(raw_event)) {
03557     char *functor = icl_Functor(raw_event);
03558     /* check to make sure it's an event */
03559     if(STREQ(functor, "event")) {
03560       *content = icl_CopyTerm(icl_NthTerm(raw_event, 1));
03561       *params = icl_CopyTerm(icl_NthTerm(raw_event, 2));
03562       return TRUE; /* always succeeds */
03563     }
03564 
03565   }
03566   *content = *params = NULL;
03567   return TRUE; /* always succeeds */
03568 }
03569 
03570 
03578 int oaa_event_param(ICLTerm *event, ICLTerm *param) {
03579   if(icl_IsStruct(event) &&
03580      STREQ(icl_Functor(event), "event") &&
03581      (icl_NumTerms(event) == 2)) {
03582 
03583     ICLTerm *params = icl_NthTerm(event, 2);
03584     return icl_ParamValue(icl_Str(param), NULL, params, NULL);
03585   }
03586   return FALSE;
03587 }
03588 
03595 int oaa_extract_event_param(ICLTerm *event, char *param, ICLTerm **result) {
03596   int res = FALSE;
03597 
03598   if(icl_IsStruct(event) &&
03599      STREQ(icl_Functor(event), "event") &&
03600      (icl_NumTerms(event) == 2)) {
03601     ICLTerm* paramAsTerm = icl_NewStruct(param, 1, icl_NewVar("_"));
03602     ICLTerm *params = icl_NthTerm(event, 2);
03603     res = icl_GetParamValue(paramAsTerm, params, result);
03604     icl_Free(paramAsTerm);
03605     return res;
03606   }
03607   return res;
03608 }
03609 
03620 int oaa_Interpret(ICLTerm *goal, ICLTerm *params, ICLTerm **solutions) {
03621   char *goalstr;
03622   if(icl_IsVar(goal)) { /* Not supposed to happen */
03623     return FALSE;
03624   }
03625   if(icl_IsStr(goal)) {
03626     if(STREQ((goalstr = icl_Str(goal)), "true")) {
03627       return TRUE;
03628     }
03629     if(STREQ(goalstr, "fail")) {
03630       return FALSE;
03631     }
03632     if(STREQ(goalstr, "false")) {
03633       return FALSE;
03634     }
03635   }
03636   if(icl_IsGroup(goal)) {
03637     char *startC=NULL, *sep;
03638     ICLListType *goal_list = icl_List(goal);
03639     icl_GetGroupChars(goal, startC, &sep);
03640     /*
03641      * ??? How to handle case (/+ P) ?
03642      * ??? How to handle cases like (P -> Q ; R) ?
03643      */
03644     switch(*sep) {
03645     case ',':
03646       while(icl_ListHasMoreElements(goal_list)) {
03647   ICLTerm *subgoal =
03648     icl_ListElement(icl_ListNextElement(goal_list));
03649   if(!oaa_Interpret(subgoal, params, solutions))
03650     return FALSE;
03651       }
03652       return TRUE;
03653     case ';':
03654       while(icl_ListHasMoreElements(goal_list)) {
03655   ICLTerm *subgoal =
03656     icl_ListElement(icl_ListNextElement(goal_list));
03657   if(oaa_Interpret(subgoal, params, solutions))
03658     return TRUE;
03659       }
03660       return FALSE;
03661     }
03662   }
03663   if(icl_IsStruct(goal) &&
03664      STREQ(icl_Functor(goal), "findall")) {
03665     /*
03666      * ??? Don't know how to do a findall in C
03667      */
03668   }
03669   if(icl_BuiltIn(goal)) {
03670     /* ??? What does it mean to "call(goal)"
03671        enumerate each case */
03672     return FALSE;
03673   }
03674   else {
03675     return oaa_exec_event(goal, params, solutions);
03676   }
03677 }
03678 
03684 int oaa_exec_event(ICLTerm *goal, ICLTerm *params, ICLTerm **solutions) {
03685   char *goalstr = icl_Str(goal);
03686   int res = FALSE;
03687   int arity = icl_NumTerms(goal);
03688   if(STREQ(goalstr, "ev_trace_on")) {
03689     oaa_trace_on = TRUE;
03690     printf("\nTrace on.\n");
03691     res = TRUE;
03692   }
03693   else if(STREQ(goalstr, "ev_trace_off")) {
03694     oaa_trace_on = FALSE;
03695     printf("\nTrace off.\n");
03696     res = TRUE;
03697   }
03698   else if(STREQ(goalstr, "ev_com_trace_on")) {
03699     oaa_com_trace_on = TRUE;
03700     printf("\nCOMMUNICATION PROTOCOL trace on.\n");
03701     res = TRUE;
03702   }
03703   else if(STREQ(goalstr, "ev_com_trace_off")) {
03704     oaa_com_trace_on = FALSE;
03705     printf("\nCOMMUNICATION PROTOCOL trace off.\n");
03706     res = TRUE;
03707   }
03708   else if(STREQ(goalstr, "ev_debug_on")) {
03709     oaa_debug_on = TRUE;
03710     printf("\nDebug on.\n");
03711     res = TRUE;
03712   }
03713   else if(STREQ(goalstr, "ev_debug_off")) {
03714     oaa_debug_on = FALSE;
03715     printf("\nDebug off.\n");
03716     res = TRUE;
03717   }
03718   else if(STREQ(goalstr, "ev_set_timeout")) {
03719     oaa_timeout = icl_Int(icl_NthTerm(goal, 1));
03720     printf("\nTimeout set to %f.\n", oaa_timeout);
03721     res = TRUE;
03722   }
03723   else if(STREQ(goalstr, "ev_set_timeout")) {
03724     oaa_timeout = icl_Int(icl_NthTerm(goal, 1));
03725     printf("\nTimeout set to %f.\n", oaa_timeout);
03726     res = TRUE;
03727   }
03728   else if (STREQ(goalstr, "ev_agent_disconnected")) {
03729     ICLTerm *lid = icl_CopyTerm(icl_NthTerm(goal, 1));
03730 
03731     oaa_remove_data_owned_by(lid);
03732     icl_Free(lid);
03733     res = TRUE;
03734   }
03735   else if (STREQ(goalstr, "ev_halt")) {
03736 
03737     ICLTerm *tmpArgs = icl_NewList(NULL);
03738 
03739     printf("\nDisconnecting...\n");
03740     com_Disconnect("parent");
03741     oaa_call_callback("app_done", NULL, tmpArgs, NULL);
03742     icl_Free(tmpArgs);
03743     exit(0);
03744   }
03745   else if(STREQ(goalstr, "ev_update_data") && (arity == 4)) {
03746 
03747     /* MAGIC BUG */
03748     res = oaa_handle_ev_update_data(goal, params);
03749   }
03750   else if(STREQ(goalstr, "ev_update_trigger") &&
03751       (arity == 6)) {
03752     res = oaa_handle_ev_update_trigger(goal, params);
03753   }
03754   else if(STREQ(goalstr, "ev_solve") && (arity == 3)) {
03755     res = oaa_handle_ev_solve(goal, params, solutions);
03756   }
03757   else if(STREQ(goalstr, "ev_solved") && (arity == 6)) {
03758     res = oaa_handle_ev_solved(goal, params);
03759   }
03760   else
03761     /***********************************************************
03762    Goal unifies with : oaa_Solve(Goal, Params)
03763     **********************************************************/
03764     if(STREQ(goalstr, "oaa_Solve") && (arity == 2)) {
03765       res = oaa_Solve(icl_NthTerm(goal,1), icl_NthTerm(goal,2), NULL, solutions);
03766     }
03767     else
03768       /*************************************************************
03769    Goal unifies with : oaa_PostEvent(Content , Params)
03770       *************************************************************/
03771       if(STREQ(goalstr, "oaa_PostEvent") && (arity == 2)) {
03772         res = oaa_PostEvent(icl_NthTerm(goal,1), icl_NthTerm(goal,2));
03773       }
03774       else
03775         /************************************************
03776    Goal unifies with : oaa_AddData(Clause, Params)
03777         ************************************************/
03778         if(STREQ(goalstr, "oaa_AddData") && (arity == 2)) {
03779           res = oaa_AddData(icl_NthTerm(goal,1), icl_NthTerm(goal,2), NULL);
03780         }
03781         else
03782           /*****************************************************************
03783    Goal unifies with : oaa_AddTrigger(Type, Condition, Action, Params)
03784           *******************************************************************/
03785           if(STREQ(goalstr, "oaa_AddTrigger") && (arity == 4)) {
03786             res = oaa_AddTrigger(icl_Str(icl_NthTerm(goal,1)), icl_NthTerm(goal,2),
03787                                  icl_NthTerm(goal,3), icl_NthTerm(goal,4), NULL);
03788           }
03789           else
03790           {
03791             res = oaa_handle_user_event(goal, params, solutions);
03792           }
03793   return res;
03794 }
03795 
03796 /*
03797  * Helper function for oaa_exec_event()
03798  */
03799 int oaa_handle_ev_update_data(ICLTerm *goal, ICLTerm *params)
03800 {
03801   ICLTerm *agent_id = NULL, *updaters = NULL, *requestees = NULL, *all_params = NULL;
03802   ICLTerm *mode = NULL, *id = NULL, *clause = NULL, *term_params = NULL;
03803   ICLTerm *t1 = NULL;
03804   int result = 0;
03805   char *modestr = NULL;
03806 
03807   mode = icl_NthTerm(goal, 2);
03808   id = icl_NthTerm(goal, 1);
03809   clause = icl_NthTerm(goal, 3);
03810   term_params = icl_NthTerm(goal, 4);
03811   modestr = icl_Str(mode);
03812   all_params = NULL;
03813 
03814   oaa_PrimaryAddress(&agent_id);
03815   requestees = icl_NewList(icl_NewCons(agent_id,NULL));
03816   icl_append_to_list(term_params, params, &all_params);
03817   if(!all_params) {
03818     all_params = icl_NewList(NULL);
03819   }
03820   /*
03821    * Changing the calling order here a little bit from prolog to C for
03822    * the sake of efficiency - sws
03823    */
03824   if(STREQ(modestr, "add")) {
03825     result = oaa_add_data_local(clause, all_params);
03826   }
03827   else if(STREQ(modestr, "remove")) {
03828     result = oaa_remove_data_local(clause, all_params);
03829   }
03830   else if(STREQ(modestr, "replace")) {
03831     result = oaa_replace_data_local(clause, all_params);
03832   }
03833   else {
03834     result = FALSE;
03835   }
03836   t1 = icl_NewTermFromData("reply(none)",11);
03837   if(!icl_GetParamValue(t1, params, NULL)) {
03838     ICLTerm *new_term;
03839     ICLTerm *emptyList;
03840     if(result) {
03841       updaters = icl_NewList(icl_NewCons(agent_id, NULL));
03842     }
03843     else {
03844       updaters = icl_NewList(NULL);
03845     }
03846     new_term =
03847       icl_NewStruct("ev_data_updated", 6,
03848                     icl_CopyTerm(id),
03849                     icl_CopyTerm(mode),
03850                     icl_CopyTerm(clause),
03851                     icl_CopyTerm(params),
03852                     requestees,
03853                     updaters);
03854     emptyList = icl_NewList(NULL);
03855     oaa_PostEvent(new_term, emptyList);
03856     icl_Free(new_term);
03857     icl_Free(emptyList);
03858   }
03859   icl_Free(t1);
03860   icl_Free(requestees);
03861   icl_Free(updaters);
03862   icl_Free(all_params);
03863   return TRUE;
03864 }
03865 
03866 /*
03867  * Helper function for oaa_exec_event()
03868  */
03869 int oaa_handle_ev_update_trigger(ICLTerm *goal, ICLTerm *params)
03870 {
03871   ICLTerm *id = icl_NthTerm(goal, 1);
03872   ICLTerm *mode = icl_NthTerm(goal, 2);
03873   char *type = icl_Str(icl_NthTerm(goal, 3));
03874   ICLTerm *condition = icl_NthTerm(goal, 4);
03875   ICLTerm *action = icl_NthTerm(goal, 5);
03876   ICLTerm *trig_params = icl_NthTerm(goal, 6);
03877   ICLTerm *agent_id, *new_term, *updaters, *all_params;
03878   ICLTerm *t1 = NULL;
03879   ICLTerm *emptyList = NULL;
03880   char *modestr = icl_Str(mode);
03881   int result = FALSE;
03882   oaa_PrimaryAddress(&agent_id);
03883   all_params = NULL;
03884   icl_append_to_list(trig_params, params, &all_params);
03885   if(!all_params) {
03886     all_params = NULL;
03887   }
03888 
03889   /*
03890    * Changing the calling order here a little bit from prolog to C for
03891    * the sake of efficiency - sws
03892    */
03893   if (STREQ(modestr, "add")) {
03894     result = oaa_add_trigger_local(type, condition, action, all_params);
03895   }
03896   else if (STREQ(modestr, "remove")) {
03897     result = oaa_remove_trigger_local(type, condition, action, all_params);
03898   }
03899   else {
03900     result = FALSE;
03901   }
03902 
03903   if (!icl_GetParamValue((t1 = icl_NewTermFromData("reply(none)",11)),
03904                          params, NULL)) {
03905     if (result) {
03906       updaters = icl_NewList(icl_NewCons(agent_id, NULL));
03907     }
03908     else {
03909       updaters = icl_NewList(NULL);
03910     }
03911     new_term = icl_NewStruct("ev_trigger_updated", 8,
03912                              icl_CopyTerm(id),
03913                              icl_CopyTerm(mode),
03914                              icl_NewStr(type),
03915                              icl_CopyTerm(condition),
03916                              icl_CopyTerm(action),
03917                              icl_CopyTerm(params),
03918                              icl_CopyTerm(updaters),
03919                              icl_CopyTerm(updaters));
03920     emptyList = icl_NewList(NULL);
03921     oaa_PostEvent(new_term, emptyList);
03922     icl_Free(emptyList);
03923     icl_Free(new_term);
03924     icl_Free(updaters);
03925   }
03926   icl_Free(t1);
03927   icl_Free(all_params);
03928   /*
03929     if (STREQ(modestr, "add"))
03930     oaa_Inform(icl_NewStr("trigger"), "trigger_added(%s, %s, %s, %s)\n",
03931     type, condition, action, all_params);
03932   */
03933   return TRUE;
03934 }
03935 
03936 /*
03937  * Helper function for oaa_exec_event().  Finds all occurances
03938  * of context(X) on a list of params and returns list of values.
03939  */
03940 int oaa_find_all_contexts(ICLTerm *params, ICLTerm **contexts) {
03941   ICLTerm *context, *test;
03942   ICLListType *p;
03943   if(!icl_IsList(params))
03944     return FALSE;
03945   test = icl_NewStruct("context", 1, icl_NewVar("X"));
03946   p = icl_List(params);
03947   *contexts = NULL;
03948   while(p) {
03949     if(icl_Unify(test, p->elt, &context)) {
03950       if(*contexts == NULL) {
03951         *contexts = icl_NewList(NULL);
03952       }
03953       icl_AddToList(*contexts, context, TRUE);
03954     }
03955     p = p->next;
03956   }
03957   if(*contexts == NULL) {
03958     *contexts = icl_NewList(NULL);
03959   }
03960   icl_Free(test);
03961   return TRUE;
03962 }
03963 
03964 /*
03965  * Helper function for oaa_exec_event()
03966  */
03967 int oaa_handle_ev_solved(ICLTerm *goal, ICLTerm *params) {
03968   ICLTerm *local_params = icl_NthTerm(goal, 5);
03969   ICLTerm *local_callback = NULL;
03970   char* local_callback_id;
03971   int res;
03972   ICLTerm* request_for_callback = icl_NewTermFromData("callback(X)",11);
03973   (void)params;
03974 
03975   if (icl_GetParamValue(request_for_callback, local_params, &local_callback)) {
03976     local_callback_id = icl_Str(icl_NthTerm(local_callback,1));
03977   }
03978   else {
03979     local_callback_id = "app_do_event";
03980   }
03981 
03982   icl_Free(request_for_callback);
03983   res = oaa_call_callback(local_callback_id, goal, local_params, NULL);
03984   icl_Free(local_callback);
03985   return res;
03986 }
03987 
03988 /*
03989  * Helper function for oaa_exec_event()
03990  */
03991 int oaa_handle_ev_solve(ICLTerm *goal, ICLTerm *params, ICLTerm **solutions) {
03992   ICLTerm *id = icl_NthTerm(goal, 1);
03993   ICLTerm *full_goal = icl_NthTerm(goal, 2);
03994   ICLTerm *solve_params = icl_NthTerm(goal, 3);
03995   ICLTerm *goal_params, *contexts;
03996   ICLTerm *tmp1, *tmp2, *user_id;
03997   ICLTerm *t1 = NULL;
03998   ICLTerm *t2 = NULL;
03999   ICLTerm *inherited_params;
04000   ICLTerm *all_params;
04001 
04002   if(!oaa_class("leaf"))
04003     return FALSE;
04004 
04005   inherited_params = NULL;
04006   all_params = NULL;
04007   icl_GoalComponents(full_goal, &tmp1, &tmp2, &goal_params);
04008   icl_Free(tmp1);
04009   icl_Free(tmp2);
04010 
04011   /*
04012    * More "local" params take precedence, so they to go the
04013    * beginning of the list
04014    */
04015   icl_append_to_list(solve_params, params, &inherited_params);
04016   icl_append_to_list(goal_params, inherited_params, &all_params);
04017   icl_Free(goal_params);
04018 
04019   /* Assert context */
04020   oaa_find_all_contexts(all_params, &contexts);
04021   oaa_assert_current_contexts(id, contexts);
04022 
04023   //oaa_TraceMsg("\n\nAttempting to solve: \n  Goal:%s\n  Params:%s\n", full_goal, inherited_params, NULL);
04024 
04025   /*
04026    * oaa_solve_local() will have to be one of those routines in C that
04027    * have an extra parameter beyond it's prolog counterpart.  The extra
04028    * parameter is a list of terms to simulate findall/3 behavior
04029    */
04030   *solutions = icl_NewList(NULL);
04031   oaa_solve_local(full_goal, inherited_params, solutions);
04032 
04033 #ifdef UNNEEDED_DEBUG
04034   oaa_TraceMsg("\nSolutions found for %s:\n  %s\n",
04035                icl_NewStringFromTerm(full_goal),
04036                icl_NewStringFromTerm(*solutions),NULL);
04037 #endif /* UNNEEDED_DEBUG */
04038 
04039   /*
04040    * If user has requested to delay the solution (oaaDelaySolution)
04041    * save current userId, Goal and Params in delay table, to be
04042    * sent back in an ev_solved() msg later (oaaReturnDelayedSolutions).
04043    */
04044   if(oaa_retract_delay(id, &user_id)) {
04045     oaa_assert_delay_table(icl_CopyTerm(id), icl_CopyTerm(user_id), icl_CopyTerm(full_goal), icl_CopyTerm(solve_params), icl_CopyTerm(all_params));
04046   } else {
04047     ICLTerm* request = icl_NewTermFromData("reply(none)",11);
04048     ICLTerm* post_params = NULL;
04049     int no_reply =  icl_GetParamValue(request, all_params, NULL);
04050     ICLTerm *from_ks = NULL;
04051     oaa_PrimaryAddress(&from_ks);
04052 
04053     if (!no_reply && !STREQ(icl_Str(from_ks), "unknown")) {
04054       ICLTerm *new_event =
04055         icl_NewStruct("ev_solved", 6,
04056                       icl_CopyTerm(id),
04057                       icl_NewList(icl_NewCons(icl_CopyTerm(from_ks), NULL)),
04058                       icl_NewList(icl_NewCons(icl_CopyTerm(from_ks), NULL)),
04059                       getEvSolvedGoal(full_goal),
04060                       icl_CopyTerm(solve_params),
04061                       icl_CopyTerm(*solutions));
04062       /* DEBUG
04063          printf("***************\n");
04064          printf("%s\n", icl_NewStringFromTerm(new_event));
04065          printf("***************\n");
04066       */
04067       post_params = icl_NewList(NULL);
04068 
04069       // if connection_id is given, the message goes there.
04070       t1 = icl_NewStruct("connection_id", 1, icl_NewVar("_"));
04071       if (icl_GetParamValue(t1, params, &t2)) {
04072         icl_AddToList(post_params, icl_CopyTerm(t2), FALSE);
04073       }
04074       icl_Free(t1);
04075       if (t2 != NULL) {
04076         icl_Free(t2);
04077       }
04078 
04079       oaa_PostEvent(new_event, post_params);
04080       icl_Free(new_event);
04081       icl_Free(post_params);
04082     }
04083     if(from_ks != NULL) {
04084       icl_Free(from_ks);
04085     }
04086     icl_Free(request);
04087   }
04088   oaa_retractall_current_contexts(id);
04089 
04090   icl_Free(inherited_params);
04091   icl_Free(all_params);
04092 
04093   return TRUE;        /* what to return here? */
04094 
04095 } // end of oaa_handle_ev_solve
04096 
04097 ICLTerm *valid_oaa_solvables() {
04098   if(oaa_solvables == NULL) {
04099     oaa_solvables = icl_NewList(NULL);
04100     return oaa_solvables;
04101   }
04102   else {
04103     return oaa_solvables;
04104   }
04105 }
04106 
04107 static char* CALLBACK_PARAM = "callback(CB)";
04108 
04109 /*
04110  * Helper function for oaa_exec_event()
04111  */
04112 int oaa_handle_user_event(ICLTerm *event,  ICLTerm *params, ICLTerm **solutions) {
04113   ICLTerm *goal = NULL, *matched = NULL;
04114   ICLTerm *solvables = valid_oaa_solvables();
04115   int res = FALSE;
04116   oaa_turn_on_debug();
04117 
04118   oaa_goal_matches_solvables(event, solvables, &goal, &matched);
04119 
04120   if (matched && icl_IsStruct(matched) &&
04121       STREQ(icl_Functor(matched), "solvable")) {
04122 
04123     int (*callback_proc)(ICLTerm*, ICLTerm*, ICLTerm*)=NULL;
04124 
04125     ICLTerm* solv_params = icl_NthTerm(matched, 2);
04126     ICLTerm* tempRequest = icl_NewTermFromData(CALLBACK_PARAM, strlen(CALLBACK_PARAM));
04127     ICLTerm* cb = NULL;
04128     icl_GetParamValue(tempRequest, solv_params, &cb);
04129     icl_Free(tempRequest);
04130 
04131     /* Check if we have a specific callback for this solvable */
04132     if (cb) {
04133       oaa_GetCallback(icl_Str(icl_NthTerm(cb,1)), &callback_proc);
04134       icl_Free(cb);
04135     }
04136 
04137     if (callback_proc) {
04138       callback_proc(event, params, *solutions);
04139     }
04140     oaa_turn_off_debug();
04141     res = TRUE;
04142   }
04143   if(goal) {
04144     icl_Free(goal);
04145   }
04146   if(matched) {
04147     icl_Free(matched);
04148   }
04149   return res;
04150 }
04151 
04152 /*
04153  * What to do about test(TEST)?
04154  * if test(TEST) is listed in arguments, solve
04155  *    it locally.
04156  */
04157 int passes_tests(ICLTerm *params)
04158 {
04159   ICLTerm *test;
04160   ICLTerm *results;
04161   ICLTerm *t1;
04162   int returnValue = TRUE;
04163 
04164   if (oaa_class("leaf")) {
04165     t1 = icl_NewStruct("test", 1, icl_NewVar("Test"));
04166     if (icl_GetParamValue(t1, params, &test)) {
04167       ICLTerm *emptyList = icl_NewList(NULL);
04168       returnValue = oaa_Solve(test, emptyList, &results, NULL);
04169       icl_Free(emptyList);
04170       icl_Free(results);
04171     }
04172     else {
04173       returnValue = TRUE;
04174     }
04175     icl_Free(t1);
04176   }
04177   else if(oaa_class("root") || oaa_class("node")) {
04178     /*
04179      * With compound goals, we also want to allow tests on the facilitator.
04180      * @@DLM: Is this the best way?
04181      */
04182     t1 = icl_NewStruct("test", 1, icl_NewVar("Test"));
04183     if(icl_GetParamValue(t1, params, &test)) {
04184       ICLTerm *emptyList = icl_NewList(NULL);
04185       (void)oaa_solve_local(test, emptyList, &results);
04186       icl_Free(emptyList);
04187       icl_Free(results);
04188     }
04189     else {
04190       returnValue = FALSE;
04191     }
04192 
04193     icl_Free(t1);
04194   }
04195   return returnValue;
04196 }
04197 
04203 int oaa_DelaySolution(ICLTerm *id) {
04204   ICLTerm *goal_id, *tmp;
04205   /*
04206    * ??? retrieve the first one for now, multiple solutions may be required
04207    */
04208   if(oaa_retrieve_nth_current_contexts(&goal_id, &tmp, 0)) {
04209     oaa_assert_delay(goal_id, id);
04210     return TRUE;
04211   }
04212   return FALSE;
04213 }
04214 
04219 int oaa_ReturnDelayedSolutions(ICLTerm *id, ICLTerm *solution_list)
04220 {
04221   ICLTerm *goal_id, *goal, *solve_params, *all_params;
04222   ICLTerm *solutions = icl_NewList(NULL);
04223   ICLTerm *from_ks;
04224 
04225   if(oaa_retract_delay_table(&goal_id, id, &goal, &solve_params,
04226                              &all_params)) {
04227     ICLTerm *t1;
04228 
04229     t1 = icl_NewTermFromData("reply(none)",11);
04230     if(!icl_GetParamValue(t1, all_params, NULL)) {
04231       ICLListType *slist;
04232 
04233       if(!oaa_PrimaryAddress(&from_ks)) {
04234         from_ks = icl_NewStr("unknown");
04235       }
04236 
04237       /* make sure all Solutions unify with the original goal */
04238       slist = icl_List(solution_list);
04239 
04240       while(icl_ListHasMoreElements(slist)) {
04241         ICLTerm *soln = icl_ListElement(slist);
04242 
04243         if(icl_Unify(goal, soln, NULL)) {
04244           icl_AddToList(solutions, icl_CopyTerm(soln), TRUE);
04245         }
04246         slist = icl_ListNextElement(slist);
04247       }
04248 
04249       if(icl_NumTerms(solutions) > 0) {
04250         ICLTerm* requestees = icl_NewList(NULL);
04251         ICLTerm* responders;
04252         ICLTerm *eventToPost;
04253         icl_AddToList(requestees, icl_CopyTerm(from_ks), 1);
04254         responders = icl_CopyTerm(requestees);
04255         eventToPost = icl_NewStruct("ev_solved", 6, icl_CopyTerm(goal_id),
04256                                              requestees, responders, getEvSolvedGoal(goal), icl_CopyTerm(solve_params),
04257                                              solutions);
04258         (void)oaa_PostEvent(eventToPost, NULL);
04259         icl_Free(goal_id);
04260         icl_Free(goal);
04261         icl_Free(solve_params);
04262         icl_Free(all_params);
04263         icl_Free(from_ks);
04264         icl_Free(eventToPost);
04265       }
04266       else {
04267         icl_Free(goal_id);
04268         icl_Free(goal);
04269         icl_Free(solve_params);
04270         icl_Free(all_params);
04271         icl_Free(from_ks);
04272         icl_Free(t1);
04273         return FALSE;
04274       }
04275     } else {
04276       icl_Free(t1);
04277       return FALSE;
04278     }
04279     icl_Free(t1);
04280   }
04281   else
04282   {
04283     return FALSE;
04284   }
04285   return TRUE;
04286 }
04287 
04305  /*
04306  *  example:
04307  *      oaa_AppDoEvent(goal(_X),_Params) :-  oaa_DelayEvent(a_goal).
04308  *      oaa_AppDoEvent(temp_event(Y),_Params) :-
04309  *    oaa_AddDelayedContextParams(a_goal, [], P),
04310  *    oaa_Solve(sub_goal(Y), P).
04311  *      oaa_AppDoEvent(final_event(S), _Params) :-
04312  *    oaa_ReturnDelayedSolutions(a_goal, [goal(S)]).
04313  *
04314  *  remarks: *new_params points to newly allocated memory--remember to call
04315  *      icl_Free(*new_params)
04316  *
04317  */
04318 int oaa_AddDelayedContextParams(ICLTerm *id, ICLTerm *params,
04319                                 ICLTerm **new_params)
04320 {
04321   ICLTerm *goal_id, *goal, *solve_params, *all_params;
04322   ICLTerm *contexts = icl_NewList(NULL);
04323 
04324   if (oaa_retract_delay_table(&goal_id, id, &goal,
04325                               &solve_params, &all_params)) {
04326     ICLListType *allparamlist = icl_List(all_params);
04327 
04328     while (icl_ListHasMoreElements(allparamlist)) {
04329       ICLTerm *param = icl_ListElement(allparamlist);
04330       ICLTerm *context;
04331       ICLTerm *t1;
04332 
04333       t1 = icl_NewStruct("context", 1, icl_NewVar("C"));
04334       if (icl_Unify(t1, param, &context))
04335         icl_AddToList(contexts, context, TRUE);
04336 
04337       allparamlist = icl_ListNextElement(allparamlist);
04338       icl_Free(t1);
04339     }
04340     if (icl_NumTerms(contexts) > 0) {
04341       icl_append_to_list(contexts, params, new_params);
04342       return TRUE;
04343     }
04344   }
04345   return FALSE;
04346 }
04347 
04348 /****************************************************************************
04349  * Agent-Facilitator communication
04350  ****************************************************************************/
04351 
04352 int oaa_address_to_comm_id(ICLTerm *inAddress, char **commId)
04353 {
04354   ICLTerm* tempRequest;
04355   int res;
04356 
04357   tempRequest = icl_NewStruct("other_address", 1, icl_CopyTerm(inAddress));
04358   res = com_GetConnectionFromInfo(tempRequest, commId);
04359   icl_Free(tempRequest);
04360   return res;
04361 }
04362 
04381 int oaa_PostEvent(ICLTerm *contents, ICLTerm *params)
04382 {
04383   ICLTerm *send_event;
04384   ICLTerm *destvar  = icl_NewVar("Dest"), *dest;
04385   ICLTerm *dest_id, *trans_event, *arglist;
04386   ICLTerm *t1 = (ICLTerm *)NULL, *t2 = (ICLTerm *)NULL;
04387   char *comm_id = NULL;
04388 
04389   /* See if any params are of interest.
04390    */
04391   t1 = icl_NewStruct("priority", 1, icl_NewVar("_"));
04392   t2 = icl_NewStruct("from", 1, icl_NewVar("_"));
04393 
04394   if (memberchk(t1, params) || memberchk(t2, params)) {
04395 
04396     send_event = icl_NewStruct("event", 2, icl_CopyTerm(contents),
04397                                icl_CopyTerm(params));
04398   }
04399   else {
04400     send_event = icl_NewStruct("event", 2, icl_CopyTerm(contents),
04401                                icl_NewList(NULL));
04402   }
04403   icl_Free(t1);
04404   icl_Free(t2);
04405 
04406   // If connection_id is given, the message goes there.
04407   t1 = icl_NewStruct("connection_id", 1, icl_NewVar("_"));
04408   if (icl_GetParamValue(t1, params, &t2)) {
04409     comm_id = strdup(icl_Str(icl_NthTerm(t2,1)));
04410   }
04411   icl_Free(t1);
04412   icl_Free(t2);
04413 
04414   /* Find destination: if none, dest = server */
04415   t1 = icl_NewStruct("address", 1, icl_CopyTerm(destvar));
04416   if (!icl_GetParamValue(t1, params, &dest)) {
04417     dest = icl_NewStr("parent");
04418   }
04419   icl_Free(t1);
04420 
04421   icl_standardize_addressee(dest, &dest_id);
04422 
04423   arglist = icl_NewList(NULL);
04424   icl_AddToList(arglist, dest, FALSE);
04425 
04426 #ifdef UNNEEDED_DEBUG
04427   oaa_ComTraceMsg("\n[COM send to %s]:\n  %s\n",
04428                   icl_NewStringFromTerm(dest_id),
04429                   icl_NewStringFromTerm(arglist), NULL);
04430 #endif //UNNEEDED_DEBUG
04431   if (comm_id == NULL) {
04432     oaa_address_to_comm_id(dest_id, &comm_id);
04433   }
04434   oaa_translate_outgoing_event(send_event, dest_id, comm_id, &trans_event);
04435   icl_AddToList(arglist, trans_event, TRUE);
04436   oaa_record_outgoing_event(comm_id, trans_event);
04437 
04438   /* send event to destination */
04439   com_SendTerm(comm_id, trans_event);
04440   icl_stFree(comm_id);
04441   /*
04442    * Use SendEvent here, because triggers always contain event/2
04443    * to unify with
04444    */
04445   oaa_CheckTriggers("comm", send_event, "send");
04446   icl_Free(destvar);
04447   icl_Free(dest_id);
04448   icl_Free(send_event);
04449   icl_Free(arglist);  /* this call frees "dest" too */
04450   return TRUE;
04451 } // end of oaa_PostEvent
04452 
04453 int oaa_convert_id_to_comm_id(ICLTerm *id, ICLTerm **cid)
04454 {
04455   char *connid;
04456   int res = FALSE;
04457   ICLTerm *fid = icl_NewStruct("fac_id", 1, icl_NewVar("FId"));
04458   ICLTerm *oid = icl_NewStruct("oaa_id", 1, icl_NewVar("FId"));
04459   (void)id;
04460 
04461   /*
04462    * ??? Prolog calling sequence has com_GetInfo being called with the
04463    * the first argument an uninstantiated variable
04464    * (  com:com_GetInfo(CId, oaa_id(Id)) )
04465    * but the C version of GetInfo doesn't allow this.
04466    * Use com_GetConnectionId(char **, ICLTerm *) instead
04467    */
04468   if(com_GetConnectionId(&connid, fid) ||
04469      com_GetConnectionId(&connid, oid)) {
04470     *cid = icl_NewStr(connid);
04471     res = TRUE;
04472   }
04473   icl_Free(fid);
04474   icl_Free(oid);
04475   return res;
04476 }
04477 
04487 int oaa_translate_outgoing_event(ICLTerm *event, ICLTerm *dest_id, char* commId,
04488                                  ICLTerm **new_event) {
04489   ICLTerm *contents;
04490   ICLTerm *params;
04491   int nextOutSeqNum;
04492   int lastSeenSeqNum;
04493   ICLTerm *lastOutSeqNumTerm = NULL;
04494   ICLTerm *lastSeenSeqNumTerm = NULL;
04495   ICLTerm *ackTerm = NULL;
04496   ICLTerm *seqNumTerm = NULL;
04497   (void)dest_id;
04498 
04499   if(!oaa_outSeqNum_matcher) {
04500     oaa_outSeqNum_matcher = icl_NewStruct("sequence", 1, icl_NewVar("_"));
04501   }
04502   if(!oaa_lastSeenSeqNum_matcher) {
04503     oaa_lastSeenSeqNum_matcher = icl_NewStruct("ack", 1, icl_NewVar("_"));
04504   }
04505 
04506   com_GetInfo(commId, oaa_outSeqNum_matcher, &lastOutSeqNumTerm);
04507   if(lastOutSeqNumTerm) {
04508     nextOutSeqNum = icl_Int(icl_NthTerm(lastOutSeqNumTerm, 1)) + 1;
04509     seqNumTerm = icl_NewStruct("sequence", 1, icl_NewInt(nextOutSeqNum));
04510     com_UpdateInfo(commId, seqNumTerm);
04511     icl_Free(lastOutSeqNumTerm);
04512   }
04513 
04514   com_GetInfo(commId, oaa_lastSeenSeqNum_matcher, &lastSeenSeqNumTerm);
04515   if(lastSeenSeqNumTerm) {
04516     lastSeenSeqNum = icl_Int(icl_NthTerm(lastSeenSeqNumTerm, 1));
04517     ackTerm = icl_NewStruct("ack", 1, icl_NewInt(lastSeenSeqNum));
04518     icl_Free(lastSeenSeqNumTerm);
04519   }
04520 
04521   /*
04522    * Special cases.  There's no need to translate these.  And, it could be
04523    * problematical, because we don't yet know the language and version of
04524    * the receiver.  See comments for oaa_unwrap_event.
04525    */
04526   if(icl_IsStruct(event) &&
04527      STREQ(icl_Functor(event), "event")) {
04528     if(icl_IsStruct(contents = icl_NthTerm(event, 1)) &&
04529        (STREQ(icl_Functor(contents), "ev_connect") ||
04530         STREQ(icl_Functor(contents), "ev_connected"))) {
04531       *new_event = icl_CopyTerm(event);
04532       params = icl_NthTerm(*new_event, 2);
04533       if(!STREQ(icl_Functor(contents), "ev_connected")) {
04534         if(seqNumTerm) {
04535           icl_AddToList(params, seqNumTerm, FALSE);
04536         }
04537       }
04538       if(ackTerm) {
04539         icl_AddToList(params, ackTerm, FALSE);
04540       }
04541       return TRUE;
04542     } else {
04543       /*
04544        * ??? I'm going to noop the rest of this for now because it depends
04545        * on some really weird stuff, including looking for a function in
04546        * the user module, which we can't do in C.
04547        * This is going to require yet another modification to GetInfo,
04548        * one that looks up both the connection ID and a parameter from
04549        * the connection_info predicate
04550        */
04551     }
04552   }
04553 #if 0
04554   /*
04555    * default action is to return the incoming event (no copy)
04556    */
04557   *new_event = event;
04558 #endif
04559 
04560   /*
04561    * Until reference count in ICLTerm is implemented, default is to
04562    * make a copy of the event. (Ruth Lang, 12/21/99)
04563    */
04564   *new_event =  icl_CopyTerm(event);
04565   params = icl_NthTerm(*new_event, 2);
04566   if(seqNumTerm) {
04567     icl_AddToList(params, seqNumTerm, FALSE);
04568   }
04569   if(ackTerm) {
04570     icl_AddToList(params, ackTerm, FALSE);
04571   }
04572   return TRUE;
04573 }
04574 
04575 /****************************************************************************
04576  * name:    oaa_LibraryVersion
04577  * purpose:
04578  * remarks:
04579  ****************************************************************************/
04580 int oaa_LibraryVersion(ICLTerm** version) {
04581   int result = FALSE;
04582   ICLTerm* myVersionAsTerm =
04583     icl_NewStruct("version", 1, icl_NewStr(oaa_library_version_str));
04584   result = icl_Unify(*version, myVersionAsTerm, version);
04585   icl_Free(myVersionAsTerm);
04586   return result;
04587 }
04588 
04593 int oaa_Version(ICLTerm *agent_id, ICLTerm **language, ICLTerm **version) {
04594   ICLTerm *true_id;
04595   ICLTerm *true_id_var = icl_NewVar("TrueId");
04596   ICLTerm *version_var = icl_NewVar("Version");
04597   ICLTerm *language_var = icl_NewVar("Language");
04598   ICLTerm *oaa_id_query = icl_NewStruct("oaa_id", 1, true_id_var);
04599   ICLTerm *fac_id_query = icl_NewStruct("fac_id", 1, true_id_var);
04600   ICLTerm *agent_language_query = icl_NewStruct("agent_language", 1,
04601                                                 true_id_var);
04602   ICLTerm *agent_version_query = icl_NewStruct("agent_version", 1,
04603                                                version_var);
04604   char *comm_id_str;
04605 
04606   if (icl_true_id(agent_id, &true_id)) {
04607     /* Asking for my version */
04608     if (oaa_PrimaryAddress(&true_id) &&
04609         oaa_LibraryVersion(version)) {
04610       *language = icl_NewStr("c");
04611     } else if ((com_GetConnectionId(&comm_id_str, oaa_id_query) ||
04612                 com_GetConnectionId(&comm_id_str, fac_id_query)) &&
04613                (com_GetInfo(comm_id_str, agent_language_query, language) ||
04614                 (*language = icl_NewStr("unknown"))) &&
04615                (com_GetInfo(comm_id_str, agent_version_query, version) ||
04616                 (*version = icl_NewStr("unknown")))) {
04617     } else if (oaa_class("leaf") || oaa_class("node")) {
04618       ICLTerm *agent_version_term =
04619         icl_NewStruct("agent_version", 3, true_id,
04620                       language_var, version_var);
04621       ICLTerm *paramlist = icl_NewTermFromData("[address(parent)]",17);
04622       ICLTerm *result, *result_list;
04623 
04624       if (oaa_Solve(agent_version_term, paramlist, NULL, &result_list)) {
04625         if (icl_IsList(result_list) &&
04626             (result = icl_NthTerm(result_list, 1)) &&
04627             icl_IsStruct(result) &&
04628             (icl_NumTerms(result) == 3)) {
04629           *language = icl_NthTerm(result, 2);
04630           *version = icl_NthTerm(result, 3);
04631         }
04632       }
04633       icl_Free(paramlist);
04634       icl_Free(agent_version_term);
04635     } else {
04636       *language = icl_NewStr("prolog");
04637       *version = icl_NewStr("1.0");
04638     }
04639   } else {
04640     *language = icl_NewStr("prolog");
04641     *version = icl_NewStr("1.0");
04642   }
04643 
04644   icl_Free(oaa_id_query);
04645   icl_Free(fac_id_query);
04646   icl_Free(agent_language_query);
04647   icl_Free(agent_version_query);
04648   icl_Free(true_id_var);
04649   icl_Free(version_var);
04650   icl_Free(language_var);
04651   return TRUE;
04652 }
04653 
04657 int oaa_CanSolve(ICLTerm *goal, ICLTerm **kslist)
04658 {
04659   ICLTerm *kslist_var = icl_NewVar("KSList");
04660   ICLTerm *can_solve_query = icl_NewStruct("can_solve", 2, goal, kslist_var);
04661   ICLTerm *paramlist = icl_NewTermFromData("[address(parent)]",17);
04662   int res = FALSE;
04663 
04664   if(oaa_Solve(can_solve_query, paramlist, NULL, kslist))
04665     res = TRUE;
04666   icl_Free(can_solve_query);
04667   icl_Free(paramlist);
04668   return res;
04669 }
04670 
04679 int oaa_Ping(ICLTerm *agent_addr, double time_limit,
04680              double *total_response_time) {
04681   int res = FALSE;
04682   if(time_limit >= 0.0) {
04683 #ifndef _WINDOWS
04684     double t0, t1;
04685     struct timeval tv0, tv1;
04686 #endif
04687     ICLTerm *trueterm = icl_NewStr("true");
04688     ICLTerm *tlfloat = icl_NewFloat(time_limit);
04689     ICLTerm *addrterm = icl_NewStruct("address", 1, agent_addr);
04690     ICLTerm *tlterm = icl_NewStruct("time_limit", 1, tlfloat);
04691     ICLTerm *paramlist = icl_NewList(NULL);
04692     ICLTerm *result;
04693 
04694     icl_AddToList(paramlist, addrterm, TRUE);
04695     icl_AddToList(paramlist, tlterm, TRUE);
04696 #ifndef _WINDOWS
04697     gettimeofday(&tv0, (void *)0);
04698 #endif
04699     if(oaa_Solve(trueterm, paramlist, &result, NULL)) {
04700 #ifndef _WINDOWS
04701       gettimeofday(&tv1, (void *)0);
04702       t0 = tv0.tv_sec*1000.0 + tv0.tv_usec;
04703       t1 = tv1.tv_sec*1000.0 + tv1.tv_usec;
04704       *total_response_time = (t1 - t0)*0.001;
04705 #endif
04706       res = TRUE;
04707     }
04708     icl_Free(trueterm);
04709     icl_Free(paramlist);
04710   }
04711   return res;
04712 }
04713 
04714 /****************************************************************************
04715  * Declaring Solvables
04716  ****************************************************************************/
04759 /*
04760  *    @@Future params may include 'num_context_args(N)'.
04761  *    @@Future solvable params may include 'shared'.
04762  *    @@Do we want client agents to request declarations on other client
04763  *      agents?
04764  */
04765 int oaa_Declare(ICLTerm *solvable, ICLTerm *initial_common_perms,
04766                 ICLTerm *initial_common_params, ICLTerm *initial_params,
04767                 ICLTerm **declared_solvables)
04768 {
04769   int res = FALSE;
04770   ICLTerm *solvable_list, *solvables, *common_perms;
04771   ICLTerm *common_params, *params, *solvables1, *new_solvables;
04772   int res1 = 0;
04773   int res2 = 0;
04774   int res3 = 0;
04775   int res4 = 0;
04776   int res5 = 0;
04777   int res6 = 0;
04778   int res7 = 0;
04779 
04780   if (icl_IsList(solvable)) {
04781     solvable_list = solvable;
04782   }
04783   else {
04784     solvable_list = icl_NewList(icl_NewCons(icl_CopyTerm(solvable), NULL));
04785   }
04786 
04787   res2 = icl_standardize_perms(initial_common_perms, FALSE, &common_perms);
04788   res3 = icl_standardize_params(initial_common_params, FALSE, &common_params);
04789   res4 = icl_standardize_params(initial_params, FALSE, &params);
04790 
04791   res1 = icl_ConvertSolvables(TRUE, solvable_list, &solvables);
04792   if(res1) {
04793     res5 = oaa_distribute_perms(solvables, common_perms, &solvables1);
04794   }
04795   if(res5) {
04796     res6 = oaa_distribute_params(solvables1, common_params, &new_solvables);
04797   }
04798   if(res6 && res4) {
04799     res7 = oaa_declare_aux("add", new_solvables, params, declared_solvables);
04800   }
04801   /* Note: actually suffices to check res2, res3, res4, res7 */
04802   if (res1 && res2 && res3 && res4 && res5 && res6 && res7) {
04803     res = TRUE;
04804   }
04805 
04806   if(solvable_list != solvable) {
04807     icl_Free(solvable_list);
04808   }
04809   icl_Free(solvables);
04810   icl_Free(solvables1);
04811   icl_Free(new_solvables);
04812   icl_Free(params);
04813   icl_Free(common_perms);
04814   icl_Free(common_params);
04815 
04816   return res;
04817 }
04818 
04819 
04823 int oaa_DeclareData(ICLTerm *solv, ICLTerm *params,
04824                     ICLTerm **declared_solvs) {
04825   int res = FALSE;
04826   if(!icl_IsList(solv)) {
04827     ICLTerm *solvlist = icl_NewList(icl_NewCons(solv, (ICLListType *)NULL));
04828     if(oaa_DeclareData(solvlist, params, declared_solvs))
04829       res = TRUE;
04830   } else if(!res) {
04831     ICLTerm *common_perms =
04832       icl_NewTermFromData("[write(true)]",13);
04833     ICLTerm *common_params =
04834       icl_NewTermFromData("[type(data)]",12);
04835     if(oaa_Declare(solv, common_perms, common_params,
04836                    params, declared_solvs))
04837       res = TRUE;
04838   }
04839   return res;
04840 }
04841 
04856 int oaa_Undeclare(ICLTerm *solvable, ICLTerm *initial_params,
04857                   ICLTerm **undeclared_solvables) {
04858   int res = FALSE;
04859   ICLTerm *solvable_list, *solvables, *params;
04860 
04861   if(icl_IsList(solvable))
04862     solvable_list = solvable;
04863   else
04864     solvable_list = icl_NewList(icl_NewCons(solvable, (ICLListType *)NULL));
04865   if(icl_minimally_instantiate_solvables(solvable_list, &solvables) &&
04866      icl_standardize_params(initial_params, FALSE, &params) &&
04867      oaa_declare_aux("remove", solvables, params, undeclared_solvables))
04868     res = TRUE;
04869   return res;
04870 }
04871 
04872 
04892 int oaa_Redeclare(ICLTerm *initial_solvable, ICLTerm *initial_new_solvable,
04893                   ICLTerm *initial_params) {
04894   ICLTerm *solvable, *new_solvable, *solvable_list, *new_solvable_list;
04895   ICLTerm *params, *with_new_solvable, *redeclared_solvables;
04896   ICLTerm *init_solv_list =
04897     icl_NewList(icl_NewCons(initial_solvable, (ICLListType *)NULL));
04898   ICLTerm *init_new_solv_list =
04899     icl_NewList(icl_NewCons(initial_new_solvable, (ICLListType *)NULL));
04900   int res = FALSE;
04901   if(icl_minimally_instantiate_solvables(init_solv_list, &solvable_list) &&
04902      icl_ConvertSolvables(TRUE, init_new_solv_list, &new_solvable_list) &&
04903      icl_standardize_params(initial_params, FALSE, &params) &&
04904      icl_IsList(solvable_list)) {
04905     solvable = icl_NthTerm(solvable_list, 1);
04906     if(icl_IsList(new_solvable_list)) {
04907       new_solvable = icl_NthTerm(new_solvable_list, 1);
04908       with_new_solvable = icl_NewStruct("with", 1, new_solvable);
04909       icl_AddToList(params, with_new_solvable, FALSE);
04910       if(oaa_declare_aux("replace", solvable,
04911                          params, &redeclared_solvables) &&
04912          icl_IsList(redeclared_solvables) &&
04913          redeclared_solvables->p) {
04914         res = TRUE;
04915       }
04916       /* ??? not sure whether to free with_new_solvable here */
04917     }
04918   }
04919   icl_Free(init_solv_list);
04920   icl_Free(init_new_solv_list);
04921   return res;
04922 }
04923 
04931 int select_elements(ICLTerm *list, int (*test_function)(ICLTerm*), ICLTerm** result){
04932 
04933   if (list && icl_IsList(list)) {
04934     ICLListType *local_list = NULL, *newArgs = NULL, *endp = NULL;
04935 
04936     local_list = icl_List(list);
04937     while (local_list) {
04938 
04939       if (test_function(local_list->elt)) {
04940         /* Keep: add to result list */
04941         if (!newArgs) {
04942           newArgs = icl_NewCons(icl_CopyTerm(local_list->elt), NULL);
04943           endp = newArgs;
04944         }
04945         else {
04946           endp->next = icl_NewCons(icl_CopyTerm(local_list->elt), NULL);
04947           endp = endp->next;
04948         }
04949       }
04950 
04951       local_list = local_list->next;
04952     }
04953     *result = icl_NewList(newArgs);
04954 
04955     return TRUE;
04956   }
04957 
04958   return FALSE;
04959 }
04960 
04961 /*
04962  * purpose: Common code for oaa_Declare, oaa_Undeclare, oaa_Redeclare.
04963  * Mode: add, remove, or replace.
04964  * Solvables: for Mode = add, a list of Solvables in standard form.
04965  *            for Mode = remove, a list of Solvables in
04966  *              "minimally instantiated" form.
04967  *            for Mode = replace, a list containing a single Solvable, in
04968  *                "minimally instantiated" form.
04969  * Params: whatever is appropriate for oaa_Declare, _Undeclare, _Redeclare.
04970  *            Must already be in standard form.
04971  * DeclaredSolvables: A list of all solvables successfully added (or removed
04972  *            or replaced), in standard form.
04973  * remarks:
04974  *   A number of params and perms are required when requesting that a
04975  *   parent declare solvables (see comments for oaa_Declare).  We could ensure
04976  *   their presence here, but it's not essential, because the facilitator will
04977  *   enforce this.
04978  */
04979 int oaa_declare_aux(char *mode, ICLTerm *solvables, ICLTerm *params,
04980                     ICLTerm **declared_solvables)
04981 {
04982 
04983   ICLTerm *fac_id_query = icl_NewTermFromData("fac_id(ParentId)",16);
04984   ICLTerm *result = (ICLTerm *)NULL;
04985   ICLTerm *dec_solv_var = icl_NewVar("DeclaredSolvables");
04986   int res = FALSE;
04987 
04988   /*
04989    * Here, a client is asking the facilitator to add, remove, or replace
04990    * solvables.
04991    */
04992   if (com_GetInfo("parent", fac_id_query, &result)) {
04993 
04994     ICLTerm *parentidlist =
04995       icl_NewList(icl_NewCons(icl_CopyTerm(icl_NthTerm(result, 1)),
04996                               (ICLListType *)NULL));
04997     ICLTerm *address_query = icl_NewStruct("address", 1, parentidlist);
04998 
04999     icl_Free(result);
05000     if (icl_GetParamValue(address_query, params, &result)) {
05001       ICLTerm *emptyList = icl_NewList(NULL);
05002       /* Send the request to the Facilitator*/
05003       ICLTerm *post = icl_NewStruct("ev_post_declare", 3,
05004                                     icl_NewStr(mode),
05005                                     icl_CopyTerm(solvables),
05006                                     icl_CopyTerm(params));
05007       ICLTerm *ev_reply_declared = icl_NewStruct("ev_reply_declared", 4,
05008                                                  icl_NewStr(mode),
05009                                                  icl_CopyTerm(solvables),
05010                                                  icl_CopyTerm(params),
05011                                                  icl_CopyTerm(dec_solv_var));
05012 
05013       if (oaa_PostEvent(post, emptyList) &&
05014           oaa_poll_until_event(ev_reply_declared, NULL)) {
05015         res = TRUE;
05016       }
05017       icl_Free(emptyList);
05018       icl_Free(post);
05019       icl_Free(ev_reply_declared);
05020       icl_Free(result);
05021     }
05022     icl_Free(address_query);
05023   }
05024 
05025   if (!res) {
05026     /*
05027      * Leaf, node or root adding, removing or replacing its own solvables:
05028      */
05029     ICLTerm *me;
05030     ICLTerm *addr_query = icl_NewStruct("address", 1, icl_NewVar("Addr"));
05031     int res1, res2, res3;
05032 
05033     oaa_PrimaryAddress(&me);
05034 
05035     res1 = icl_GetParamValue(addr_query, params, &result);
05036     res2 = icl_Unify(me, icl_NthTerm(result, 1), NULL);
05037     res3 = oaa_declare_local(mode, solvables, params, declared_solvables);
05038     if ((!res1 || res2) && res3) {
05039       /*
05040        * If I'm a facilitator, I must also "register" my Solvables with
05041        * myself. (If I'm a node, this will also register them with my
05042        * parent.)
05043        */
05044       if (((!oaa_class("leaf")) && (*declared_solvables)->p)) {
05045 #if 0
05046         /* HAVE DIDIER LOOK AT THIS */
05047         ICLTerm *my_name;
05048         ICLTerm *event, *param_list;
05049         oaa_Name(&my_name);
05050         event =
05051           icl_NewStruct("ev_register_solvables", 1, icl_NewStr(mode),
05052                         dec_solv_var, my_name, params);
05053         param_list = icl_NewList(icl_NewCons(icl_NewStruct("from", 1, me),
05054                                              NULL));
05055         /* BOGUS : Removed */
05056         /* oaa_AppDoEvent(event, param_list); */
05057 #endif
05058       } else {
05059         /*
05060          * If I'm a leaf, post public solvables to parent facilitator:
05061          */
05062         ICLTerm *public_solvables;
05063         CHECK_LEAKS();
05064         select_elements(*declared_solvables, oaa_is_public_solvable,
05065                         &public_solvables);
05066         CHECK_LEAKS();
05067         if (oaa_class("leaf") && public_solvables->p) {
05068           ICLTerm *tempRequest = icl_NewTermFromData("oaa_name(MyName)",16);
05069           if(res1) {
05070             icl_Free(result);
05071           }
05072           CHECK_LEAKS();
05073           com_GetInfo("parent", tempRequest, &result);
05074           CHECK_LEAKS();
05075 
05076           if(result && icl_IsStruct(result)) {
05077             ICLTerm *my_name_c = icl_CopyTerm(icl_NthTerm(result, 1));
05078             ICLTerm *event =
05079               icl_NewStruct("ev_register_solvables", 4, icl_NewStr(mode),
05080                             public_solvables, my_name_c, icl_CopyTerm(params));
05081             ICLTerm *postParams = icl_NewList(NULL);
05082             CHECK_LEAKS();
05083             oaa_PostEvent(event, postParams);
05084             CHECK_LEAKS();
05085             icl_Free(postParams);
05086             icl_Free(result);
05087             icl_Free(event);  /* fress public_solvables, my_name_c too */
05088           }
05089           else {
05090             icl_Free(public_solvables);
05091           }
05092           icl_Free(tempRequest);
05093         }
05094         else {
05095           icl_Free(public_solvables);
05096         }
05097       }
05098       res = TRUE;
05099     }
05100     icl_Free(me);
05101     icl_Free(addr_query);
05102   }
05103   icl_Free(fac_id_query);
05104   icl_Free(dec_solv_var);
05105   return res;
05106 }
05107 
05108 
05109 /*
05110  * Solvable must be in standard from
05111  */
05112 int oaa_public_solvable(ICLTerm *solvable)
05113 {
05114   ICLTerm *tmpres, *params;
05115   ICLTerm *param = icl_NewTermFromData("private(false)",14);
05116 
05117   if (icl_IsStruct(solvable) &&
05118       (icl_NumTerms(solvable) == 3) &&
05119       (params = icl_NthTerm(solvable, 2)) &&
05120       icl_GetParamValue(param, params, &tmpres)) {
05121 
05122     icl_Free(param);
05123     return TRUE;
05124   }
05125 
05126   icl_Free(param);
05127   return FALSE;
05128 }
05129 
05130 /*
05131  * Solvable must be in standard from
05132  */
05133 int oaa_data_solvable(ICLTerm *solvable)
05134 {
05135   ICLTerm *tmpres, *params;
05136   ICLTerm *param = icl_NewTermFromData("type(data)",10);
05137 
05138   if (icl_IsStruct(solvable) &&
05139       (icl_NumTerms(solvable) == 3) &&
05140       (params = icl_NthTerm(solvable, 2)) &&
05141       icl_GetParamValue(param, params, &tmpres)) {
05142 
05143     icl_Free(param);
05144     return TRUE;
05145   }
05146 
05147   icl_Free(param);
05148   return FALSE;
05149 }
05150 
05151 /*
05152  * purpose:   Declare solvables for an agent.
05153  * Mode:      add, remove, or replace.
05154  * Solvables: The form they're in depends on the mode.  See oaa_declare_aux.
05155  * DeclaredSolvables: Returns those members of Solvables for which
05156  *     the operation was successful (more specifically, those that should
05157  *     be passed up to the parent in ev_register_solvables).  Always returned
05158  *     in STANDARD FORM.
05159  * Also see:  comments for oaa_Declare, oaa_Undeclare, oaa_Redeclare.
05160  * remarks:
05161  *   - This performs the local processing needed by calls to oaa_Declare,
05162  *     and by ev_declare events.
05163  *   - Solvables and Params must already be in standard form.
05164  *
05165  *   @@DLM: Could do more careful testing to be sure the solvables are
05166  *   all valid for the requested operation.
05167  *
05168  *   *returned_solvables is newly allocated memory
05169  */
05170 int oaa_declare_local(char *mode, ICLTerm *solvable0, ICLTerm *params,
05171                       ICLTerm **returned_solvables) {
05172   ICLTerm *current_solvables;
05173   ICLTerm *db_solvables, *solvables;
05174   ICLTerm *all_solvables = NULL;
05175   int res = FALSE;
05176 
05177   if (!icl_IsList(solvable0)) {
05178     solvables = icl_NewList(icl_NewCons(solvable0, NULL));
05179   }
05180   else {
05181     solvables = solvable0;
05182   }
05183 
05184   if (STREQ(mode, "add")) {
05185 
05186     ICLTerm *initial_solvables = solvables;
05187     ICLTerm *declared_solvables = NULL;
05188     ICLTerm *ifexistsfalse = icl_NewTermFromString("if_exists(overwrite)");
05189 
05190     if (icl_GetParamValue(ifexistsfalse, params, NULL)) {
05191       current_solvables = icl_NewList(NULL);
05192     }
05193     else {
05194       current_solvables = valid_oaa_solvables();
05195     }
05196     icl_Free(ifexistsfalse);
05197 
05198     /*
05199      * This will eliminate those that unify with an already declared
05200      * solvable.
05201      * @@DLM: Should do more, though: warnings.
05202      */
05203     solvables_to_be_added(initial_solvables, current_solvables, &declared_solvables);
05204     /*
05205      * Make sure Quintus has the correct properties for each DB solvable.
05206      * ??? - sws
05207      */
05208     select_elements(declared_solvables, oaa_is_data_solvable, &db_solvables);
05209 
05210     /* BOGUS, REMOVED */
05211     /* oaa_declare_for_prolog(db_solvables); */
05212 
05213     icl_append_to_list(current_solvables, declared_solvables, &all_solvables);
05214     if(oaa_solvables != NULL) {
05215       icl_Free(oaa_solvables);
05216     }
05217     oaa_solvables = all_solvables;
05218     if(oaa_solvables == NULL) {
05219       oaa_solvables = icl_NewList(NULL);
05220     }
05221     if (returned_solvables != NULL) {
05222       *returned_solvables = declared_solvables;
05223     }
05224     else {
05225       icl_Free(declared_solvables);
05226     }
05227 
05228     icl_Free(current_solvables);
05229     icl_Free(db_solvables);
05230     res = TRUE;
05231   }
05232   else if (STREQ(mode, "remove")) {
05233     ICLTerm *removed_solvables, *new;
05234     ICLTerm *current = valid_oaa_solvables();
05235 
05236     /*
05237      * See which ones are really declared
05238      */
05239     solvables_to_be_removed(solvables, current, &removed_solvables);
05240     /*
05241      * Retract all clauses from data solvables:
05242      */
05243     select_elements(removed_solvables, oaa_is_data_solvable, &db_solvables);
05244     oaa_remove_solvables_data(db_solvables);
05245     /*
05246      * Assert the new solvables list:
05247      */
05248     icl_subtract(current, removed_solvables, &new);
05249     if(oaa_solvables != NULL) {
05250       icl_Free(oaa_solvables);
05251     }
05252     oaa_solvables = new;
05253     if(oaa_solvables == NULL) {
05254       oaa_solvables = icl_NewList(NULL);
05255     }
05256     *returned_solvables = removed_solvables;
05257     icl_Free(db_solvables);
05258     res = TRUE;
05259   }
05260   else if (STREQ(mode, "replace") &&
05261            (icl_NumTerms(solvables) == 1)) {
05262 
05263     ICLTerm *new_solvable, *result, *current, *new;
05264     ICLTerm *solvable = icl_NthTerm(solvables, 1);
05265     ICLTerm *t1;
05266 
05267     if (icl_Member((t1 = icl_NewTermFromString("with(NewSolvable)")),
05268                    icl_CopyTerm(params), &result)) {
05269       new_solvable = icl_CopyTerm(icl_NthTerm(result, 1));
05270       icl_Free(result);
05271       /*
05272        * Make sure solvables is really declared
05273        */
05274       current = valid_oaa_solvables();
05275       if (icl_Member(solvable, current, NULL)) {
05276         /*
05277          * if a data solvable, maybe retract all its clauses
05278          */
05279         if (oaa_data_solvable(solvable))
05280           oaa_remove_solvables_data(solvables);
05281         /*
05282          * Assert thenew solvables list:
05283          */
05284         replace_element(solvable, current, new_solvable, &new);
05285         if(oaa_solvables != NULL) {
05286           icl_Free(oaa_solvables);
05287         }
05288         oaa_solvables = new;
05289         if(oaa_solvables == NULL) {
05290           oaa_solvables = icl_NewList(NULL);
05291         }
05292         *returned_solvables = solvables;
05293         res = TRUE;
05294       }
05295     }
05296     icl_Free(t1);
05297 
05298     if (!res) {
05299       ICLTerm *goal;
05300       if (icl_IsStruct(solvable) &&
05301           STREQ(icl_Functor(solvable), "solvable") &&
05302           (goal = icl_NthTerm(solvable, 1))) {
05303         printf("WARNING: Ignoring attempt to replace a non-existent solvable:\n  %s\n",
05304                icl_NewStringFromTerm(goal));
05305       }
05306       *returned_solvables = icl_NewList(NULL);
05307       res = TRUE;
05308     }
05309   }
05310   return res;
05311 }
05312 
05317 int icl_subtract(ICLTerm *list1, ICLTerm *list2, ICLTerm **result) {
05318   *result = icl_NewList(NULL);
05319   if(icl_IsList(list1) && icl_IsList(list2)) {
05320     ICLListType *iterator = icl_List(list1);
05321     while(icl_ListHasMoreElements(iterator)) {
05322       ICLTerm *el = icl_ListElement(iterator);
05323       if(!icl_Member(el, list2, NULL)) {
05324         icl_AddToList(*result, el, TRUE);
05325       }
05326       iterator = icl_ListNextElement(iterator);
05327     }
05328     return TRUE;
05329   }
05330   return FALSE;
05331 }
05332 
05338 /*
05339  * remarks: @@Should warn when a solvables has a param that conflicts with
05340  *          CommonParams.  Also, should have an arg that says which version of
05341  *          of the conflicting param to keep.
05342  */
05343 int oaa_distribute_params(ICLTerm *solvables, ICLTerm *common_params,
05344                           ICLTerm **new_solvables) {
05345   *new_solvables = icl_NewList(NULL);
05346   if(icl_IsList(solvables)) {
05347     ICLListType *solvable_list = icl_List(solvables);
05348     while(icl_ListHasMoreElements(solvable_list)) {
05349       ICLTerm *solvable = icl_ListElement(solvable_list);
05350 
05351       if(icl_IsStruct(solvable) &&
05352          STREQ(icl_Functor(solvable), "solvable") &&
05353          (icl_NumTerms(solvable) == 3)) {
05354 
05355         ICLTerm *goal = icl_NthTerm(solvable, 1);
05356         ICLTerm *params = icl_NthTerm(solvable, 2);
05357         ICLTerm *perms = icl_NthTerm(solvable, 3);
05358         ICLTerm *new_params, *new_solvable;
05359         icl_Union(params, common_params, &new_params);
05360 
05361         new_solvable = icl_NewStruct("solvable", 3, icl_CopyTerm(goal),
05362                                      new_params, icl_CopyTerm(perms));
05363         icl_AddToList(*new_solvables, new_solvable, TRUE);
05364       }
05365       solvable_list = icl_ListNextElement(solvable_list);
05366     }
05367     return TRUE;
05368   }
05369   return FALSE;
05370 }
05371 
05372 int oaa_distribute_perms(ICLTerm *solvables, ICLTerm *common_perms,
05373                          ICLTerm **new_solvables) {
05374 
05375   *new_solvables = icl_NewList(NULL);
05376   if(icl_IsList(solvables)) {
05377     ICLListType *solvable_list = icl_List(solvables);
05378     while(icl_ListHasMoreElements(solvable_list)) {
05379       ICLTerm *solvable = icl_ListElement(solvable_list);
05380 
05381       if(icl_IsStruct(solvable) &&
05382          STREQ(icl_Functor(solvable), "solvable") &&
05383          (icl_NumTerms(solvable) == 3)) {
05384         ICLTerm *goal = icl_NthTerm(solvable, 1);
05385         ICLTerm *params = icl_NthTerm(solvable, 2);
05386         ICLTerm *perms = icl_NthTerm(solvable, 3);
05387         ICLTerm *new_perms, *new_solvable;
05388         icl_Union(perms, common_perms, &new_perms);
05389 
05390         new_solvable = icl_NewStruct("solvable", 3, icl_CopyTerm(goal),
05391                                      icl_CopyTerm(params), new_perms);
05392         icl_AddToList(*new_solvables, new_solvable, TRUE);
05393       }
05394       solvable_list = icl_ListNextElement(solvable_list);
05395     }
05396     return TRUE;
05397   }
05398   return FALSE;
05399 }
05400 
05401 
05406 /*
05407  * ProposedSolvs: Must be in STANDARD FORM.
05408  * CurrentSolvs: This agent's current solvables.
05409  * SolvsToBeAdded: A subset of ProposedSolvs.
05410  */
05411 int solvables_to_be_added(ICLTerm *solvables, ICLTerm *current,
05412                           ICLTerm **ok_solvables) {
05413   *ok_solvables = icl_NewList(NULL);
05414   if(icl_IsList(solvables)) {
05415     ICLListType *solvable_list = icl_List(solvables);
05416     while(icl_ListHasMoreElements(solvable_list)) {
05417       ICLTerm *solvable = icl_ListElement(solvable_list);
05418       if(icl_IsStruct(solvable) &&
05419          STREQ(icl_Functor(solvable), "solvable") &&
05420          (icl_NumTerms(solvable) == 3)) {
05421         ICLTerm *goal = icl_NthTerm(solvable, 1);
05422         if(icl_Member(goal, current, NULL)) {
05423 
05424           char *debugString = icl_NewStringFromTerm(goal);
05425           printf("WARNING: Ignoring attempt to declare an already"
05426                  " existing solvable:\n  %s", debugString);
05427           icl_stFree(debugString);
05428           continue;
05429         }
05430         icl_AddToList(*ok_solvables, icl_CopyTerm(solvable), TRUE);
05431       }
05432       solvable_list = icl_ListNextElement(solvable_list);
05433     }
05434   }
05435   return TRUE;
05436 }
05437 
05442 /*
05443  * ProposedSolvs: Must be in MINIMALLY INSTANTIATED FORM.
05444  * CurrentSolvs: This agent's current solvables.
05445  * SolvsToBeRemoved: A subset of ProposedSolvs, but returned in standard form,
05446  *   fully instantiated.
05447  */
05448 int solvables_to_be_removed(ICLTerm *solvables, ICLTerm *current,
05449                             ICLTerm **ok_solvables) {
05450   *ok_solvables = icl_NewList(NULL);
05451   if(icl_IsList(solvables)) {
05452     ICLListType *solvable_list = icl_List(solvables);
05453     while(icl_ListHasMoreElements(solvable_list)) {
05454       ICLTerm *solvable = icl_ListElement(solvable_list);
05455       if(icl_IsStruct(solvable) &&
05456          STREQ(icl_Functor(solvable), "solvable") &&
05457          (icl_NumTerms(solvable) == 3)) {
05458         ICLTerm *goal = icl_NthTerm(solvable, 1);
05459         if(!icl_Member(goal, current, NULL)) {
05460           printf("WARNING: Ignoring attempt to remove a "
05461                  "non-existent solvable:\n  %s",
05462                  icl_NewStringFromTerm(goal));
05463           continue;
05464         }
05465         icl_AddToList(*ok_solvables, solvable, TRUE);
05466       }
05467       solvable_list = icl_ListNextElement(solvable_list);
05468     }
05469   }
05470   return TRUE;
05471 }
05472 
05473 
05474 /****************************************************************************
05475  * Updating Data Solvables
05476  ****************************************************************************/
05477 
05478 
05517 int oaa_AddData(ICLTerm *clause, ICLTerm *in_params, ICLTerm **out_params) {
05518   return oaa_update("add", clause, in_params, out_params);
05519 }
05520 
05521 /*
05522  * Remove a clause from a DATA solvable (locally and/or remotely).
05523  * <p>Params:</p>
05524  * <ul>
05525   *   <li>address(X): a list including 'self', 'parent', and/or the
05526  *      addresses of other client agents.  The default (no address)
05527  *      behavior is the same as with oaa_Solve and oaa_AddData.</li>
05528  *    <li>reflexive(T_F): Save as with oaa_Solve.  Default: true.</li>
05529  *    <li>do_all(T_F): If true, removes all predicate values that match the Clause
05530  *      Default: false (removes only the first)</li>
05531  *    <li>get_address(X): Returns a list of addresses (ids) of agents that
05532  *      were sent the request.</li>
05533  *    <li>get_satisfiers(X): Returns a list of addresses (ids) of agents that
05534  *      successfully completed the request.</li>
05535  *    <li>owner(LocalId): if bookkeeping(true) for this solvable, remove only
05536  *      data owned by LocalId.
05537  *      Default: ignore owner in removing data.</li>
05538  *    <li>reply({true,none}): When data is being removed on
05539  *      a remote agent or agents, this tells whether reply message(s) are
05540  *      desired.</li>
05541  *    <li>block(Mode) : true: Block until the reply arrives.
05542  *                 : false: Don't block.  In
05543  *                         this case, the reply events (ev_reply_updated)
05544  *                         can be handled by the user's app_do_event callback
05545  *                 Default: true.  Note that reply(none) overrides
05546  *                         block(true).</li>
05547  *</ul>
05548  * <p><b>Remarks:</b></p><ul>
05549  *    <li>Clause is normally a fact (no body), but with Prolog agents, and
05550  *      with rules_ok(true), it's possible for it to have a body.</li>
05551  *    <li>Triggers will be examined with the 'on_Retract' operation mask.</li>
05552  *    <li>Not for backtracking.</li>
05553  *</ul>
05554  */
05555 int oaa_RemoveData(ICLTerm *clause, ICLTerm *in_params, ICLTerm **out_params) {
05556   return oaa_update("remove", clause, in_params, out_params);
05557 }
05558 
05602 int oaa_ReplaceData(ICLTerm *clause1, ICLTerm *clause2,
05603                     ICLTerm *in_params, ICLTerm **out_params) {
05604   ICLTerm *new_param_list = icl_NewList(icl_List(in_params));
05605   icl_AddToList(new_param_list, icl_NewStruct("with", 1, clause2), FALSE);
05606   return oaa_update("replace", clause1, new_param_list, out_params);
05607 }
05608 
05614 int icl_replace_param_value(ICLTerm *param, ICLTerm *param_list) {
05615   int res = FALSE;
05616   if (icl_IsStruct(param) &&
05617       (icl_NumTerms(param) == 1) &&
05618       icl_IsList(param_list)) {
05619     ICLListType *plist = icl_List(param_list);
05620     while(icl_ListHasMoreElements(plist)) {
05621       ICLTerm *p = icl_ListElement(plist);
05622       ICLTerm *result;
05623       if(icl_Unify(param, p, &result)) {
05624         plist->elt = result;
05625         icl_Free(p);
05626         res = TRUE;
05627         break;
05628       }
05629       plist = icl_ListNextElement(plist);
05630     }
05631   }
05632   return res;
05633 }
05634 
05643 int oaa_update(char *mode, ICLTerm *clause, ICLTerm *initial_params,
05644                ICLTerm **out_params)
05645 {
05646   ICLTerm *params = NULL, *addr = NULL, *me = NULL;
05647   ICLTerm *new_addr = NULL, *params1 = NULL, *params2 = NULL, *solvables = NULL;
05648   ICLTerm *updaters1 = NULL, *updaters2 = NULL, *updaters = NULL;
05649   ICLTerm *requestees1 = NULL, *requestees2 = NULL, *requestees = NULL;
05650   ICLTerm *t1 = NULL;
05651   int self = FALSE, res = FALSE;
05652   ICLTerm *reflexive_true = icl_NewTermFromString("reflexive(true)");
05653 
05654   icl_standardize_params(initial_params, FALSE, &params);
05655 
05656   /* is there a specific address ? */
05657   if (!icl_param_arg("address", NULL, params, &addr)) {
05658     addr = icl_NewList(NULL);
05659   }
05660 
05661   /* decide whether or not to update locally: */
05662   if (oaa_PrimaryAddress(&me) &&
05663       icl_Member(me, addr, NULL)) {
05664 
05665     icl_ListDelete(addr, me, &new_addr);
05666     t1 = icl_NewStruct("address", 1, icl_CopyTerm(addr));
05667     replace_element(t1, params,
05668                     icl_NewStruct("address", 1, new_addr), &params1);
05669     icl_Free(t1);
05670     self = TRUE;
05671   } else {
05672     new_addr = icl_CopyTerm(addr);
05673     params1 = icl_CopyTerm(params);
05674   }
05675 
05676   if ((!addr->p) &&
05677       icl_GetParamValue(reflexive_true, params1, NULL)) {
05678     ICLTerm *write = icl_NewTermFromString("write");
05679     ICLTerm *real_clause, *real_matched;
05680     /* do NOT use remove_element here: */
05681     icl_ListDelete(params1, reflexive_true, &params2);
05682     solvables = valid_oaa_solvables();
05683     if (oaa_data_matches_solvables(clause, solvables, write, &real_clause,
05684                                    &real_matched))
05685       self = TRUE;
05686     icl_Free(write);
05687   } else {
05688     params2 = params1;
05689   }
05690   icl_Free(reflexive_true);
05691 
05692   /* update locally if appropriate */
05693   if (self) {
05694     requestees1 = icl_NewList(icl_NewCons(icl_CopyTerm(me), NULL));
05695     if (STREQ(mode, "add")) {
05696       res = oaa_add_data_local(clause, params2);
05697     }
05698     else if (STREQ(mode, "replace")) {
05699       res = oaa_replace_data_local(clause, params2);
05700     }
05701     else if (STREQ(mode, "remove")) {
05702       res = oaa_remove_data_local(clause, params2);
05703     }
05704     if(res) {
05705       updaters1 = icl_NewList(icl_NewCons(icl_CopyTerm(me), NULL));
05706     } else {
05707       updaters1 = icl_NewList(NULL);
05708     }
05709   } else {
05710     requestees1 = icl_NewList(NULL);
05711     updaters1 = icl_NewList(NULL);
05712   }
05713   icl_Free(me);
05714 
05715   /* Update remotely if appropriate:
05716    */
05717   if (oaa_class("leaf") &&
05718       ((!addr->p) || (new_addr->p))) {
05719 
05720     ICLTerm *reply;
05721     char    *goalIdStr = new_goal_id();
05722 
05723     /* Send the ev_update_data event to the Facilitator
05724      */
05725     ICLTerm* toBeSent = icl_NewStruct("ev_update_data", 4,
05726                                       icl_NewStr(goalIdStr),
05727                                       icl_NewStr(mode), icl_CopyTerm(clause),
05728                                       icl_CopyTerm(params2));
05729     oaa_PostEvent(toBeSent, ICL_EMPTY);
05730     icl_Free(toBeSent);
05731     icl_stFree(goalIdStr);
05732     /* In the return event, Requestees2 lists all agents to whom
05733      * the update request wassent; Updaters2 lists those who succeeded
05734      */
05735     if ( !(icl_param_arg("reply", NULL, params, &reply) &&
05736            (STREQ("asynchronous", icl_Str(reply)) ||
05737             STREQ("none", icl_Str(reply)))) ) {
05738       ICLTerm *ev_reply_updated =
05739         icl_NewStruct("ev_data_updated", 6, icl_NewVar("G"), icl_NewStr(mode),
05740                       icl_CopyTerm(clause), icl_CopyTerm(params2),
05741                       icl_NewVar("Requestees"), icl_NewVar("Updaters"));
05742       oaa_poll_until_event(ev_reply_updated, NULL);
05743       icl_Free(ev_reply_updated);
05744     }
05745   }
05746   icl_Free(addr);
05747   icl_Free(new_addr);
05748 
05749   requestees2 = icl_NewList(NULL);
05750   updaters2 = icl_NewList(NULL);
05751 
05752   /*
05753    * The following section replaces a variable parameter value in the
05754    * parameter list for return to the calling function
05755    */
05756   icl_append_to_list(updaters1, updaters2, &updaters);
05757   icl_Free(updaters1);
05758   icl_Free(updaters2);
05759 
05760   /* Return Updaters if requested:
05761    */
05762   t1 = icl_NewStruct("get_satisfiers", 1, updaters);
05763   icl_replace_param_value(t1, params);
05764   icl_Free(t1);   /* frees updaters too */
05765 
05766   /*  Return Requestees if requested:
05767    */
05768   icl_append_to_list(requestees1, requestees2, &requestees);
05769   t1 = icl_NewStruct("get_address", 1, requestees);
05770   icl_replace_param_value(t1, params);
05771   icl_Free(requestees1);
05772   icl_Free(requestees2);
05773   icl_Free(t1);
05774   if(params2 == params1) {
05775     icl_Free(params2);
05776   }
05777   else {
05778     icl_Free(params2);
05779     icl_Free(params1);
05780   }
05781 
05782   if (out_params != NULL) {
05783     *out_params = params;
05784   }
05785   else {
05786     icl_Free(params);
05787   }
05788 
05789   return TRUE;
05790 }
05791 
05792 /*
05793  * name:    asserta
05794  *          assertz
05795  *          retract
05796  *          retract_all
05797  * purpose: Asserts or retracts clauses in the database just like the
05798  *          equivalent prolog built-in clauses
05799  */
05800 int asserta(ICLTerm *clause)
05801 {
05802   int res;
05803   ICLTerm *t1;
05804 
05805   if(!db_IsValid(local_db))
05806     local_db = db_NewDB();
05807   res =
05808     db_Assert(local_db, clause,
05809               (t1 = icl_NewTermFromString("[at_beginning(true)]")));
05810   icl_Free(t1);
05811   return res;
05812 }
05813 
05814 int assertz(ICLTerm *clause)
05815 {
05816   int res;
05817   ICLTerm *t1;
05818 
05819   if(!db_IsValid(local_db))
05820     local_db = db_NewDB();
05821   res =
05822     db_Assert(local_db, clause,
05823               (t1 = icl_NewTermFromString("[at_beginning(false)]")));
05824   icl_Free(t1);
05825   return res;
05826 }
05827 
05828 int retract(ICLTerm *clause) {
05829   if(!db_IsValid(local_db))
05830     local_db = db_NewDB();
05831   return db_Retract(local_db, clause, ICL_EMPTY);
05832 }
05833 
05834 /*
05835  * mimics asserta/2, assertz/2
05836  */
05837 
05838 /* for use in asserts with ref.  Hopefully, this won't wrap around */
05839 static int db_ref_number = 0;
05840 
05841 /*
05842  * maintain a table of ref numbers associated with asserted clauses
05843  */
05844 static DICTIONARY *oaa_db_ref = (DICTIONARY *)NULL;
05845 
05846 
05847 int asserta_ref(ICLTerm *clause, ICLTerm **ref) {
05848   *ref = icl_NewInt(db_ref_number++);
05849   if(!oaa_db_ref)
05850     oaa_db_ref = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
05851   dict_put(oaa_db_ref, (void *)icl_CopyTerm(clause), (void *)*ref);
05852   return asserta(clause);
05853 }
05854 
05855 int assertz_ref(ICLTerm *clause, ICLTerm **ref) {
05856   *ref = icl_NewInt(db_ref_number++);
05857   if(!oaa_db_ref)
05858     oaa_db_ref = dict_new(oaa_compare_terms, (void *)icl_FreeTermSingle);
05859   dict_put(oaa_db_ref, (void *)icl_CopyTerm(clause), (void *)*ref);
05860   return assertz(clause);
05861 }
05862 
05863 int ref_for_clause(ICLTerm *clause, ICLTerm **ref) {
05864   int result = FALSE;
05865   if(oaa_db_ref) {
05866     *ref = (ICLTerm *)dict_get(oaa_db_ref, (void *)clause);
05867     if (*ref)
05868       result = TRUE;
05869   }
05870   return result;
05871 }
05872 
05873 int erase_ref(ICLTerm *clause, ICLTerm *ref) {
05874   if(oaa_db_ref) {
05875     ICLTerm *val = (ICLTerm *)dict_get(oaa_db_ref, clause);
05876     while(val != NULL) {
05877       if(icl_Unify(val, ref, NULL)) {
05878         dict_remove_specific(oaa_db_ref, clause, ref);
05879         return TRUE;
05880       }
05881       val = (ICLTerm *)dict_get(oaa_db_ref, clause);
05882     }
05883   }
05884   return TRUE;
05885 }
05886 
05887 
05896 int oaa_add_data_local(ICLTerm *clause1, ICLTerm *params)
05897 {
05898   ICLTerm *clause = NULL, *matched = NULL;
05899   ICLTerm *head = NULL, *body = NULL;
05900   ICLTerm *pred = NULL, *decl_params = NULL, *all_params = NULL;
05901   ICLTerm *callback = NULL, *result = NULL;
05902   ICLTerm *t1 = NULL, *t2 = NULL;
05903   ICLTerm *dummyvar = NULL, *single_value_true = NULL;
05904   ICLTerm *solvables = valid_oaa_solvables();
05905   ICLTerm *permRequest = icl_NewStr("write");
05906 
05907   oaa_data_matches_solvables(clause1, solvables,
05908                              permRequest,
05909                              &clause, &matched);
05910   icl_Free(permRequest);
05911 
05912   if (icl_IsStruct(matched) &&
05913       (icl_NumTerms(matched) == 3) &&
05914       STREQ(icl_Functor(matched), "solvable")) {
05915 
05916     pred = icl_NthTerm(matched, 1);
05917     decl_params = icl_NthTerm(matched, 2);
05918   } else {
05919     return FALSE;
05920   }
05921   if (icl_IsStruct(clause) &&
05922       STREQ(icl_Functor(clause), ":-") &&
05923       (icl_NumTerms(clause) == 2)) {
05924 
05925     head = icl_NthTerm(clause, 1);
05926     body = icl_NthTerm(clause, 2);
05927   } else {
05928     head = clause;
05929     body = ICL_TRUE;
05930   }
05931   icl_append_to_list(params, decl_params, &all_params);
05932 
05933   /* If there's no callback, leave Callback a var:
05934    */
05935   dummyvar = icl_NewVar("dummy");
05936   t1 = icl_NewStruct("callback", 1, icl_CopyTerm(dummyvar));
05937 
05938   if (! icl_GetParamValue(t1, all_params, &callback)) {
05939     /* ??? Not really sure what to do in C  */
05940     callback = icl_NewVar("Callback");
05941   }
05942   icl_Free(t1);
05943 
05944   /* if single value, erase all old values */
05945   single_value_true = icl_NewTermFromString("single_value(true)");
05946   if (icl_GetParamValue(single_value_true, all_params, &result)) {
05947     if (!icl_ParamValue("bookkeeping", ICL_FALSE, decl_params, NULL)) {
05948       oaa_retractall(pred, dummyvar, callback);
05949     }
05950     else {
05951       retract_all(pred);
05952     }
05953   }
05954 
05955   icl_Free(dummyvar);
05956   icl_Free(single_value_true);
05957 
05958   /* if unique_values(true), make sure fact not already in database */
05959   t1 = icl_NewTermFromString("unique_values(true)");
05960   if (db_Solve(local_db, pred, ICL_EMPTY, NULL) &&
05961       icl_GetParamValue(t1, all_params, NULL)) {
05962     icl_Free(all_params);
05963     icl_Free(t1);
05964     return TRUE;
05965   }
05966   icl_Free(t1);
05967 
05968   t1 = icl_NewTermFromString("bookkeeping(true)");
05969   if (icl_GetParamValue(t1, decl_params, NULL)) {
05970     ICLTerm *owner;
05971 
05972     icl_Free(t1);
05973     oaa_data_owner(params, &owner);
05974     if(icl_GetParamValue((t1 = icl_NewTermFromString("at_beginning(true)")),
05975                          all_params, NULL)) {
05976       oaa_asserta(clause, owner, callback);
05977     }
05978     else {
05979       oaa_assertz(clause, owner, callback);
05980     }
05981     icl_Free(t1);
05982   } else {
05983     if (icl_GetParamValue((t2 = icl_NewTermFromString("at_beginning(true)")),
05984                           all_params, NULL)) {
05985       asserta(clause);
05986     }
05987     else {
05988       assertz(clause);
05989     }
05990   }
05991   icl_Free(t1);
05992   icl_Free(t2);
05993   icl_Free(all_params);
05994   oaa_CheckTriggers("data", head, "add");
05995   return TRUE;
05996 }
05997 
06004 int oaa_remove_data_local(ICLTerm *clause1, ICLTerm *params)
06005 {
06006   ICLTerm *matched = NULL;
06007   ICLTerm *clause, *decl_params;
06008   ICLTerm *head, *body, *all_params, *callback;
06009   ICLTerm *local_solvables = valid_oaa_solvables();
06010   ICLTerm *permRequest = icl_NewStr("write");
06011   ICLTerm *t1 = (ICLTerm *)NULL, *t2 = (ICLTerm *)NULL;
06012 
06013   oaa_data_matches_solvables(clause1, local_solvables,
06014                              permRequest,
06015                              &clause, &matched);
06016   icl_Free(permRequest);
06017   if(matched && icl_IsStruct(matched) &&
06018      (icl_NumTerms(matched) == 3) &&
06019      STREQ(icl_Functor(matched), "solvable")) {
06020     decl_params = icl_NthTerm(matched, 2);
06021   } else {
06022     return FALSE;
06023   }
06024   if(icl_IsStruct(clause) &&
06025      STREQ(icl_Functor(clause), ":-") &&
06026      (icl_NumTerms(clause) == 2)) {
06027     head = icl_NthTerm(clause, 1);
06028     body = icl_NthTerm(clause, 2);
06029   } else {
06030     head = clause;
06031     body = ICL_TRUE;
06032   }
06033   icl_append_to_list(params, decl_params, &all_params);
06034   if(!icl_param_arg("callback", NULL, all_params, &callback)) {
06035     /* ??? Not really sure if this is correct thing to do in C  */
06036     callback = icl_NewVar("Callback");
06037   }
06038 
06039   t1 = icl_NewTermFromString("bookkeeping(true)");
06040   if (icl_GetParamValue(t1, decl_params, NULL)) {
06041     ICLTerm *owner;
06042 
06043     if (!icl_param_arg("owner", NULL, params, &owner)) {
06044       owner = icl_NewVar("Owner");
06045     }
06046     if (icl_ParamValue("do_all", ICL_TRUE, all_params, NULL)) {
06047       oaa_retractall(clause, owner, callback);
06048     }
06049     else {
06050       oaa_retract(clause, owner, callback);
06051     }
06052   }
06053   else {
06054     t2 = icl_NewTermFromString("do_all(true)");
06055     if (icl_GetParamValue(t2, all_params, NULL)) {
06056       retract_all(clause);
06057     }
06058     else {
06059       retract(clause);
06060     }
06061   }
06062   icl_Free(t1);
06063   icl_Free(t2);
06064   icl_Free(all_params);
06065   oaa_CheckTriggers("data", head, "remove");
06066   return TRUE;
06067 }
06068 
06077 int oaa_replace_data_local(ICLTerm *clause1_in, ICLTerm *params) {
06078   ICLTerm *clause2_in, *result = (ICLTerm *)NULL, *clause1, *clause2;
06079   ICLTerm *decl_params = NULL;
06080   ICLTerm *all_params;
06081   ICLTerm *head, *body, *matched;
06082   ICLTerm *solvables = valid_oaa_solvables();
06083   ICLTerm *dummyvar = icl_NewVar("dummy");
06084   ICLTerm *callback = NULL;
06085   ICLTerm *owner = NULL;
06086   ICLTerm *t1;
06087 
06088   if (icl_Member((t1 = icl_NewStruct("with", 1, dummyvar)), params,
06089                  &result)) {
06090     clause2_in = icl_CopyTerm(icl_NthTerm(result, 1));
06091     icl_Free(result);
06092   }
06093   else {
06094     icl_Free(t1);
06095     return FALSE;
06096   }
06097   icl_Free(t1);
06098 
06099   print_dictionary(oaa_db_ref);
06100 
06101   oaa_data_matches_solvables(clause1_in, solvables,
06102                              (t1 = icl_NewStr("write")),
06103                              &clause1, &matched);
06104   icl_Free(t1);
06105 
06106   oaa_data_matches_solvables(clause2_in, solvables,
06107                              (t1 = icl_NewStr("write")),
06108                              &clause2, &result);
06109   icl_Free(t1);
06110 
06111   if(icl_IsStruct(matched) &&
06112      (icl_NumTerms(matched) == 3) &&
06113      STREQ(icl_Functor(matched), "solvable")) {
06114     decl_params = icl_CopyTerm(icl_NthTerm(matched, 2));
06115   } else {
06116     return FALSE;
06117   }
06118   if(icl_IsStruct(clause1) &&
06119      STREQ(icl_Functor(clause1), ":-") &&
06120      (icl_NumTerms(clause1) == 2)) {
06121     head = icl_NthTerm(clause1, 1);
06122     body = icl_NthTerm(clause1, 2);
06123   } else {
06124     head = clause1;
06125     body = ICL_TRUE;
06126   }
06127 
06128   icl_append_to_list(params, decl_params, &all_params);
06129   icl_param_arg("callback", dummyvar, all_params, &callback);
06130 
06131   /* ??? Not really sure what to do in C  */
06132   if (callback==NULL) {
06133     callback = icl_NewVar("Callback");
06134   }
06135 
06136   if(!icl_ParamValue("bookkeeping",ICL_FALSE, decl_params, NULL)) {
06137     oaa_data_owner(params, &owner);
06138     if(icl_ParamValue("do_all", ICL_TRUE, params, NULL)) {
06139       oaa_replace_all(clause1, clause2, owner, callback);
06140     }
06141     else {
06142       if (oaa_retract(clause1, owner, callback)) {
06143         if(icl_ParamValue("at_beginning", ICL_TRUE, all_params, NULL)) {
06144           oaa_asserta(clause2, owner, callback);
06145         }
06146         else {
06147           oaa_assertz(clause2, owner, callback);
06148         }
06149       }
06150     }
06151   } else {
06152     if(icl_ParamValue("do_all", ICL_TRUE, params, NULL)) {
06153       replace_all(clause1, clause2);
06154     }
06155     else {
06156       if (retract(clause1)) {
06157         if(icl_ParamValue("at_beginning", ICL_TRUE, all_params, NULL)) {
06158           asserta(clause2);
06159         }
06160         else {
06161           assertz(clause2);
06162         }
06163       }
06164     }
06165   }
06166   oaa_CheckTriggers("data", clause1, "remove");
06167   oaa_CheckTriggers("data", clause2, "add");
06168 
06169   icl_Free(head);
06170   icl_Free(body);
06171   icl_Free(clause1);
06172   icl_Free(result);
06173   icl_Free(decl_params);
06174   icl_Free(all_params);
06175   icl_Free(owner);
06176   return TRUE;
06177 }
06178 
06184 int retract_all(ICLTerm *clause)
06185 {
06186   ICLTerm *t1;
06187 
06188   if(!db_IsValid(local_db))
06189     local_db = db_NewDB();
06190   db_Retract(local_db, clause,
06191              (t1 = icl_NewTermFromString("[do_all(true)]")));
06192   icl_Free(t1);
06193   return TRUE;
06194 }
06195 
06200 int replace_all(ICLTerm *clause1, ICLTerm *clause2)
06201 {
06202   ICLTerm *t1;
06203 
06204   if(!db_IsValid(local_db))
06205     local_db = db_NewDB();
06206   db_Retract(local_db, clause1,
06207              (t1 = icl_NewTermFromString("[do_all(true)]")));
06208   db_Assert(local_db, clause2, ICL_EMPTY);
06209   icl_Free(t1);
06210   return TRUE;
06211 }
06212 
06216 int oaa_data_owner(ICLTerm *params, ICLTerm **owner) {
06217   ICLTerm *dummyvar = icl_NewVar("_");
06218   if(icl_param_arg("owner", dummyvar, params, owner))
06219     return TRUE;
06220   else if(icl_param_arg("from", dummyvar, params, owner))
06221     return TRUE;
06222   else if(oaa_PrimaryAddress(owner))
06223     return TRUE;
06224   *owner = icl_NewStr("unknown");
06225   return TRUE;
06226 }
06227 
06231 int oaa_Id(ICLTerm **my_id) {
06232   ICLTerm *result, *t1;
06233 
06234   if(com_GetInfo("parent",
06235                  (t1 = icl_NewTermFromString("oaa_id(MyId)")),
06236                  &result)) {
06237 
06238     *my_id = icl_CopyTerm(icl_NthTerm(result, 1));
06239     icl_Free(result);
06240     icl_Free(t1);
06241     return TRUE;
06242   } else {
06243     char *conn_id;
06244     ICLTerm *type_server = icl_NewTermFromString("type(server)");
06245 
06246     icl_Free(t1);
06247     if(com_GetConnectionId(&conn_id, type_server) &&
06248        com_GetInfo(conn_id,
06249                    (t1 = icl_NewTermFromString("oaa_id(MyId)")),
06250                    &result)) {
06251       *my_id = icl_CopyTerm(icl_NthTerm(result, 1));
06252       icl_Free(result);
06253       icl_Free(t1);
06254       icl_Free(type_server);
06255       return TRUE;
06256     }
06257   }
06258   icl_Free(t1);
06259   return FALSE;
06260 }
06261 
06271 /*
06272  * Note : Type not used ?
06273  */
06274 int oaa_Address(char* connectionId, ICLTerm* Type, ICLTerm **myAddress)
06275 {
06276   (void)Type;
06277   *myAddress = icl_NewList(NULL);
06278 
06279   if (connectionId != NULL) {
06280     if (!com_Connected(connectionId)) {
06281       printWarning(1, "Address requested for connection %s but no such "
06282                    "connection exists",connectionId);
06283       icl_AddToList(*myAddress, icl_NewStr("no_address"), FALSE);
06284     } else {
06285       ICLTerm *t1, *tempTerm = NULL;
06286 
06287       com_GetInfo(connectionId,
06288                   (t1 = icl_NewTermFromString("oaa_address(MyAddress)")),
06289                   &tempTerm);
06290       icl_AddToList(*myAddress, icl_CopyTerm(icl_NthTerm(tempTerm, 1)), FALSE);
06291       icl_Free(t1);
06292       icl_Free(tempTerm);
06293       return TRUE;
06294     }
06295   }
06296   else {
06297     /*
06298        Here, connectionId is null.
06299        First, we look for all connections of the incoming Type that
06300        are currently valid (actually connected).
06301     */
06302     int index;
06303     ICLTerm* validConnections = NULL;
06304 
06305     com_GetAllValidConnections(&validConnections);
06306 
06307     if (validConnections != NULL) {
06308       ICLTerm* requestInfo = icl_NewTermFromString("oaa_address(MyAddress)");
06309       /*
06310         Retreives all Id from the list of connected connections Not the best
06311         optimized way to to it (n^2 order), but lists of connections are not
06312         going to be huge.
06313       */
06314       char* connectionIdAsString = NULL;
06315 
06316       for (index = 1; index <=icl_ListLen(validConnections) ; index ++) {
06317         ICLTerm* tempTerm = NULL;
06318         connectionIdAsString = icl_Str(icl_NthTerm(validConnections, index));
06319         /*
06320           Makes the request to the connections database about the address
06321           of the current valid connection's id
06322         */
06323         com_GetInfo(connectionIdAsString, requestInfo, &tempTerm);
06324         icl_AddToList(*myAddress, icl_CopyTerm(icl_NthTerm(tempTerm, 1)),
06325                       TRUE);
06326         icl_Free(tempTerm);
06327       }
06328       icl_Free(validConnections);
06329       icl_Free(requestInfo);
06330       return TRUE;
06331     }
06332   }
06333   return FALSE;
06334 } // end of oaa_Address
06335 
06339 int oaa_PrimaryAddress(ICLTerm** primaryAddress)
06340 {
06341   if (com_Connected("parent")) {
06342     ICLTerm* tempResult = NULL;
06343     ICLTerm* requestInfo = icl_NewTermFromString("oaa_address(MyAddress)");
06344 
06345     com_GetInfo("parent", requestInfo, &tempResult);
06346     *primaryAddress = icl_CopyTerm(icl_NthTerm(tempResult,1));
06347     icl_Free(tempResult);
06348     icl_Free(requestInfo);
06349     return TRUE;
06350   }
06351   else {
06352     printf("liboaa.c::oaa_PrimaryAddress: not connected\n");
06353   }
06354   return FALSE;
06355 }
06356 
06360 int oaa_PrimaryId(ICLTerm** primaryId) {
06361   ICLTerm* tempAddress = NULL;
06362 
06363   if (oaa_PrimaryAddress(&tempAddress)) {
06364 
06365     int returnValue = icl_address_to_id(tempAddress, primaryId);
06366     icl_Free(tempAddress);
06367     return returnValue;
06368   }
06369   return FALSE;
06370 }
06371 
06372 /****************************************************************************
06373  * Given a full address return only the Id
06374  ***************************************************************************/
06375 
06376 int icl_address_to_id(ICLTerm* inFullAddress, ICLTerm** result) {
06377   int success = FALSE;
06378   ICLTerm *tempTerm = icl_NewTermFromString("addr(FacAddr, Id)");
06379   if (icl_Unify(inFullAddress, tempTerm, NULL)) {
06380     *result = icl_CopyTerm(icl_NthTerm(inFullAddress, 2));
06381     success = TRUE;
06382   }
06383   icl_Free(tempTerm);
06384   return success;
06385 }
06386 
06390 int oaa_Name(ICLTerm **my_name) {
06391   ICLTerm *result, *t1;
06392 
06393   if (com_GetInfo("parent",
06394                   (t1 = icl_NewTermFromString("oaa_name(MyName)")),
06395                   &result)) {
06396 
06397     *my_name = icl_CopyTerm(icl_NthTerm(result, 1));
06398     icl_Free(result);
06399     icl_Free(t1);
06400     return TRUE;
06401   } else {
06402 
06403     char *conn_id;
06404     ICLTerm *type_server = icl_NewTermFromString("type(server)");
06405 
06406     icl_Free(t1);
06407     if (com_GetConnectionId(&conn_id, type_server) &&
06408         com_GetInfo(conn_id,
06409                     (t1 = icl_NewTermFromString("oaa_name(MyName)")),
06410                     &result)) {
06411 
06412       *my_name = icl_CopyTerm(icl_NthTerm(result, 1));
06413       icl_Free(result);
06414       icl_Free(t1);
06415       return TRUE;
06416     }
06417     icl_Free(t1);
06418   }
06419   return FALSE;
06420 }
06421 
06422 char *oaa_name_string()
06423 {
06424   ICLTerm *name;
06425 
06426   if (oaa_Name(&name)) {
06427 
06428     char *nameStr = strdup(icl_Str(name));
06429     icl_Free(name);
06430     return nameStr;
06431   }
06432   else
06433     return NULL;
06434 }
06435 
06436 
06440 int oaa_class(char *class) {
06441   int res = FALSE;
06442 
06443     if(STREQ(class, "leaf") &&
06444          !com_Connected("fac_listener"))
06445        res = TRUE;
06446     else if(STREQ(class, "node") &&
06447          com_Connected("fac_listener") &&
06448          com_Connected("parent"))
06449       res = TRUE;
06450     else if(STREQ(class, "root") &&
06451          com_Connected("fac_listener") &&
06452          !com_Connected("parent"))
06453       res = TRUE;
06454 
06455   return res;
06456 } // end of oaa_class
06457 
06458 /*
06459  *       oaa_assertz(Clause, Owner, SpecifiedCallback)
06460  *       oaa_retract(Clause, Owner, SpecifiedCallback)
06461  *       oaa_retractall(Clause, Owner, SpecifiedCallback)
06462  *       oaa_replace_all(Clause1, Clause2, Owner, SpecifiedCallback)
06463  * purpose: Perform data updates with bookkeeping info (in oaa_data_ref/3)
06464  * remarks: These should only be used with data solvables having param
06465  *          bookkeeping(true).
06466  *          There are still a couple limitations related to data callbacks.
06467  *          First, callbacks don't work when bookkeeping(false).
06468  *          Second, oaa_replace_all assumes the same callback is appropriate
06469  *          for both the old and new facts.
06470  */
06471 int oaa_asserta(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback)
06472 {
06473   ICLTerm *ref, *now, *t1;
06474 #ifndef _WINDOWS
06475   struct timeval tv;
06476 #else
06477   time_t ltime;;
06478 #endif
06479   (void)callback;
06480 
06481   asserta_ref(clause, &ref);
06482 
06483   /* Time in seconds since UTC 1/1/70 */
06484 #ifndef _WINDOWS
06485   gettimeofday(&tv, (void *)0);
06486   now = icl_NewFloat(tv.tv_sec*1000.0 + tv.tv_usec);
06487 #else
06488   time( &ltime );
06489   now = icl_NewFloat(ltime*1000.0);
06490 #endif
06491   asserta(icl_NewStruct("oaa_data_ref", 3, ref, owner, now));
06492   oaa_call_callback("app_on_data_change", (t1 = icl_NewStruct("add", 1, clause)), NULL, NULL);
06493   icl_Free(t1);
06494   return TRUE;
06495 }
06496 
06497 int oaa_assertz(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback)
06498 {
06499   ICLTerm *ref, *now, *t1;
06500 #ifndef _WINDOWS
06501   struct timeval tv;
06502 #else
06503   time_t ltime;;
06504 #endif
06505   (void)callback;
06506 
06507   // Stores the clause in the database and
06508   // returns (create) a unique id for it (ref).
06509   assertz_ref(clause, &ref);
06510   /* Time in seconds since UTC 1/1/70 */
06511 #ifndef _WINDOWS
06512   gettimeofday(&tv, (void *)0);
06513   now = icl_NewFloat(tv.tv_sec*1000.0 + tv.tv_usec);
06514 #else
06515   time( &ltime );
06516   now = icl_NewFloat(ltime*1000.0);
06517 #endif
06518   asserta(icl_NewStruct("oaa_data_ref", 3, ref, owner, now));
06519   oaa_call_callback("app_on_data_change", (t1 = icl_NewStruct("add", 1, icl_CopyTerm(clause))),NULL,NULL);
06520   icl_Free(t1);
06521   return TRUE;
06522 }
06523 
06524 int oaa_retract(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback)
06525 {
06526   ICLTerm *ref, *t1;
06527   (void)callback;
06528 
06529   if (ref_for_clause(clause, &ref)) {
06530     t1 = icl_NewStruct("oaa_data_ref", 3, ref, icl_CopyTerm(owner),
06531                        icl_NewVar("_"));
06532     if (retract(t1)) {
06533       erase_ref(clause, ref);
06534       icl_Free(t1);
06535 
06536       t1 = icl_NewStruct("remove", 1, icl_CopyTerm(clause));
06537       oaa_call_callback("app_on_data_change", t1, NULL, NULL);
06538       icl_Free(t1);
06539       retract(clause);
06540       return TRUE;
06541     }
06542     icl_Free(t1);
06543   }
06544   return FALSE;
06545 }
06546 
06547 int oaa_retractall(ICLTerm *clause, ICLTerm *owner, ICLTerm *callback)
06548 {
06549   while (oaa_retract(clause, owner, callback));
06550   return TRUE;
06551 }
06552 
06553 int oaa_replace_all(ICLTerm *clause1, ICLTerm *clause2, ICLTerm *owner,
06554                     ICLTerm *callback) {
06555   ICLTerm *dummyvar = icl_NewVar("_old_owner");
06556   /* ??? Hopefully, dummyvar will unify properly with any owner */
06557   while(oaa_retract(clause1, dummyvar, callback))
06558     oaa_assertz(clause2, owner, callback);
06559   icl_Free(dummyvar);
06560   return TRUE;
06561 }
06562 
06563 /*****************************************************************************
06564  * Requesting Services
06565  *****************************************************************************/
06566 
06567 static int oaaSolveRec = 0;
06706 int oaa_Solve(ICLTerm *goal, ICLTerm *initial_params, ICLTerm **out_params,
06707               ICLTerm **solutions) {
06708   int compound, res = FALSE;
06709   ICLTerm *params=NULL, *new_params = NULL, *id = NULL, *contexts = NULL, *t1 = NULL;
06710   ICLTerm *tmp_params = NULL;
06711   ++oaaSolveRec;
06712 
06713   icl_standardize_params(initial_params, FALSE, &params);
06714   /* Trace message */
06715 #ifdef UNNEEDED_DEBUG
06716   arglist = (icl_NewList(
06717               icl_NewCons(
06718                icl_CopyTerm(goal),
06719                icl_NewCons(icl_CopyTerm(params),NULL))));
06720   {
06721     char *debugStr = icl_NewStringFromTerm(arglist);
06722     oaa_TraceMsg("\n\nStarting oaa_Solve request:\n %s\n", debugStr,NULL);
06723     icl_stFree(debugStr);
06724     icl_Free(arglist);
06725   }
06726 #endif /* UNNEEDED_DEBUG */
06727 
06728   /* check for inappropriate params */
06729   t1 = icl_NewTermFromString("cache(true)");
06730   if (icl_GetParamValue(t1, params, NULL) &&
06731       icl_compound_goal(goal)) {
06732     char *debugStr = icl_NewStringFromTerm(goal);
06733 
06734     printf("%s: %s (%s)\n  Goal: %s\n", "Warning",
06735            "Ignoring 'cache' parameter", "cannot be used with compound goal",
06736            debugStr);
06737     icl_stFree(debugStr);
06738     compound = TRUE;
06739   }
06740   else {
06741     compound = FALSE;
06742   }
06743   icl_Free(t1);
06744 
06745   /* Add context to params.  Regarding the condition, see comments in
06746      the corresponding code of oaa.pl */
06747   t1 = icl_NewTermFromString("reply(true)");
06748   if (icl_GetParamValue(t1, params, NULL) &&
06749       oaa_retrieve_nth_current_contexts(&id, &contexts, 0)) {
06750     icl_append_to_list(contexts, params, &new_params);
06751   }
06752   else {
06753     new_params = params;
06754   }
06755   icl_Free(t1);
06756 
06757   /* check cache */
06758   /*
06759    * ??? Not sure how to handle exception in C.  Prolog version has:
06760    * on_exception(_, oaa_InCache(Goal, Solutions), fail) ->
06761    */
06762   t1 = icl_NewTermFromString("cache(true)");
06763   if (icl_GetParamValue(t1, new_params, NULL) &&
06764       !compound &&
06765       oaa_InCache(goal, solutions)) {
06766 
06767 #ifdef UNNEEDED_DEBUG
06768     {
06769       char *debugStr = icl_NewStringFromTerm(*solutions);
06770       oaa_TraceMsg("\n\nSolutions found in cache:\n    %s.\n",
06771                    debugStr,NULL);
06772       icl_stFree(debugStr);
06773     }
06774 #endif /* UNNEEDED_DEBUG */
06775     icl_Free(t1);
06776     res = TRUE;
06777   }
06778   else { /* me */
06779     /* Should I solve this only locally? */
06780     ICLTerm *me;
06781     int meRes;
06782 
06783     /*
06784     {
06785       char* ds = icl_NewStringFromTerm(params);
06786       fprintf(stderr, "%i Params me: %s\n", oaaSolveRec, ds);
06787       icl_stFree(ds);
06788     }
06789     */
06790     icl_Free(t1);
06791     meRes = oaa_PrimaryAddress(&me);
06792     if(meRes == FALSE) {
06793       fprintf(stderr, "oaa_Solve: could not get my address--not connected?\n");
06794       --oaaSolveRec;
06795       return FALSE;
06796     }
06797     t1 = icl_NewStruct("address", 1, me);
06798     if (meRes && icl_GetParamValue(t1, params, NULL)) {
06799       icl_Free(t1);
06800       res = oaa_solve_local(goal, new_params, solutions);
06801     }
06802     else { /* send request to facilitator */
06803       char* newId = new_goal_id();
06804       ICLTerm* local_goal_id = icl_NewStr(newId);
06805       /*
06806       {
06807         char* ds = icl_NewStringFromTerm(params);
06808         fprintf(stderr, "%i Params after send request to fac: %s\n", oaaSolveRec, ds);
06809         icl_stFree(ds);
06810       }
06811       */
06812       icl_Free(t1);
06813       icl_stFree(newId);
06814       /*
06815       {
06816         char* ds = icl_NewStringFromTerm(params);
06817         fprintf(stderr, "%i Params before cont_solve: %s\n", oaaSolveRec, ds);
06818         fflush(stderr);
06819         icl_stFree(ds);
06820       }
06821       */
06822       /* printf("calling oaa_cont_solve\n");*/
06823       res = oaa_cont_solve(local_goal_id,
06824                            goal,
06825                            new_params,
06826                            solutions,
06827                            &tmp_params);
06828 
06829       /* printf("oaa_cont_solve done\n");*/
06830       /*
06831       {
06832         char* ds = icl_NewStringFromTerm(params);
06833         fprintf(stderr, "%i Params before free: %s\n", oaaSolveRec, ds);
06834         icl_stFree(ds);
06835       }
06836       */
06837       icl_Free(local_goal_id);
06838       if (res) {
06839         if(new_params != NULL) {
06840           if(new_params == params) {
06841             /*
06842             {
06843               char* ds = icl_NewStringFromTerm(params);
06844               fprintf(stderr, "%i Freeing params: %s\n", oaaSolveRec, ds);
06845               icl_stFree(ds);
06846             }
06847             */
06848             icl_Free(params);
06849           }
06850           else {
06851             icl_Free(params);
06852             icl_Free(new_params);
06853           }
06854         }
06855         new_params = tmp_params; /* copy output params */
06856         /* print appropriate trace message */
06857 #ifdef UNNEEDED_DEBUG
06858         t1 = icl_NewTermFromString("reply(none)");
06859         if (icl_GetParamValue(t1, new_params, NULL)){
06860           //oaa_TraceMsg("\n\nMessage broadcast.\n", NULL); UNEEDED_DEBUG
06861         }
06862         else {
06863           //oaa_TraceMsg("\n\nSolutions returned:\n    %s.\n", UNNEDED_DEBUG
06864           //  icl_NewStringFromTerm(*solutions),NULL);
06865         }
06866         icl_Free(t1);
06867 #endif /* UNNEEDED_DEBUG */
06868         /* cache returned solutions if necessary */
06869         t1 = icl_NewTermFromString("cache(true)");
06870         if (icl_GetParamValue(t1, new_params, NULL) &&
06871             (*solutions)->p) {
06872           oaa_AddToCache(goal, *solutions);
06873           //oaa_TraceMsg("Solutions cached.\n",NULL);
06874         }
06875         icl_Free(t1);
06876       }
06877 
06878       if (out_params && new_params) {
06879         *out_params = icl_CopyTerm(new_params);
06880       }
06881 
06882       icl_Free(local_goal_id);
06883     }
06884   }
06885   if (new_params == tmp_params) {
06886     new_params = NULL;
06887   }
06888   if(tmp_params != NULL) {
06889     icl_Free(tmp_params);
06890   }
06891   if ((new_params != params)) {
06892     icl_Free(new_params);
06893     icl_Free(params);
06894   }
06895   else {
06896     icl_Free(params);
06897   }
06898   --oaaSolveRec;
06899   return res;
06900 }
06901 
06902 int oaa_solve_local(ICLTerm *full_goal, ICLTerm *params, ICLTerm **solutions)
06903 {
06904   // chantier
06905   ICLTerm *tmp=NULL;
06906   ICLTerm *goal_params=NULL;
06907   ICLTerm *solvables=NULL;
06908   ICLTerm *goal1=NULL;
06909   ICLTerm *goal=NULL;
06910   ICLTerm *new_params=NULL;
06911   ICLTerm *t1 = NULL;
06912   ICLTerm *matched=NULL;
06913   ICLTerm *all_params = NULL;
06914   int res = FALSE;
06915 
06916 
06917   /* validate the goal */
06918   icl_GoalComponents(full_goal, &tmp, &goal1, &goal_params);
06919   solvables = valid_oaa_solvables();
06920 
06921   {
06922 
06923   }
06924 
06925   // Rhaa
06926   if (!(icl_compound_goal(goal1) || icl_BuiltIn(goal1))) {
06927     oaa_goal_matches_solvables(goal1, solvables, &goal, &matched);
06928   }
06929 
06930   /* If the goal is not found, returns false */
06931   if (goal == NULL) {
06932     if(!*solutions) {
06933       *solutions = icl_NewList(NULL);
06934     }
06935   }
06936   else {
06937     /*
06938      * More "local" params take precedence, so they go to the
06939      * beginning of the list:
06940      */
06941     icl_append_to_list(goal_params, params, &all_params);
06942 
06943     /*
06944      * We don't want tests to be performed repeatedly with compound goals,
06945      * so we remove them after testing.
06946      */
06947     if (passes_tests(all_params)) {
06948       ICLTerm* tempTerm=NULL;
06949       ICLTerm* solvParams = icl_NthTerm(matched, 2);
06950       ICLTerm *empty_list = icl_NewList(NULL);
06951 
06952       t1 = icl_NewTermFromString("test(_)");
06953       icl_ListDelete(all_params, t1, &new_params);
06954       icl_Free(t1);
06955 
06956       /* Checks wether the solvable is a Data one */
06957       tempTerm = icl_NewTermFromString("type(data)");
06958       if (icl_GetParamValue(tempTerm, solvParams, NULL)) {
06959         res = db_Solve(local_db, goal, empty_list, solutions);
06960       }
06961       else {
06962         res = oaa_Interpret(goal, new_params, solutions);
06963       }
06964 
06965       icl_Free(empty_list);
06966       icl_Free(tempTerm);
06967 
06968       /*
06969         icl_ParamValueAsInt("solution_limit", all_params, &n);
06970       */
06971     } else {
06972       //oaa_TraceMsg("\nDoesn't pass test in: %s\n", icl_NewStringFromTerm(full_goal),NULL); UNNEDED_DEBUG
06973     }
06974     /* DEBUG
06975        if (!res)
06976        printf("\nError: do not know how to solve: %s\n",
06977        icl_NewStringFromTerm(full_goal));
06978     */
06979 
06980     icl_Free(all_params);
06981   icl_Free(goal);
06982   }
06983   icl_Free(tmp);
06984   icl_Free(goal1);
06985   icl_Free(goal_params);
06986   icl_Free(matched);
06987   icl_Free(new_params);
06988   return res;
06989 }
06990 
06995 int oaa_cont_solve(ICLTerm  *goal_id,   ICLTerm  *goal, ICLTerm *global_params,
06996                    ICLTerm **solutions, ICLTerm **out_params) {
06997 
06998   int answer = FALSE;
06999   ICLTerm *anAddress = NULL;
07000   ICLTerm *fullGoal = NULL;
07001   ICLTerm *actualGoal = NULL;
07002   ICLTerm *new_global_params = NULL;
07003   int freeFullGoal = FALSE;
07004   static ICLTerm *full_goal_struct = NULL;
07005   static ICLTerm *addr_struct = NULL;
07006   static ICLTerm *d_c_struct = NULL;
07007 
07008   if (!icl_IsValid(full_goal_struct)) {
07009     full_goal_struct = icl_NewTermFromData("full_goal(_)", 12);
07010     addr_struct      = icl_NewTermFromData("address(AnAddress)", 18);
07011     d_c_struct       = icl_NewTermFromData("direct_connect(true)", 20);
07012   }
07013 
07014   if (icl_GetParamValue(full_goal_struct, global_params, &fullGoal)) {
07015     actualGoal = icl_NthTerm(fullGoal,1);
07016     // "goal" is just a template for planning...
07017     // remove full_goal from global params since it could be big...
07018     icl_ListDelete(global_params, full_goal_struct, &new_global_params);
07019     freeFullGoal = TRUE;
07020   }
07021   else {
07022     actualGoal = goal;
07023     new_global_params = global_params;
07024     freeFullGoal = FALSE;
07025   }
07026 
07027   if (icl_GetParamValue(addr_struct, global_params, &anAddress)
07028    && icl_GetParamValue(d_c_struct, global_params, NULL)) {
07029     // address AND direct_connect specified
07030     ICLTerm *addr = icl_NthTerm(anAddress,1);
07031     /*
07032     {
07033       fprintf(stderr, "Calling oaa_cont_solve_direct with addr\n");
07034     }
07035     */
07036     answer = oaa_cont_solve_direct(goal_id, actualGoal, addr, new_global_params,
07037                                                           solutions, out_params);
07038   }
07039   else if (!icl_GetParamValue(addr_struct, global_params, NULL)
07040          && icl_GetParamValue(d_c_struct, global_params, NULL)) {
07041     // direct_connect specified without address
07042     /*
07043     {
07044       fprintf(stderr, "Calling oaa_cont_plan\n");
07045     }
07046     */
07047     answer = oaa_cont_plan(goal_id, goal, actualGoal, new_global_params,
07048                                                   solutions, out_params);
07049   }
07050   else {
07051     // "OAA Classic"...no direct_connect
07052     /*
07053     {
07054       fprintf(stderr, "Calling oaa_cont_solve_direct with NULL addr\n");
07055     }
07056     */
07057     answer = oaa_cont_solve_direct(goal_id, actualGoal, NULL, new_global_params,
07058                                                           solutions, out_params);
07059   }
07060 
07061   icl_Free(anAddress);
07062   if (freeFullGoal) {
07063     icl_Free(fullGoal);
07064     icl_Free(new_global_params);
07065   }
07066   return answer;
07067 }
07068 
07069 /*****************************************************************************
07070  * purpose: Convenience function:  oaa_Solve with default parameters
07071  ****************************************************************************/
07072 
07073 /* ??? Can't do function name overloading in C
07074    oaa_Solve(Goal) :- oaa_Solve(Goal, []). */
07075 
07076 
07081 int oaa_InCache(ICLTerm *goal, ICLTerm **solutions) {
07082   /* ??? Don't currently have a way to check for subsumption,
07083      Use plain old unify for now */
07084   return oaa_retrieve_all_cache(goal, solutions);
07085 }
07086 
07091 int oaa_AddToCache(ICLTerm *goal, ICLTerm *solutions) {
07092   ICLListType *slist = NULL;
07093   /* safety check */
07094   if(icl_IsList(solutions)) {
07095     slist = icl_List(solutions);
07096   }
07097   while(icl_ListHasMoreElements(slist)) {
07098     ICLTerm *soln = icl_ListElement(slist);
07099     oaa_assert_cache(goal, soln);
07100     slist = icl_ListNextElement(slist);
07101   }
07102   return TRUE;
07103 }
07104 
07108 int oaa_ClearCache() {
07109   ICLTerm *dummyvar = icl_NewVar("_");
07110   ICLTerm *allcache = icl_NewStruct("oaa_cache", 2, dummyvar, dummyvar);
07111   oaa_retractall_cache(allcache);
07112   icl_Free(allcache);
07113   icl_Free(dummyvar);
07114   return TRUE;
07115 }
07116 
07124 int oaa_poll_until_event(ICLTerm *event, ICLTerm **solution) {
07125   ICLTerm *pterm;
07126   int p;
07127   static ICLTerm *temp_term = NULL;
07128   int answer;
07129 
07130   if (!icl_IsValid(temp_term)) {
07131     temp_term = icl_NewTermFromData("priority(P)",11);
07132   }
07133   icl_param_default(temp_term, &pterm);
07134   p = icl_Int(icl_NthTerm(pterm,1));
07135   icl_Free(pterm);
07136   answer = oaa_poll_until_event_priority(event, p, solution);
07137   return answer;
07138 }
07139 
07140 int oaa_poll_until_event_priority(ICLTerm *event, int priority,
07141                                   ICLTerm **solutions) {
07142   int res;
07143   ICLTerm *event_list = icl_NewList(icl_NewCons(icl_CopyTerm(event), NULL));
07144 
07145   /* Determines wether solutions should be returned or not */
07146   if (solutions) {
07147     /* note that oaa_poll_until_all_events can take an initialized list */
07148     ICLTerm* local_solutions = icl_NewList(NULL);
07149     res = oaa_poll_until_all_events(event_list, priority, &local_solutions);
07150     /* Since oaa_poll_until_all_events returns a list of solution
07151        and oaa_poll_until_event_priority returns one solution, we
07152        extract it from the returned list.
07153     */
07154     if (local_solutions && (icl_NumTerms(local_solutions)>0)) {
07155       *solutions = icl_CopyTerm(icl_NthTerm(local_solutions, 1));
07156     }
07157     icl_Free(local_solutions);
07158   }
07159   else {
07160     res = oaa_poll_until_all_events(event_list, priority, NULL);
07161   }
07162   icl_Free(event_list);
07163   return res;
07164 }
07165 
07170 /*
07171  * Note :
07172  * event_list : The list of events we are waiting for.
07173  */
07174 int oaa_poll_until_all_events(ICLTerm *event_list, int priority,
07175                               ICLTerm **solutions) {
07176   ICLTerm *event = (ICLTerm *)NULL, *params = (ICLTerm *)NULL;
07177   ICLTerm *dummyvar = icl_NewVar("_");
07178   int res = FALSE;
07179 
07180 //  {
07181 //    char* eventList = icl_NewStringFromTerm(event_list);
07182 //    icl_stFree(eventList);
07183 //  }
07184 
07185   if(solutions != NULL) {
07186     if(*solutions == NULL) {
07187       *solutions = icl_NewList(NULL);
07188     }
07189   }
07190 
07191   if(!event_list->p) {
07192     return TRUE; /* no more events, we're done! */
07193   }
07194 
07195   while(!res) {
07196     int otherres = 0;
07197     /*
07198      * If we have a waiting event, grab it (see problem description in
07199      * oaa_is_waiting_for()
07200      */
07201     event = NULL;
07202     otherres = oaa_grab_waiting_event(event_list, &event);
07203     CHECK_LEAKS();
07204     if(!otherres) {
07205       oaa_GetEvent(&event, &params, 0);
07206       CHECK_LEAKS();
07207     }
07208     CHECK_LEAKS();
07209     /*
07210      * if timeout returned, check triggers and call user:oaa_AppIdle
07211      * the fail (continue with next clause)
07212      */
07213     CHECK_LEAKS();
07214     if (STREQ(icl_Str(event), "timeout")) {
07215       if (oaa_CheckTriggers("task", dummyvar, "_")) {
07216         ICLTerm *tmpArgs = icl_NewList(NULL);
07217         oaa_call_callback("oaa_AppIdle", dummyvar, tmpArgs, NULL);
07218         icl_Free(tmpArgs);
07219       }
07220     }
07221     else {
07222       CHECK_LEAKS();
07223       oaa_cont_poll_until_all_events(event_list, event, params,
07224                                      priority, solutions);
07225       CHECK_LEAKS();
07226       res = TRUE;
07227     }
07228     icl_Free(event);
07229     icl_Free(params);
07230   }
07231   icl_Free(dummyvar);
07232   return res;
07233 }
07234 
07235 /**********************************************************************
07236  * Note :
07237  *   event_list : Events we are waiting for
07238  *   event : New event coming from oaa_GetEvent
07239  **********************************************************************/
07240 
07241 int oaa_cont_poll_until_all_events(ICLTerm *event_list, ICLTerm *event,
07242                                    ICLTerm *params, int priority,
07243                                    ICLTerm **solutions) {
07244   static int cntr = 0;
07245   char buf[128];
07246   ICLTerm *new_event_list, *wait_id, *tmp_event_list;
07247   /* The incoming event is in the list of the events we
07248      are waiting for.
07249   */
07250   ICLTerm *removed_from_list = NULL;
07251 
07252   CHECK_LEAKS();
07253   removed_from_list = remove_element(event, event_list, &new_event_list);
07254   /*
07255   {
07256     char* gotEvent;
07257     char* eventList;
07258     char* removed;
07259     gotEvent = icl_NewStringFromTerm(event);
07260     eventList = icl_NewStringFromTerm(event_list);
07261     if(removed_from_list != NULL) {
07262       removed = icl_NewStringFromTerm(removed_from_list);
07263     }
07264     else {
07265       removed = "(nil)";
07266     }
07267     printf("  Event: [%s]\n  Event list: [%s]\n  Removed: [%s]\n", gotEvent, eventList, removed);
07268     icl_stFree(gotEvent);
07269     icl_stFree(eventList);
07270     if(removed_from_list != NULL) {
07271       icl_stFree(removed);
07272     }
07273   }
07274   */
07275   CHECK_LEAKS();
07276   /* Something is wrong here--either we use new_event_list and free
07277    * event_list, or we don't free removed_from_list
07278    */
07279   if (removed_from_list) {
07280     if (solutions) {
07281       if(*solutions == NULL) {
07282         *solutions = icl_NewList(NULL);
07283       }
07284       icl_AddToList(*solutions, icl_CopyTerm(event), TRUE);
07285     }
07286     icl_Free(new_event_list);
07287     /*icl_Free(removed_from_list);*/
07288     return TRUE;
07289   }
07290   else {
07291     //if (oaa_poll_until_all_events(new_event_list, priority, solutions)) {
07292     /*
07293      * if the new event is a ev_solved() message for which we
07294      * are waiting at a higher recursive level, save this for
07295      * a later time, until we pop back out to the correct level.
07296      */
07297     if(oaa_is_waiting_for(event)) {
07298       oaa_assert_waiting_event(event);
07299     }
07300     else {
07301       /* record what events we are waiting for on this processing level */
07302       sprintf(buf, "wait%d", cntr);
07303       ++cntr;
07304       wait_id = icl_NewStr(buf);
07305       oaa_assert_waiting_for(wait_id, event_list);
07306       oaa_ProcessEvent(event, params);
07307       /* level over, remove waiting statement */
07308       oaa_retract_waiting_for(wait_id, &tmp_event_list);
07309     }
07310     return oaa_poll_until_all_events(event_list, priority, solutions);
07311   }
07312   return FALSE;
07313 }
07314 
07315 
07316 /*****************************************************************************
07317  * Callbacks
07318  *****************************************************************************/
07319 
07320 
07325 int oaa_RegisterCallback(char* callback_id, int (*callback_proc)(ICLTerm*, ICLTerm*, ICLTerm*)) {
07326   ICLTerm* callbackId;
07327 
07328   // For backwards compatibility:
07329   if (strcmp(callback_id, "oaa_AppDoEvent") == 0) {
07330     callback_id = "app_do_event";
07331   }
07332   else if (strcmp(callback_id,  "oaa_AppIdle") == 0) {
07333     callback_id = "app_idle";
07334   }
07335   else if (strcmp(callback_id,  "oaa_AppDone") == 0) {
07336     callback_id = "app_done";
07337   }
07338 
07339   callbackId = icl_NewStr(callback_id);
07340   /*
07341   printf("liboaa.c oaa_RegisterCallback() mapping callback named %s to function pointer %p\n",
07342          callback_id,
07343          callback_proc);
07344   */
07345   oaa_assert_callback(callbackId, callback_proc);
07346   CHECK_LEAKS();
07347   icl_Free(callbackId);
07348   CHECK_LEAKS();
07349   return TRUE;
07350 }
07351 
07352 int oaa_GetCallback(char* callback_id, int (**callback_proc)(ICLTerm*, ICLTerm*, ICLTerm*)) {
07353   ICLTerm* tempTerm = icl_NewStr(callback_id);
07354   int result = oaa_retrieve_callback(tempTerm, callback_proc);
07355   icl_Free(tempTerm);
07356   return result;
07357 }
07358 
07359 int oaa_call_callback(char* callback_id, ICLTerm *goal, ICLTerm* params, ICLTerm* solutions) {
07360   char* goalStr;
07361   /* Pointer to the callback we are looking for */
07362   int (*callback_proc)(ICLTerm*, ICLTerm*, ICLTerm*)=NULL;
07363   /* Check if we have a specific callback for this solvable */
07364   oaa_GetCallback(callback_id, &callback_proc);
07365 
07366   if (callback_proc) {
07367     goalStr = icl_NewStringFromTerm(goal);
07368     icl_stFree(goalStr);
07369     return callback_proc(goal, params, solutions);
07370   }
07371   else if(goal != NULL && strcmp("oaa_AppIdle",callback_id)) {
07372     goalStr = icl_NewStringFromTerm(goal);
07373     printf("oaa_call_callback no callback for id %s and goal %s from term pointer %p\n", callback_id, goalStr, goal);
07374     icl_stFree(goalStr);
07375   }
07376   return FALSE;
07377 }
07378 
07379 /*
07380  * Generates a unique ID for a goal.
07381  * remarks:
07382  *   - ID's should be unique across Facilitators which is why we use the
07383  *     Name prefix
07384  *   - Goal counters are used to make sure the solution really matches the
07385  *     query.
07386  */
07387 char* new_goal_id()
07388 {
07389 // re-worked so that icl_NewStringFromTerm()
07390 // is called only once
07391   char *res = NULL;
07392   static char *idStr = NULL;
07393   ICLTerm *myPrimId = NULL;
07394   char temp[255];
07395 
07396   if (idStr == NULL) {
07397     if (oaa_PrimaryId(&myPrimId)) {
07398       idStr = icl_NewStringFromTerm(myPrimId);
07399       icl_Free(myPrimId);
07400     }
07401   }
07402   sprintf(temp, "g_%s%d", idStr, globalCounter++);
07403   res = strdup(temp);
07404 
07405   if(idStr == NULL) {
07406     printf("liboaa.c::new_goal_id() Warning: No result\n");
07407   }
07408 
07409   return res;
07410 }
07411 
07412 /****
07413  * Generates a unique ID for a trigger assertion.
07414  ***/
07415 
07416 char* new_trigger_id() {
07417   char *res = NULL;
07418 
07419   ICLTerm *myPrimId = NULL;
07420   if (oaa_PrimaryId(&myPrimId)) {
07421     char temp [255];
07422     sprintf(temp, "t_%s%d", icl_NewStringFromTerm(myPrimId),globalCounter++);
07423     res = strdup(temp);
07424     icl_Free(myPrimId);
07425   }
07426   return res;
07427 }
07428 
07429 /*****************************************************************************
07430  * Debugging
07431  ****************************************************************************/
07432 
07436 int oaa_TraceMsg(char *format_string, ...) {
07437   if (oaa_trace_on) {
07438     char buf[1000];
07439     va_list ptr;
07440     va_start(ptr,format_string);
07441     vsprintf(buf,format_string,ptr);
07442     printf("%s\n", buf);
07443     va_end(ptr);
07444   }
07445   return TRUE;
07446 }
07447 
07451 int oaa_ComTraceMsg(char *format_string, ...) {
07452   if (oaa_com_trace_on){
07453     char buf[10000];
07454     va_list ptr;
07455     va_start(ptr,format_string);
07456     vsprintf(buf,format_string,ptr);
07457     printf("%s\n", buf);
07458     va_end(ptr);
07459   }
07460   return TRUE;
07461 }
07462 
07463 /*
07464  * Start debugging if debug mode is on.
07465  * Use predicate_property and call so as to avoid errors in
07466  * building and running a Quintus runtime system.
07467  */
07468 int oaa_turn_on_debug() {
07469   if(oaa_debug_on) {
07470     /* ??? Again, there's no user module, so what to do with
07471        ( predicate_property(user:trace, built_in) ->
07472        call(user:trace)
07473        ??? */
07474   }
07475   return TRUE;
07476 }
07477 /*
07478  * Stop debugging if debug mode is on.
07479  * Use predicate_property and call so as to avoid errors in
07480  * building and running a Quintus runtime system.
07481  */
07482 int oaa_turn_off_debug() {
07483   if(oaa_debug_on) {
07484     /* ??? Again, there's no user module, so what to do with
07485        ( predicate_property(user:trace, built_in) ->
07486        call(user:trace)
07487        ??? */
07488   }
07489   return TRUE;
07490 }
07491 
07492 /*****************************************************************************
07493  * User Interface
07494  ****************************************************************************/
07499 int oaa_Inform(ICLTerm *type_info, char *format_string, ICLTerm *args) {
07500 
07501 #ifdef OAA_INFORM
07502 
07503   char result[512];
07504   int res = FALSE;
07505   (void)type_info;
07506   (void)format_string;
07507   (void)args;
07508   if(oaa_TraceMsg(format_string, args) &&
07509      oaa_class("leaf")) {
07510     if(icl_IsList(args)) {
07511       ICLListType *plist = icl_List(args);
07512       va_list ap;
07513       /* convert terms into strings that can be passed as an
07514          argument list into fprintf() */
07515       va_start(ap);
07516       while(icl_ListHasMoreElements(plist)) {
07517         char *term_string = icl_Str(icl_ListElement(plist));
07518         va_arg(ap, char *) = term_string;
07519         plist = icl_ListNextElement(plist);
07520       }
07521       va_end(ap);
07522       vsprintf(result, format_string, ap);
07523       res = oaa_Solve(icl_NewStruct("inform", 2, type_info,
07524                                     icl_NewStr(result)),
07525                       icl_NewList(
07526                        icl_NewCons(
07527                         icl_NewTermFromString("strategy(inform)"),
07528                         NULL)));
07529     }
07530   }
07531   return res;
07532 
07533 #endif
07534 
07535   (void)type_info;
07536   (void)format_string;
07537   (void)args;
07538   return FALSE;
07539 }
07540 
07541 /*****************************************************************************
07542  * Connection primitives
07543  ****************************************************************************/
07544 
07545 /*****************************************************************************
07546 %%% BUG/HACK!!!!!
07547 % tcp_send/1 is not currently defined (new version of quintus)
07548 % so these predicates should fail.  This means we can't have
07549 % multilevel facilitators.
07550 % However, if we fix it by the tcp_send/2 version (commented out),
07551 % killing the agent doesn't shut down both connections and the
07552 % facilitator server doesn't register the agent as disconnected.
07553 % This must be fixed, but I don't have time now...
07554 
07555 % Ask the root agent for the address of facilitator FacName.
07556 % Either FacId or FacName may be bound.
07557 % IMPORTANT: This assumes the root agent is the only connection when
07558 % this is called.
07559 % @@Not happy with the use of a Connection number in the address param here.
07560 % Can an address be a connection number as well as an id or name???  [No.]
07561 
07562 % get_address(FacId, FacName, Port, Host):-
07563 %         tcp_connected(RootConnection),
07564 %   oaa_Solve(agent_location(FacId, FacName, Port, Host),
07565 %       [address(RootConnection)]).
07566 
07567 
07568 %% succeed if FacName has not been registered with the root agent.
07569 %%    otherwise, ask user to enter a different name for FacName
07570 
07571 % check_name_duplication(MyName, NewMyName) :-
07572 %         tcp_send(ev_check_agent_name(MyName)),
07573 %         oaa_select_event(0, X),
07574 %         oaa_extract_event(X, Result, _), %% 'UNIQUE'
07575 %         (Result == 'UNIQUE' -> NewMyName = MyName
07576 %                 ;
07577 %         format('Name is duplicated~n',[]),
07578 %         format('The following are registered ~n ~q ~n',[Result]),
07579 %         format('Input agent name again:',[]),
07580 %         read(NewMyName)).
07581 
07582 % report_address_to_root(MyName, NewAddress):-
07583 %   tcp_send(register_port_number(MyName, NewAddress)).
07584 
07585 
07586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
07587 % routines to fix bug:
07588 %   blocking solve1
07589 %      incoming event generates blocking solve2
07590 %      solution to solve1 thrown away!!!
07591 %      solutions to solve2
07592 %   stuck  waiting for solve1 forever
07593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
07594 
07595 ****************************************************************************/
07596 
07601 int oaa_is_waiting_for(ICLTerm *event)
07602 {
07603   int result;
07604   ICLTerm *event_list = NULL;
07605   ICLTerm *dummyvar = icl_NewVar("_");
07606 
07607   oaa_retrieve_all_waiting_for(dummyvar, &event_list);
07608   icl_Free(dummyvar);
07609 
07610   if(icl_Member(event, event_list, NULL))
07611     result = TRUE;
07612   else
07613     result = FALSE;
07614 
07615   icl_Free(event_list);
07616   return(result);
07617 }
07618 
07623 int oaa_grab_waiting_event(ICLTerm *event_list, ICLTerm **event)
07624 {
07625   ICLTerm     *test_events, *an_event, *unified_event;
07626   ICLListType *elist;
07627   int          returnValue = FALSE;
07628 
07629   oaa_retrieve_all_waiting_events(&test_events);
07630   elist = icl_List(test_events);
07631 
07632   while(icl_ListHasMoreElements(elist)) {
07633     an_event = icl_ListElement(elist);
07634     elist = icl_ListNextElement(elist);
07635 
07636     if(icl_Member(an_event, event_list, &unified_event)) {
07637       oaa_retract_waiting_event(unified_event);
07638       *event = unified_event;
07639       returnValue = TRUE;
07640       break;
07641     }
07642   }
07643   icl_Free(test_events);
07644   return returnValue;
07645 }
07646 
07647 /*****************************************************************************
07648  * OAA Utilities
07649  ****************************************************************************/
07655 int oaa_remove_solvables_data(ICLTerm *solvables) {
07656   int res = FALSE;
07657   if(icl_IsList(solvables)) {
07658     ICLListType *slist = icl_List(solvables);
07659     ICLTerm *dummyvar = icl_NewVar("_");
07660     ICLTerm *type_data = icl_NewTermFromString("type(data)");
07661     ICLTerm *synonym = icl_NewStruct("synonym", 2, dummyvar, dummyvar);
07662     while(icl_ListHasMoreElements(slist)) {
07663       ICLTerm *solvable = icl_ListElement(slist);
07664       res = FALSE;
07665       if(icl_IsStruct(solvable) &&
07666          (icl_Arity(solvable) == 3)) {
07667 
07668         ICLTerm *goal = icl_NthTerm(solvable, 1);
07669         ICLTerm *params = icl_NthTerm(solvable, 2);
07670         ICLTerm *t1;
07671 
07672         if (icl_GetParamValue(type_data, params, NULL) &&
07673             (!icl_GetParamValue(synonym, params, NULL))) {
07674           /* This should have already been done, but to be safe: */
07675           /* ??? We can't really do the following in C:
07676              (clause(Goal, _, _) -> true | true),
07677           */
07678           ICLTerm *skeleton;
07679           predicate_skeleton(goal, &skeleton);
07680           if (oaa_remove_data_local(skeleton,
07681                                     (t1 = icl_NewTermFromString(
07682                                      "[do_all(true)]"))))
07683             res = TRUE;
07684           else
07685             printf(
07686              "%s: Problem in removing all data form solvable: %s\n",
07687              "! ERROR", icl_NewStringFromTerm(goal));
07688           icl_Free(t1);
07689         }
07690       }
07691       slist = icl_ListNextElement(slist);
07692     }
07693     icl_Free(synonym);
07694     icl_Free(dummyvar);
07695     icl_Free(type_data);
07696   }
07697   return res;
07698 }
07699 
07700 int oaa_remove_data_owned_by(ICLTerm *id)
07701 {
07702   ICLTerm *solvables = valid_oaa_solvables();
07703   ICLTerm *built_ins = oaa_built_in_solvables();
07704   ICLTerm *all_solvables=NULL;
07705   ICLListType *slist = NULL;
07706   ICLTerm *type_data = icl_NewTermFromString("type(data)");
07707   ICLTerm *persistent_true = icl_NewTermFromString("persistent(true)");
07708   ICLTerm *dummyvar = icl_NewVar("_");
07709   ICLTerm *synonym = icl_NewStruct("synonym", 2, icl_CopyTerm(dummyvar), icl_CopyTerm(dummyvar));
07710   int res= FALSE;
07711 
07712   icl_append_to_list(built_ins, solvables, &all_solvables);
07713   slist = icl_List(all_solvables);
07714   while(icl_ListHasMoreElements(slist)) {
07715     ICLTerm *solvable = icl_ListElement(slist);
07716     res = FALSE;
07717     if(icl_IsStruct(solvable) &&
07718        (icl_Arity(solvable) == 3)) {
07719       ICLTerm *goal = icl_NthTerm(solvable, 1);
07720       ICLTerm *params = icl_NthTerm(solvable, 2);
07721       if(icl_GetParamValue(type_data, params, NULL) &&
07722          !icl_GetParamValue(persistent_true, params, NULL) &&
07723          !icl_GetParamValue(synonym, params, NULL)) {
07724         /* This should have already been done, but to be safe: */
07725         /* ??? We can't really do the following in C:
07726            (clause(Goal, _, _) -> true | true),
07727         */
07728         ICLTerm *skeleton=NULL;
07729         ICLTerm *rparams =
07730           icl_NewList(icl_NewCons(icl_NewStruct("owner", 1, icl_CopyTerm(id)),
07731                                   icl_NewCons(icl_NewTermFromString("do_all(true)"), NULL)));
07732         predicate_skeleton(goal, &skeleton);
07733         if (oaa_remove_data_local(skeleton, rparams)) {
07734           res = TRUE;
07735         }
07736         else {
07737           char *debugStr = icl_NewStringFromTerm(goal);
07738           printf("%s: Problem in removing all data form solvable: %s\n",
07739                  "! ERROR", debugStr);
07740           icl_stFree(debugStr);
07741         }
07742         icl_Free(rparams);
07743       }
07744     }
07745     slist = icl_ListNextElement(slist);
07746   }
07747   icl_Free(synonym);
07748   icl_Free(dummyvar);
07749   icl_Free(persistent_true);
07750   icl_Free(type_data);
07751   return res;
07752 }
07753 
07754 /*****************************************************************************
07755  * General Utilities
07756  ****************************************************************************/
07757 
07758 
07759 /*****************************************************************************
07760  * name:    oaa_consult(+FilePath, -AbsFileName).
07761  * purpose:
07762  * remarks: We don't use Quintus' builtin consult, because it's too picky
07763  *          about associating predicates with files.
07764  ****************************************************************************/
07765 /* This has to do with Prolog compilation and doesn't translate into C */
07766 
07767 /*****************************************************************************
07768  * name:    load_clauses(+Stream).
07769  * purpose:
07770  ****************************************************************************/
07771 /* This has to do with Prolog compilation and doesn't translate into C */
07772 
07773 /*****************************************************************************
07774  * name:    load_clause(+Term).
07775  * purpose:
07776  ****************************************************************************/
07777 /* This has to do with Prolog compilation and doesn't translate into C */
07778 
07779 /*****************************************************************************
07780  * name:    oaa_declare_for_prolog(Solvables).
07781  * purpose: For each solvable, make sure it's known to Prolog as a dynamic
07782  *          predicate.  This will prevent exceptions and warnings from
07783  *          calls and retracts before there have been any asserts.
07784  * remarks: Solvables must be in standard form, and should include only
07785  *          data solvables.
07786  *          This is probably Quintus-specific.
07787  *          We are assuming that none of these predicates are known to
07788  *          Prolog as compiled predicates.  Would be better to check for this.
07789  ****************************************************************************/
07790 /* This has to do with Prolog compilation and doesn't translate into C */
07791 
07792 /*****************************************************************************
07793  * name:    predicate_skeleton(+Goal, +Skeleton).
07794  ****************************************************************************/
07795 int predicate_skeleton(ICLTerm *goal, ICLTerm **skeleton) {
07796   if(icl_IsStruct(goal)) {
07797     ICLTerm *dummyvar = icl_NewVar("_");
07798     char *functor = icl_Functor(goal);
07799     int arity = icl_Arity(goal);
07800     ICLTerm *arglist = icl_NewList(NULL);
07801     int i;
07802     for(i=0; i<arity; i++) {
07803       icl_AddToList(arglist, icl_CopyTerm(dummyvar), TRUE);
07804     }
07805     *skeleton = icl_NewStructFromList(functor, arglist);
07806     icl_Free(dummyvar);
07807     return TRUE;
07808   }
07809   return FALSE;
07810 }
07811 
07812 /*****************************************************************************
07813  * name:    memberchk_nobind
07814  * purpose: like memberchk, but doesn't bind variables in Elt when doing test.
07815  ****************************************************************************/
07816 /* ??? This function doesn't seem to be used anywhere */
07817 
07818 /*****************************************************************************
07819  * name:    would_unify
07820  * purpose: succeeds if X and Y WOULD unify, but doesn't actually do the
07821  *          unification (no variables are bound by test)
07822  ****************************************************************************/
07823 /* This function is unecessary in C */
07824 
07831 ICLTerm* remove_element(ICLTerm *elt, ICLTerm *list, ICLTerm **rest) {
07832   ICLTerm* removed = NULL;
07833   ICLListType *elist = icl_List(list);
07834   *rest = icl_NewList(NULL);
07835   while(icl_ListHasMoreElements(elist)) {
07836     ICLTerm *test = icl_ListElement(elist);
07837 //    {
07838 //      char* element;
07839 //      char* testStr;
07840 //      element = icl_NewStringFromTerm(elt);
07841 //      testStr = icl_NewStringFromTerm(test);
07842 //      icl_stFree(element);
07843 //      icl_stFree(testStr);
07844 //    }
07845     if(icl_Unify(elt, test, NULL)) {
07846       removed = test;
07847     }
07848     else {
07849       icl_AddToList(*rest, icl_CopyTerm(test), TRUE);
07850     }
07851     elist = icl_ListNextElement(elist);
07852   }
07853   return removed;
07854 }
07855 
07861 int replace_element(ICLTerm *elt, ICLTerm *old_list, ICLTerm *new_elt,
07862                     ICLTerm **new_list)
07863 {
07864   int res = FALSE;
07865   ICLListType *elist = icl_List(old_list);
07866   (void)new_elt;
07867   *new_list = icl_NewList(NULL);
07868   while(icl_ListHasMoreElements(elist)) {
07869     ICLTerm *unified, *test = icl_ListElement(elist);
07870     if(icl_Unify(elt, test, &unified)) {
07871       icl_AddToList(unified, icl_CopyTerm(*new_list), TRUE);
07872       res = TRUE;
07873     } else {
07874       icl_AddToList(test, icl_CopyTerm(*new_list), TRUE);
07875     }
07876     elist = icl_ListNextElement(elist);
07877   }
07878   return res;
07879 }
07880 
07881 // added for direct_connect
07882 
07883 /*
07884  * Check for an existing connection with the given agent.  If
07885  * there is none, establish one.  If that's not possible, FAIL.
07886  */
07887 static int ensure_direct_connection(ICLTerm *AgentAddress, char **ConnectionId) {
07888   int answer = FALSE;
07889   ICLTerm *other_address = icl_NewStruct("other_address", 1, icl_CopyTerm(AgentAddress));
07890   answer = com_GetConnectionId(ConnectionId, other_address);
07891   if (!answer) {
07892     ICLTerm *goal =  icl_NewStruct("agent_listener", 2,
07893                                    icl_CopyTerm(AgentAddress),
07894                                    icl_NewVar("X"));
07895 
07896     ICLTerm *solveParams = icl_NewTermFromData("[address(parent)]", 17);
07897     ICLTerm *solutions = icl_NewList(NULL);
07898     ICLTerm *myName = NULL;
07899     char *myNameString = NULL;
07900     ICLTerm *ConnectAddress = NULL;
07901     ICLTerm *connectParams = icl_NewList(NULL);
07902     icl_AddToList(connectParams, icl_NewStruct("resolve_vars", 1, icl_NewStr("false")), TRUE);
07903     icl_AddToList(connectParams, icl_CopyTerm(other_address), TRUE);
07904     oaa_Solve(goal, solveParams, NULL, &solutions);
07905     ConnectAddress = icl_CopyTerm(icl_NthTerm(icl_NthTerm(icl_NthTerm(solutions,1),2),1));
07906     if (ConnectAddress == NULL) {
07907       icl_Free(connectParams);
07908       icl_Free(ConnectAddress);
07909       icl_Free(goal);
07910       icl_Free(connectParams);
07911       icl_Free(solutions);
07912       icl_Free(solveParams);
07913       answer = FALSE;
07914     }
07915     else {
07916       *ConnectionId = new_direct_connection_id();
07917 
07918       oaa_Name(&myName);
07919       myNameString = icl_NewStringFromTerm(myName);
07920       answer = oaa_Connect(*ConnectionId, ConnectAddress, myNameString, connectParams);
07921 
07922       icl_Free(goal);
07923       icl_Free(solveParams);
07924       icl_Free(solutions);
07925       icl_Free(myName);
07926       icl_stFree(myNameString);
07927       icl_Free(ConnectAddress);
07928       icl_Free(connectParams);
07929     }
07930     CHECK_LEAKS();
07931   }
07932   icl_Free(other_address);
07933   CHECK_LEAKS();
07934   return answer;
07935 } // end of ensure_direct_connection
07936 
07937 
07938 /*
07939  *
07940  */
07941 static int isClientConnection(char *ConnectionId) {
07942   ICLTerm *t2 = NULL;
07943   ICLTerm *type = NULL;
07944   int answer = TRUE;
07945 
07946   t2 = icl_NewStruct("type", 1, icl_NewVar("T"));
07947   if (com_GetInfo(ConnectionId, t2, &type)) {
07948     answer = STREQ(icl_Str(type), "client");
07949   }
07950   icl_Free(type);
07951   icl_Free(t2);
07952   return answer;
07953 } // end of isClientConnection
07954 
07964 EXPORT_MSCPP
07965 int EXPORT_BORLAND
07966 memberchk(ICLTerm *Param, ICLTerm *ParamList) {
07967   int res = FALSE;
07968 
07969   // return FALSE quickly if args are NULL or list is empty
07970   if ((Param == NULL) ||
07971       (ParamList == NULL) ||
07972       (icl_ListLen(ParamList) == 0)) {
07973     return FALSE;
07974   }
07975 
07976   if (icl_IsStruct(Param) && (icl_NumTerms(Param) == 1) &&
07977       icl_IsList(ParamList)) {
07978     ICLTerm *p;
07979     if (icl_ParamValue(icl_Str(Param), NULL, ParamList, &p)) {
07980       res = icl_Unify(Param, p, NULL);
07981       icl_Free(p);
07982     }
07983     return res;
07984   }
07985   else {
07986     return FALSE;
07987   }
07988 } // end of memberchk
07989 
07990 
07991 /*
07992  * Generates a unique ConnectionId for a direct connection.
07993  */
07994 static char* new_direct_connection_id() {
07995     static int counter = 1;
07996     char temp[255];
07997     sprintf(temp, "direct%d", counter++);
07998     return strdup(temp);
07999 }
08000 
08007 EXPORT_MSCPP
08008 int EXPORT_BORLAND
08009 oaa_Connect(char *ConnectionId, ICLTerm *Address, char *InitialAgentName, ICLTerm *Params) {
08010 
08011     if (comConnectFormat(ConnectionId, Params, Address, COM_BEST_FORMAT) <= 0) {
08012         return FALSE;
08013     }
08014 
08015     if(!oaa_handshake(ConnectionId, InitialAgentName, Params)) {
08016         return FALSE;
08017     }
08018 
08019     return TRUE;
08020 
08021 } // end of oaa_Connect
08022 
08023 /*
08024  * If SingleAgentAddress is NULL, perform a "classic" oaa_solve().
08025  */
08026 static int oaa_cont_solve_direct(ICLTerm* goal_id,
08027                                  ICLTerm *goal,
08028                                  ICLTerm *SingleAgentAddress,
08029                                  ICLTerm *global_params,
08030                                  ICLTerm **solutions,
08031                                  ICLTerm **out_params) {
08032   ICLTerm *tmp1 = NULL;
08033   ICLTerm *tmp2 = NULL;
08034   ICLTerm *params = NULL;
08035   ICLTerm *requestees = NULL;
08036   ICLTerm *solvers = NULL;
08037   ICLTerm *solved_params = NULL;
08038   ICLTerm *dummyvar = icl_NewVar("_");
08039   ICLTerm *t1 = (ICLTerm *)NULL, *t2 = (ICLTerm *)NULL, *t3 = (ICLTerm *)NULL;
08040   ICLTerm *all_params = NULL;
08041   int res = FALSE;
08042 
08043   ICLTerm *conn_id = NULL;
08044   ICLTerm *post_params = icl_NewList(NULL);
08045   char *ConnectionId = NULL;
08046 
08047   int direct_connect_used = FALSE;
08048   static ICLTerm *get_direct_connect_used_true = NULL;
08049   static ICLTerm *get_direct_connect_used_false = NULL;
08050 
08051   if (!icl_IsValid(get_direct_connect_used_true)) {
08052     get_direct_connect_used_true
08053       = icl_NewTermFromData("get_direct_connect_used(true)",29);
08054     get_direct_connect_used_false
08055       = icl_NewTermFromData("get_direct_connect_used(false)",30);
08056   }
08057 
08058   // if we have an address, we must be trying to use direct_connect...
08059   // ...add the connection_id to post_params, if a direct_connection
08060   // is really available. This allows "fail-over" to a "regular"
08061   // oaa_Solve() if d_c is not set up
08062   if((SingleAgentAddress != NULL) &&
08063      ensure_direct_connection(SingleAgentAddress, &ConnectionId)) {
08064     direct_connect_used = TRUE;
08065     icl_AddToList(global_params, icl_CopyTerm(SingleAgentAddress), FALSE);
08066     conn_id = icl_NewStruct("connection_id", 1, icl_NewStr(ConnectionId));
08067     icl_AddToList(post_params, conn_id, FALSE);
08068     // TODO: ALA add timeout check for direct connect
08069   }
08070   t1 = icl_NewStruct("ev_solve", 3,
08071                      icl_CopyTerm(goal_id),
08072                      icl_CopyTerm(goal),
08073                      icl_CopyTerm(global_params));
08074 
08075   oaa_PostEvent(t1, post_params);
08076   icl_Free(t1);
08077   /* compound goals may also contain relevant params */
08078   icl_GoalComponents(goal, &tmp1, &tmp2, &params);
08079   icl_append_to_list(params, global_params, &all_params);
08080 
08081   icl_Free(tmp1);
08082   icl_Free(tmp2);
08083   icl_Free(params);
08084 
08085   t1 = icl_NewTermFromData("reply(false)",12);
08086   t2 = icl_NewTermFromData("reply(none)",11);
08087   t3 = icl_NewTermFromData("blocking(false)",15);
08088   /* If delayed reply or no reply OK, suceed immediately */
08089   if (icl_GetParamValue(t1, all_params, NULL) ||
08090       icl_GetParamValue(t2, all_params, NULL) ||
08091       icl_GetParamValue(t3, all_params, NULL)) {
08092 
08093     if (solutions) {
08094       *solutions = icl_CopyTerm(goal);
08095     }
08096     requestees = icl_NewList(NULL);
08097     solvers = icl_NewList(NULL);
08098   }
08099   else {
08100     /* otherwise wait for solutions to return */
08101     ICLTerm *result;
08102     ICLTerm *ev_reply_solved_term;
08103     ev_reply_solved_term = icl_NewStruct("ev_solved", 6,
08104                                          icl_CopyTerm(goal_id),
08105                                          icl_CopyTerm(dummyvar),
08106                                          icl_CopyTerm(dummyvar),
08107                                          icl_CopyTerm(dummyvar),
08108                                          icl_CopyTerm(dummyvar),
08109                                          icl_CopyTerm(dummyvar));
08110     /* Never used */
08111     /* icl_param_arg("priority", icl_CopyTerm(dummyvar), all_params, &p);*/
08112 
08113     /*
08114      * in prolog:
08115      * ev_solved(GoalId, Requestees, Solvers, Goal, SolvedParams, Solutions),
08116      */
08117     if (oaa_poll_until_event(ev_reply_solved_term, &result)) {
08118       if (icl_IsStruct(result) && (icl_Arity(result) == 6)) {
08119         requestees = icl_CopyTerm(icl_NthTerm(result, 2));
08120         solvers = icl_CopyTerm(icl_NthTerm(result, 3));
08121         solved_params = icl_CopyTerm(icl_NthTerm(result, 5));
08122         if(*solutions != NULL) {
08123           icl_Free(*solutions);
08124         }
08125         *solutions = icl_CopyTerm(icl_NthTerm(result, 6));
08126         icl_Free(result);
08127         if (icl_ListLen(*solutions)>0) {
08128           res = TRUE;
08129         }
08130         if (!icl_Unify(global_params, solved_params, NULL)) {
08131           char *debugStr = icl_NewStringFromTerm(solved_params);
08132           printf("%s: %s %s\n  %s: %s\n", "WARNING",
08133                  "Params in solved event don't unify",
08134                  "with original params", "SolvedParams",
08135                  debugStr);
08136           icl_stFree(debugStr);
08137         }
08138       }
08139     }
08140     icl_Free(ev_reply_solved_term);
08141   }
08142   icl_Free(t1); icl_Free(t2); icl_Free(t3);
08143 
08144   if (res) {
08145     /* Return Solvers if requested: */
08146     if (out_params) {
08147       *out_params = icl_CopyTerm(global_params);
08148       t1 = icl_NewStruct("get_satisfiers", 1, icl_CopyTerm(solvers));
08149       icl_replace_param_value(t1, *out_params);
08150       icl_Free(t1);
08151 
08152       /* Return Requestees if requested: */
08153       t1 = icl_NewStruct("get_address", 1, icl_CopyTerm(requestees));
08154       icl_replace_param_value(t1, *out_params);
08155       icl_Free(t1);
08156 
08157       // return direct connect status if requested
08158       if (direct_connect_used) {
08159         icl_replace_param_value(get_direct_connect_used_true,*out_params);
08160       }
08161       else {
08162         icl_replace_param_value(get_direct_connect_used_false,*out_params);
08163       }
08164     }
08165   }
08166   icl_Free(solved_params);
08167   icl_Free(solvers);
08168   icl_Free(requestees);
08169   icl_Free(dummyvar);
08170   icl_Free(all_params);
08171   icl_Free(post_params);
08172   icl_stFree(ConnectionId);
08173   return res;
08174 
08175 } // end of oaa_cont_solve_direct()
08176 
08177 /*
08178  *
08179  */
08180 static int oaa_cont_plan(ICLTerm *goal_id,
08181                          ICLTerm *templateGoal,
08182                          ICLTerm *actualGoal,
08183                          ICLTerm *global_params,
08184                          ICLTerm **solutions,
08185                          ICLTerm **out_params) {
08186   int answer = FALSE;
08187   ICLTerm *result = NULL;
08188   ICLTerm *ev_reply_planned_term = NULL;
08189   ICLTerm *t1 = NULL;
08190   ICLTerm *t2 = NULL;
08191   ICLTerm *t3 = NULL;
08192   ICLTerm *SingleAgentAddress = NULL;
08193 
08194   t1 = icl_NewStruct("ev_plan", 3,
08195                      icl_CopyTerm(goal_id),
08196                      icl_CopyTerm(templateGoal),
08197                      icl_CopyTerm(global_params));
08198   t2 = icl_NewStruct("connection_id", 1, icl_NewStr("parent"));
08199   t3 = icl_NewList(NULL);
08200   icl_AddToList(t3,t2,TRUE);
08201 
08202   oaa_PostEvent(t1, t3);
08203 
08204   ev_reply_planned_term = icl_NewStruct("ev_planned", 4,
08205                                          icl_NewVar("_"),
08206                                          icl_CopyTerm(templateGoal),
08207                                          icl_NewVar("_"),
08208                                          icl_NewVar("_"));
08209 
08210   oaa_poll_until_event(ev_reply_planned_term, &result);
08211 
08212 
08213  if (oaa_get_single_address_from_plan(result, &SingleAgentAddress)) {
08214    answer = oaa_cont_solve_direct(goal_id, actualGoal, SingleAgentAddress, global_params, solutions, out_params);
08215  }
08216  else {
08217    // not suitable for direct connect
08218    answer = oaa_cont_solve_direct(goal_id, actualGoal, NULL, global_params, solutions, out_params);
08219  }
08220 
08221    icl_Free(SingleAgentAddress);
08222    icl_Free(ev_reply_planned_term);
08223    icl_Free(t1);
08224    icl_Free(t3);
08225    icl_Free(result);
08226 
08227    return answer;
08228 
08229 } // end of oaa_cont_plan
08230 
08241 EXPORT_MSCPP
08242 int EXPORT_BORLAND
08243 oaa_Disconnect(char* ConnectionId, ICLTerm *Params) {
08244   // next line is used to eliminate a gcc compile
08245   // warning on Linux...warnings are now treated as errors
08246   (void)Params;
08247 
08248   return com_Disconnect(ConnectionId);
08249 } // end of oaa_Disconnect
08250 
08251 /*
08252  *
08253  */
08254 static int oaa_get_single_address_from_plan(ICLTerm *ev_planned_term,
08255                                             ICLTerm **SingleAgentAddress) {
08256   ICLTerm *AgentAddressList = icl_NthTerm(icl_NthTerm(ev_planned_term, 4), 1);
08257   int answer = FALSE;
08258   *SingleAgentAddress = NULL;
08259 
08260   if (AgentAddressList != NULL &&
08261       icl_IsList(AgentAddressList) &&
08262       icl_ListLen(AgentAddressList) == 1) {
08263     *SingleAgentAddress = icl_CopyTerm(icl_NthTerm(AgentAddressList, 1));
08264     answer = TRUE;
08265     if(!icl_IsValid(ev_planned_term) ||
08266        !icl_IsValid(AgentAddressList) ||
08267        !icl_IsValid(*SingleAgentAddress)) {
08268       ev_planned_term = NULL;
08269       ev_planned_term->magic_cookie = 0;
08270     }
08271   }
08272 
08273   return answer;
08274 
08275 } // end of oaa_get_single_address_from_plan
08276 
08277 
08278 /*
08279  *
08280  */
08281 static int oaa_handshake(char *ConnectionId, char *InitialAgentName, ICLTerm *Params) {
08282   int isClient = TRUE;
08283   ICLTerm *ConnEvent = NULL;
08284   ICLTerm *EventTerm = NULL;
08285   ICLTerm* agent_name_cmdline = NULL;
08286   ICLTerm *myId = NULL;
08287   ICLTerm *t1   = NULL;
08288   char *AgentName = NULL;
08289   char     buf[1000];
08290   int result = TRUE;
08291   ICLTerm* usePassword = NULL;
08292   ICLTerm* passwordTerm = NULL;
08293   char* password = NULL;
08294   ICLTerm* reconnectMatcher = icl_NewStruct("reconnect", 1, icl_NewVar("true"));
08295   int isReconnect = FALSE;
08296   (void)Params;
08297 
08298   memset(buf, 0, 1000);
08299 
08300   /* Creates oaa_saved_events */
08301   if (oaa_saved_events==NULL) {
08302     oaa_saved_events = icl_NewList(NULL);
08303   }
08304 
08305   /* Determine whether connection is server or client type */
08306   isClient = isClientConnection(ConnectionId);
08307   isReconnect = icl_Member(reconnectMatcher, Params, NULL);
08308   icl_Free(reconnectMatcher);
08309 
08310   /* Uses the command line info to figure out wether the
08311      agent's name should be changed
08312   */
08313   oaa_ResolveVariable("-oaa_name", &agent_name_cmdline);
08314   if(agent_name_cmdline) {
08315     AgentName = icl_NewStringFromTerm(agent_name_cmdline);
08316   }
08317   else {
08318     AgentName = strdup(InitialAgentName);
08319   }
08320 
08321   icl_stFixQuotes(AgentName); //icl_stRemovesQuotes() is deprecated...
08322 
08323   com_AddInfo(ConnectionId,
08324         (t1 = icl_NewStruct("oaa_name",
08325           1,
08326           icl_NewStr(AgentName))));
08327   icl_Free(t1);
08328 
08329   if (isClient) {   /* CLIENT AGENT */
08330     ICLTerm* ev_connect;
08331     /* Makes sure the local database has been created */
08332     if(!db_IsValid(local_db))
08333       local_db = db_NewDB();
08334 
08335     oaa_ResolveVariable("use_password", &usePassword);
08336 
08337     if(usePassword != NULL) {
08338       if(icl_IsStr(usePassword) && 
08339          (strlen(icl_Str(usePassword)) == 4) &&
08340          (strncmp(icl_Str(usePassword), "true", 4) == 0)) {
08341         oaa_ResolveVariable("client_password", &passwordTerm);
08342         if(passwordTerm != NULL) {
08343           password = icl_NewStringFromTerm(passwordTerm);
08344         }
08345         else {
08346           password = strdup("_");
08347         }
08348       }
08349     }
08350 
08351     /* Handshaking with Facilitator -- exchange information...
08352      *  note: for this first communication, no format is defined for the
08353      *  connection, so it will be sent using default (ascii) format.
08354      *  Information coming back from Facilitator will update the
08355      *  format() field for the connection, possibly improving future
08356      *  communication (if the comm library support it -- libcom_tcp doesn't.
08357      */
08358 
08359     if(password != NULL) {
08360       sprintf(buf, "event(ev_connect([other_name('%s'),"
08361               "other_language(c),other_type(client),"
08362               "other_version(%s),password(%s)]),[])",
08363               AgentName, oaa_library_version_str, password);
08364       icl_stFree(password);
08365     }
08366     else {
08367       sprintf(buf, "event(ev_connect([other_name('%s'),"
08368               "other_language(c),other_type(client),"
08369               "other_version(%s)]),[])",
08370               AgentName, oaa_library_version_str);
08371     }
08372     ev_connect = icl_NewTermFromString(buf);
08373     if(isReconnect) {
08374       ICLTerm* connectParams = icl_NthTerm(icl_NthTerm(ev_connect, 1), 1);
08375       ICLTerm* reconnectTerm;
08376       ICLTerm* nameTerm;
08377       ICLTerm* addressTerm;
08378       ICLTerm* reconnectMatcher = icl_NewStruct("reconnect", 1, icl_NewVar("_"));
08379       ICLTerm* nameMatcher = icl_NewStruct("other_name", 1, icl_NewVar("_"));
08380       ICLTerm* addressMatcher = icl_NewStruct("other_address", 1, icl_NewVar("_"));
08381       if(!icl_Member(reconnectMatcher, Params, &reconnectTerm)) {
08382         fprintf(stderr, "Reconnecting handshake requires reconnect(_) in Params, but none found");
08383       }
08384       else {
08385         icl_AddToList(connectParams, reconnectTerm, FALSE);
08386       }
08387       if(!icl_Member(nameMatcher, Params, &nameTerm)) {
08388         fprintf(stderr, "Reconnecting handshake requires other_name(_) in Params, but none found");
08389       }
08390       else {
08391         icl_AddToList(connectParams, nameTerm, FALSE);
08392       }
08393       if(!icl_Member(addressMatcher, Params, &addressTerm)) {
08394         fprintf(stderr, "Reconnecting handshake requires other_addres(_) in Params, but none found");
08395       }
08396       else {
08397         icl_AddToList(connectParams, addressTerm, FALSE);
08398       }
08399     }
08400     com_SendTerm(ConnectionId, ev_connect);
08401     icl_Free(ev_connect);
08402 
08403     // Get the connection acknowledgement from the same ConnectionId.
08404     // A timeout of 0.0 means we'll block on this socket.
08405     com_GetEventFromConnection(ConnectionId, 0.0, &EventTerm);
08406 
08407     ConnEvent = icl_NthTerm(icl_NthTerm(EventTerm, 1), 1);
08408     
08409     t1 = icl_NewStruct("ev_connected",
08410                        1,
08411                        icl_NewVar("FacInfoList"));
08412     if(icl_Unify(ConnEvent, t1, NULL)) {
08413       if(icl_IsStruct((icl_NthTerm(ConnEvent, 1)))) {
08414         ICLTerm* resStruct = icl_NthTerm(ConnEvent, 1);
08415         char* functor = icl_Functor(resStruct);
08416         if(functor != NULL) {
08417           if((strlen(functor) == 9) &&
08418              (strncmp(functor, "exception", 9) == 0)) {
08419             char* exceptionData = icl_NewStringFromTerm(icl_NthTerm(resStruct, 1));
08420             fprintf(stderr, "Exception in oaa_handlshake: %s\n", exceptionData);
08421             icl_stFree(exceptionData);
08422             result = FALSE;
08423           }
08424         }
08425       }
08426 
08427       if(result != FALSE) {
08428         com_UpdateInfo(ConnectionId, icl_NthTerm(ConnEvent, 1));
08429       }
08430     }
08431     else {
08432       printf("oaa_handshake no ev_connected\n");
08433       result = FALSE;
08434     }
08435 
08436     icl_Free(t1);
08437     icl_Free(EventTerm);
08438   }
08439   else {    /* FACILITATOR */
08440 
08441     /* Add the agent's name and ID to the connection info
08442      * For a client agent, this is done through handshaking with the
08443      * faciliator.
08444      */
08445     com_AddInfo(ConnectionId,
08446     (t1 = icl_NewStruct("oaa_name",
08447                         1,
08448                         icl_NewStr(AgentName))));
08449     icl_Free(t1);
08450 
08451     /* A Facilitator's ID is always 0.
08452      */
08453     com_AddInfo(ConnectionId,
08454     (t1 = icl_NewStruct("oaa_id", 1, icl_NewInt(0))));
08455     icl_Free(t1);
08456 
08457     result = oaa_PrimaryAddress(&myId);
08458 
08459     /* I didn't do anything about the following comment.  If we ever
08460      * have a Facilitator written in C, this might cause a problem
08461      * and should be looked into...
08462      *
08463      * The fac. records its own agent_data in the same way as its clients'.
08464      * Note that we can't call oaa_add_data_local until after the solvables
08465      * have been declared, and we can't declare solvables until we're
08466      * open - so we have to bootstrap this assertion:
08467      *
08468      * oaa_assertz(agent_data(AgentId, open, [], AgentName), AgentId)
08469      */
08470   }
08471   icl_stFree(agent_name_cmdline);
08472   icl_stFree(AgentName);
08473   return result;
08474 } // end of oaa_handshake
08475 
08482 EXPORT_MSCPP
08483 int EXPORT_BORLAND
08484 oaa_SetupCommunication(char *InitialAgentName) {
08485     ICLTerm *RequestedAddress = NULL;
08486     ICLTerm* var;
08487     char *requestedAddressString;
08488 
08489     var = icl_NewVar("_");
08490     if (!oaa_Connect("parent", var, InitialAgentName, ICL_EMPTY)) {
08491       icl_Free(var);
08492       return FALSE;
08493     }
08494     icl_Free(var);
08495 
08496     oaa_ResolveVariable("oaa_listen", &RequestedAddress);   // setup file
08497     requestedAddressString = getenv("OAA_LISTEN");          // env var
08498     if (requestedAddressString) {
08499         RequestedAddress = icl_NewTermFromString(requestedAddressString);
08500     }
08501     oaa_ResolveVariable("-oaa_listen", &RequestedAddress);  // cmd line
08502 
08503     if (RequestedAddress != NULL) {
08504         if (com_ListenAt("client_listener", NULL, RequestedAddress)) {
08505             char *tmp = icl_NewStringFromTerm(RequestedAddress);
08506             printf("Agent listening at %s\n", tmp);
08507             icl_stFree(tmp);
08508         }
08509         else {
08510             printf("Unable to open a client listener connection;");
08511             printf(" continuing without it\n");
08512         }
08513         icl_Free(RequestedAddress);
08514     }
08515     return TRUE;
08516 } //end of oaa_SetupCommunication
08517 
08518 int oaa_SeqNumLessThan(int a, int b)
08519 {
08520   if(a < b) {
08521     return (b - a) <= (2147483647 / 3);
08522   }
08523   else {
08524     return (a - b) >= ((2147483647 / 3) * 2);
08525   }
08526 }
08527 
08538 int oaa_version_atleast(int major, int minor, int level, ICLTerm* toCheck)
08539 {
08540   int size;
08541   if(!icl_IsList(toCheck)) {
08542     return FALSE;
08543   }
08544 
08545   size = icl_NumTerms(toCheck);
08546   if(size > 0) {
08547     ICLTerm* majorTerm = icl_NthTerm(toCheck, 1);
08548     int majorCheck = icl_Int(majorTerm);
08549     if(majorCheck > major) {
08550       return TRUE;
08551     }
08552     else if(majorCheck < major) {
08553       return FALSE;
08554     }
08555     else if(size > 1) {
08556       ICLTerm* minorTerm = icl_NthTerm(toCheck, 2);
08557       int minorCheck = icl_Int(minorTerm);
08558       if(minorCheck > minor) {
08559         return TRUE;
08560       }
08561       else if(minorCheck < minor) {
08562         return FALSE;
08563       }
08564       else if(size > 2) {
08565         ICLTerm* levelTerm = icl_NthTerm(toCheck, 3);
08566         int levelCheck = icl_Int(levelTerm);
08567         if(levelCheck >= level) {
08568           return TRUE;
08569         }
08570         else {
08571           return FALSE;
08572         }
08573       }
08574     }
08575     else {
08576       return minor < 0;
08577     }
08578   }
08579   return FALSE;
08580 }
08581 
08582 EXPORT_MSCPP
08583 int EXPORT_BORLAND
08584 oaa_SupportsSequenceNumbers(char* connectionId)
08585 {
08586   ICLTerm* otherVersionTerm;
08587   ICLTerm* toMatch = icl_NewStruct("other_version", 1, icl_NewVar("_"));
08588   ICLTerm* versionList;
08589   int result = FALSE;
08590   if(!com_GetInfo(connectionId, toMatch, &otherVersionTerm)) {
08591     goto finally;
08592   }
08593   
08594   versionList = icl_NthTerm(otherVersionTerm, 1);
08595   result = oaa_version_atleast(2, 3, 3, versionList);
08596 
08597 finally:
08598   icl_Free(toMatch);
08599   icl_Free(otherVersionTerm);
08600   return result;
08601 }
08602 
08603 // doxygen content
08604 

Generated on Wed May 23 17:20:12 2007 using doxygen 1.5.2