root/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_named_value
  2. check_docs_loaded
  3. describe_method
  4. xi_system_describe_methods_cb
  5. xi_system_list_methods_cb
  6. xi_system_method_signature_cb
  7. xi_system_method_help_cb
  8. xi_register_system_methods
  9. describeValue_worker
  10. xml_element_to_method_description
  11. XMLRPC_IntrospectionCreateDescription
  12. XMLRPC_ServerAddIntrospectionData
  13. XMLRPC_ServerRegisterIntrospectionCallback

   1 /*
   2   This file is part of libXMLRPC - a C library for xml-encoded function calls.
   3 
   4   Author: Dan Libby (dan@libby.com)
   5   Epinions.com may be contacted at feedback@epinions-inc.com
   6 */
   7 
   8 /*
   9   Copyright 2001 Epinions, Inc.
  10 
  11   Subject to the following 3 conditions, Epinions, Inc.  permits you, free
  12   of charge, to (a) use, copy, distribute, modify, perform and display this
  13   software and associated documentation files (the "Software"), and (b)
  14   permit others to whom the Software is furnished to do so as well.
  15 
  16   1) The above copyright notice and this permission notice shall be included
  17   without modification in all copies or substantial portions of the
  18   Software.
  19 
  20   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
  21   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
  22   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
  23   PURPOSE OR NONINFRINGEMENT.
  24 
  25   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
  26   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
  27   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
  28   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH
  29   DAMAGES.
  30 
  31 */
  32 
  33 
  34 /****h* ABOUT/xmlrpc_introspection
  35  * AUTHOR
  36  *   Dan Libby, aka danda  (dan@libby.com)
  37  * HISTORY
  38  *   $Log$
  39  *   Revision 1.4  2003/12/16 21:00:21  sniper
  40  *   Fix some compile warnings (patch by Joe Orton)
  41  *
  42  *   Revision 1.3  2002/07/05 04:43:53  danda
  43  *   merged in updates from SF project.  bring php repository up to date with xmlrpc-epi version 0.51
  44  *
  45  *   Revision 1.9  2001/09/29 21:58:05  danda
  46  *   adding cvs log to history section
  47  *
  48  *   4/10/2001 -- danda -- initial introspection support
  49  * TODO
  50  * NOTES
  51  *******/
  52 
  53 
  54 #ifdef _WIN32
  55 #include "xmlrpc_win32.h"
  56 #endif
  57 #include "queue.h"
  58 #include "xmlrpc.h"
  59 #include "xmlrpc_private.h"
  60 #include "xmlrpc_introspection_private.h"
  61 #include <string.h>
  62 #include <stdlib.h>
  63 #include <stdarg.h>
  64 
  65 
  66 /* forward declarations for static (non public, non api) funcs */
  67 static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
  68 static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
  69 static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
  70 static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
  71 
  72 
  73 /*-**********************************
  74 * Introspection Callbacks (methods) *
  75 ************************************/
  76 
  77 /* iterates through a list of structs and finds the one with key "name" matching
  78  * needle.  slow, would benefit from a struct key hash.
  79  */
  80 static inline XMLRPC_VALUE find_named_value(XMLRPC_VALUE list, const char* needle) {
  81    XMLRPC_VALUE xIter = XMLRPC_VectorRewind(list);
  82    while(xIter) {
  83       const char* name = XMLRPC_VectorGetStringWithID(xIter, xi_token_name);
  84       if(name && !strcmp(name, needle)) {
  85          return xIter;
  86       }
  87       xIter = XMLRPC_VectorNext(list);
  88    }
  89    return NULL;
  90 }
  91 
  92 
  93 /* iterates through docs callbacks and calls any that have not yet been called */
  94 static void check_docs_loaded(XMLRPC_SERVER server, void* userData) {
  95    if(server) {
  96       q_iter qi = Q_Iter_Head_F(&server->docslist);
  97       while( qi ) {
  98          doc_method* dm = Q_Iter_Get_F(qi);
  99          if(dm && !dm->b_called) {
 100             dm->method(server, userData);
 101             dm->b_called = 1;
 102          }
 103          qi = Q_Iter_Next_F(qi);
 104       }
 105    }
 106 }
 107 
 108 
 109 /* utility function for xi_system_describe_methods_cb */
 110 static inline void describe_method(XMLRPC_SERVER server, XMLRPC_VALUE vector, const char* method) {
 111    if(method) {
 112       server_method* sm = find_method(server, method);
 113       if(sm) {
 114          XMLRPC_AddValueToVector(vector, sm->desc);
 115       }
 116    }
 117 }
 118 
 119 
 120 
 121 /* system.describeMethods() callback */
 122 static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
 123    XMLRPC_VALUE xParams = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input));
 124    XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
 125    XMLRPC_VALUE xMethodList = XMLRPC_CreateVector("methodList", xmlrpc_vector_array);
 126    XMLRPC_VALUE xTypeList = NULL;
 127    int bAll = 1;
 128 
 129    /* lazy loading of introspection data */
 130    check_docs_loaded(server, userData);
 131 
 132    xTypeList = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList");
 133 
 134    XMLRPC_AddValueToVector(xResponse, xTypeList);
 135    XMLRPC_AddValueToVector(xResponse, xMethodList);
 136 
 137    /* check if we have any param */
 138    if(xParams) {
 139       /* check if string or vector (1 or n) */
 140       XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(xParams);
 141       if(type == xmlrpc_string) {
 142          /* just one.  spit it out. */
 143          describe_method(server, xMethodList, XMLRPC_GetValueString(xParams));
 144          bAll = 0;
 145       }
 146       else if(type == xmlrpc_vector) {
 147          /* multiple.  spit all out */
 148          XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams);
 149          while(xIter) {
 150             describe_method(server, xMethodList, XMLRPC_GetValueString(xIter));
 151             xIter = XMLRPC_VectorNext(xParams);
 152          }
 153          bAll = 0;
 154       }
 155    }
 156 
 157    /* otherwise, default to sending all methods */
 158    if(bAll) {
 159       q_iter qi = Q_Iter_Head_F(&server->methodlist);
 160       while( qi ) {
 161          server_method* sm = Q_Iter_Get_F(qi);
 162          if(sm) {
 163             XMLRPC_AddValueToVector(xMethodList, sm->desc);
 164          }
 165          qi = Q_Iter_Next_F(qi);
 166       }
 167    }
 168 
 169    return xResponse;
 170 }
 171 
 172 /* this complies with system.listMethods as defined at http://xmlrpc.usefulinc.com/doc/reserved.html */
 173 static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
 174    XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
 175 
 176    q_iter qi = Q_Iter_Head_F(&server->methodlist);
 177    while( qi ) {
 178       server_method* sm = Q_Iter_Get_F(qi);
 179       if(sm) {
 180          XMLRPC_VectorAppendString(xResponse, 0, sm->name, 0);
 181       }
 182       qi = Q_Iter_Next_F(qi);
 183    }
 184    return xResponse;
 185 }
 186 
 187 /* this complies with system.methodSignature as defined at
 188  * http://xmlrpc.usefulinc.com/doc/sysmethodsig.html
 189  */
 190 static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
 191    const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)));
 192    XMLRPC_VALUE xResponse = NULL;
 193 
 194    /* lazy loading of introspection data */
 195    check_docs_loaded(server, userData);
 196 
 197    if(method) {
 198       server_method* sm = find_method(server, method);
 199       if(sm && sm->desc) {
 200          XMLRPC_VALUE xTypesArray = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
 201          XMLRPC_VALUE xIter, xParams, xSig, xSigIter;
 202          const char* type;
 203 
 204          /* array of possible signatures.  */
 205          xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
 206 
 207          /* find first signature */
 208          xSig = XMLRPC_VectorGetValueWithID(sm->desc, xi_token_signatures);
 209          xSigIter = XMLRPC_VectorRewind( xSig );
 210 
 211          /* iterate through sigs */
 212          while(xSigIter) {
 213             /* first type is the return value */
 214             type = XMLRPC_VectorGetStringWithID(XMLRPC_VectorRewind(
 215                                                  XMLRPC_VectorGetValueWithID(xSigIter, xi_token_returns)),
 216                                                 xi_token_type);
 217             XMLRPC_AddValueToVector(xTypesArray,
 218                                     XMLRPC_CreateValueString(NULL,
 219                                                              type ? type : type_to_str(xmlrpc_none, 0),
 220                                     0));
 221 
 222             /* the rest are parameters */
 223             xParams = XMLRPC_VectorGetValueWithID(xSigIter, xi_token_params);
 224             xIter = XMLRPC_VectorRewind(xParams);
 225 
 226             /* iter through params, adding to types array */
 227             while(xIter) {
 228                XMLRPC_AddValueToVector(xTypesArray,
 229                                        XMLRPC_CreateValueString(NULL,
 230                                                                 XMLRPC_VectorGetStringWithID(xIter, xi_token_type),
 231                                                                 0));
 232                xIter = XMLRPC_VectorNext(xParams);
 233             }
 234 
 235             /* add types for this signature */
 236             XMLRPC_AddValueToVector(xResponse, xTypesArray);
 237 
 238             xSigIter = XMLRPC_VectorNext( xSig );
 239          }
 240       }
 241    }
 242 
 243    return xResponse;
 244 }
 245 
 246 /* this complies with system.methodHelp as defined at
 247  * http://xmlrpc.usefulinc.com/doc/sysmethhelp.html
 248  */
 249 static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
 250    const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)));
 251    XMLRPC_VALUE xResponse = NULL;
 252 
 253    /* lazy loading of introspection data */
 254    check_docs_loaded(server, userData);
 255 
 256    if(method) {
 257       server_method* sm = find_method(server, method);
 258       if(sm && sm->desc) {
 259          const char* help = XMLRPC_VectorGetStringWithID(sm->desc, xi_token_purpose);
 260 
 261          /* returns a documentation string, or empty string */
 262          xResponse = XMLRPC_CreateValueString(NULL, help ? help : xi_token_empty, 0);
 263       }
 264    }
 265 
 266    return xResponse;
 267 }
 268 
 269 /*-**************************************
 270 * End Introspection Callbacks (methods) *
 271 ****************************************/
 272 
 273 
 274 /*-************************
 275 * Introspection Utilities *
 276 **************************/
 277 
 278 /* performs registration of introspection methods */
 279 void xi_register_system_methods(XMLRPC_SERVER server) {
 280    XMLRPC_ServerRegisterMethod(server, xi_token_system_list_methods, xi_system_list_methods_cb);
 281    XMLRPC_ServerRegisterMethod(server, xi_token_system_method_help, xi_system_method_help_cb);
 282    XMLRPC_ServerRegisterMethod(server, xi_token_system_method_signature, xi_system_method_signature_cb);
 283    XMLRPC_ServerRegisterMethod(server, xi_token_system_describe_methods, xi_system_describe_methods_cb);
 284 }
 285 
 286 /* describe a value (param, return, type) */
 287 static XMLRPC_VALUE describeValue_worker(const char* type, const char* id, const char* desc, int optional, const char* default_val, XMLRPC_VALUE sub_params) {
 288    XMLRPC_VALUE xParam = NULL;
 289    if(id || desc) {
 290       xParam = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
 291       XMLRPC_VectorAppendString(xParam, xi_token_name, id, 0);
 292       XMLRPC_VectorAppendString(xParam, xi_token_type, type, 0);
 293       XMLRPC_VectorAppendString(xParam, xi_token_description, desc, 0);
 294       if(optional != 2) {
 295          XMLRPC_VectorAppendInt(xParam, xi_token_optional, optional);
 296       }
 297       if(optional == 1 && default_val) {
 298          XMLRPC_VectorAppendString(xParam, xi_token_default, default_val, 0);
 299       }
 300       XMLRPC_AddValueToVector(xParam, sub_params);
 301    }
 302    return xParam;
 303 }
 304 
 305 
 306 /* convert an xml tree conforming to spec <url tbd> to  XMLRPC_VALUE
 307  * suitable for use with XMLRPC_ServerAddIntrospectionData
 308  */
 309 XMLRPC_VALUE xml_element_to_method_description(xml_element* el, XMLRPC_ERROR err) {
 310    XMLRPC_VALUE xReturn = NULL;
 311 
 312    if(el->name) {
 313       const char* name = NULL;
 314       const char* type = NULL;
 315       const char* basetype = NULL;
 316       const char* desc = NULL;
 317       const char* def = NULL;
 318       int optional = 0;
 319       xml_element_attr* attr_iter = Q_Head(&el->attrs);
 320 
 321       /* grab element attributes up front to save redundant while loops */
 322       while(attr_iter) {
 323          if(!strcmp(attr_iter->key, "name")) {
 324             name = attr_iter->val;
 325          }
 326          else if(!strcmp(attr_iter->key, "type")) {
 327             type = attr_iter->val;
 328          }
 329          else if(!strcmp(attr_iter->key, "basetype")) {
 330             basetype = attr_iter->val;
 331          }
 332          else if(!strcmp(attr_iter->key, "desc")) {
 333             desc = attr_iter->val;
 334          }
 335          else if(!strcmp(attr_iter->key, "optional")) {
 336             if(attr_iter->val && !strcmp(attr_iter->val, "yes")) {
 337                optional = 1;
 338             }
 339          }
 340          else if(!strcmp(attr_iter->key, "default")) {
 341             def = attr_iter->val;
 342          }
 343          attr_iter = Q_Next(&el->attrs);
 344       }
 345 
 346       /* value and typeDescription behave about the same */
 347       if(!strcmp(el->name, "value") || !strcmp(el->name, "typeDescription")) {
 348          XMLRPC_VALUE xSubList = NULL;
 349          const char* ptype = !strcmp(el->name, "value") ? type : basetype;
 350          if(ptype) {
 351             if(Q_Size(&el->children) &&
 352                (!strcmp(ptype, "array") || !strcmp(ptype, "struct") || !strcmp(ptype, "mixed"))) {
 353                xSubList = XMLRPC_CreateVector("member", xmlrpc_vector_array);
 354 
 355                if(xSubList) {
 356                   xml_element* elem_iter = Q_Head(&el->children);
 357                   while(elem_iter) {
 358                      XMLRPC_AddValueToVector(xSubList,
 359                                              xml_element_to_method_description(elem_iter, err));
 360                      elem_iter = Q_Next(&el->children);
 361                   }
 362                }
 363             }
 364             xReturn = describeValue_worker(ptype, name, (desc ? desc : (xSubList ? NULL : el->text.str)), optional, def, xSubList);
 365          }
 366       }
 367 
 368       /* these three kids are about equivalent */
 369       else if(!strcmp(el->name, "params") ||
 370               !strcmp(el->name, "returns") ||
 371               !strcmp(el->name, "signature")) {
 372          if(Q_Size(&el->children)) {
 373             xml_element* elem_iter = Q_Head(&el->children);
 374             xReturn = XMLRPC_CreateVector(!strcmp(el->name, "signature") ? NULL : el->name, xmlrpc_vector_struct);
 375 
 376 
 377             while(elem_iter) {
 378                XMLRPC_AddValueToVector(xReturn,
 379                                        xml_element_to_method_description(elem_iter, err));
 380                elem_iter = Q_Next(&el->children);
 381             }
 382          }
 383       }
 384 
 385 
 386       else if(!strcmp(el->name, "methodDescription")) {
 387          xml_element* elem_iter = Q_Head(&el->children);
 388          xReturn = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
 389 
 390          XMLRPC_VectorAppendString(xReturn, xi_token_name, name, 0);
 391 
 392          while(elem_iter) {
 393             XMLRPC_AddValueToVector(xReturn,
 394                                     xml_element_to_method_description(elem_iter, err));
 395             elem_iter = Q_Next(&el->children);
 396          }
 397       }
 398 
 399       /* items are slightly special */
 400       else if(!strcmp(el->name, "item")) {
 401          xReturn = XMLRPC_CreateValueString(name, el->text.str, el->text.len);
 402       }
 403 
 404       /* sure.  we'll let any ol element with children through */
 405       else if(Q_Size(&el->children)) {
 406          xml_element* elem_iter = Q_Head(&el->children);
 407          xReturn = XMLRPC_CreateVector(el->name, xmlrpc_vector_mixed);
 408 
 409          while(elem_iter) {
 410             XMLRPC_AddValueToVector(xReturn,
 411                                     xml_element_to_method_description(elem_iter, err));
 412             elem_iter = Q_Next(&el->children);
 413          }
 414       }
 415 
 416       /* or anything at all really, so long as its got some text.
 417        * no reason being all snotty about a spec, right?
 418        */
 419       else if(el->name && el->text.len) {
 420          xReturn = XMLRPC_CreateValueString(el->name, el->text.str, el->text.len);
 421       }
 422    }
 423 
 424    return xReturn;
 425 }
 426 
 427 /*-****************************
 428 * End Introspection Utilities *
 429 ******************************/
 430 
 431 
 432 
 433 /*-******************
 434 * Introspection API *
 435 ********************/
 436 
 437 
 438 /****f* VALUE/XMLRPC_IntrospectionCreateDescription
 439  * NAME
 440  *   XMLRPC_IntrospectionCreateDescription
 441  * SYNOPSIS
 442  *   XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err)
 443  * FUNCTION
 444  *   converts raw xml describing types and methods into an
 445  *   XMLRPC_VALUE suitable for use with XMLRPC_ServerAddIntrospectionData()
 446  * INPUTS
 447  *   xml - xml data conforming to introspection spec at <url tbd>
 448  *   err - optional pointer to error struct. filled in if error occurs and not NULL.
 449  * RESULT
 450  *   XMLRPC_VALUE - newly created value, or NULL if fatal error.
 451  * BUGS
 452  *   Currently does little or no validation of xml.
 453  *   Only parse errors are currently reported in err, not structural errors.
 454  * SEE ALSO
 455  *   XMLRPC_ServerAddIntrospectionData ()
 456  * SOURCE
 457  */
 458 XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) {
 459    XMLRPC_VALUE xReturn = NULL;
 460    xml_element* root = xml_elem_parse_buf(xml, 0, 0, err ? &err->xml_elem_error : NULL);
 461 
 462    if(root) {
 463       xReturn = xml_element_to_method_description(root, err);
 464 
 465       xml_elem_free(root);
 466    }
 467 
 468    return xReturn;
 469 
 470 }
 471 /*******/
 472 
 473 
 474 /****f* SERVER/XMLRPC_ServerAddIntrospectionData
 475  * NAME
 476  *   XMLRPC_ServerAddIntrospectionData
 477  * SYNOPSIS
 478  *   int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc)
 479  * FUNCTION
 480  *   updates server with additional introspection data
 481  * INPUTS
 482  *   server - target server
 483  *   desc - introspection data, should be a struct generated by
 484  *          XMLRPC_IntrospectionCreateDescription ()
 485  * RESULT
 486  *   int - 1 if success, else 0
 487  * NOTES
 488  *  - function will fail if neither typeList nor methodList key is present in struct.
 489  *  - if method or type already exists, it will be replaced.
 490  *  - desc is never freed by the server.  caller is responsible for cleanup.
 491  * BUGS
 492  *   - horribly slow lookups. prime candidate for hash improvements.
 493  *   - uglier and more complex than I like to see for API functions.
 494  * SEE ALSO
 495  *   XMLRPC_ServerAddIntrospectionData ()
 496  *   XMLRPC_ServerRegisterIntrospectionCallback ()
 497  *   XMLRPC_CleanupValue ()
 498  * SOURCE
 499  */
 500 int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) {
 501    int bSuccess = 0;
 502    if(server && desc) {
 503       XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList");
 504       XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList");
 505       XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList");
 506 
 507       if(xNewMethods) {
 508          XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods);
 509 
 510          while(xMethod) {
 511             const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name);
 512             server_method* sm = find_method(server, name);
 513 
 514             if(sm) {
 515                if(sm->desc) {
 516                   XMLRPC_CleanupValue(sm->desc);
 517                }
 518                sm->desc = XMLRPC_CopyValue(xMethod);
 519                bSuccess = 1;
 520             }
 521 
 522             xMethod = XMLRPC_VectorNext(xNewMethods);
 523          }
 524       }
 525       if(xNewTypes) {
 526          if(!xServerTypes) {
 527             if(!server->xIntrospection) {
 528                server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
 529             }
 530 
 531             XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes);
 532             bSuccess = 1;
 533          }
 534          else {
 535             XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes);
 536             while(xIter) {
 537                /* get rid of old values */
 538                XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name));
 539                if(xPrev) {
 540                   XMLRPC_VectorRemoveValue(xServerTypes, xPrev);
 541                }
 542                XMLRPC_AddValueToVector(xServerTypes, xIter);
 543                bSuccess = 1;
 544                xIter = XMLRPC_VectorNext(xNewTypes);
 545             }
 546          }
 547       }
 548    }
 549    return bSuccess;
 550 }
 551 /*******/
 552 
 553 
 554 /****f* SERVER/XMLRPC_ServerRegisterIntrospectionCallback
 555  * NAME
 556  *   XMLRPC_ServerRegisterIntrospectionCallback
 557  * SYNOPSIS
 558  *   int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb)
 559  * FUNCTION
 560  *   registers a callback for lazy generation of introspection data
 561  * INPUTS
 562  *   server - target server
 563  *   cb - callback that will generate introspection data
 564  * RESULT
 565  *   int - 1 if success, else 0
 566  * NOTES
 567  *   parsing xml and generating introspection data is fairly expensive, thus a
 568  *   server may wish to wait until this data is actually requested before generating
 569  *   it. Any number of callbacks may be registered at any time.  A given callback
 570  *   will only ever be called once, the first time an introspection request is
 571  *   processed after the time of callback registration.
 572  * SEE ALSO
 573  *   XMLRPC_ServerAddIntrospectionData ()
 574  *   XMLRPC_IntrospectionCreateDescription ()
 575  * SOURCE
 576  */
 577 int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) {
 578    int bSuccess = 0;
 579    if(server && cb) {
 580 
 581       doc_method* dm = calloc(1, sizeof(doc_method));
 582 
 583       if(dm) {
 584          dm->method = cb;
 585          dm->b_called = 0;
 586 
 587          if(Q_PushTail(&server->docslist, dm)) {
 588             bSuccess = 1;
 589          }
 590          else {
 591             my_free(dm);
 592          }
 593       }
 594    }
 595    return 0;
 596 }
 597 /*******/
 598 
 599 /*-**********************
 600 * End Introspection API *
 601 ************************/
 602 
 603 
 604 

/* [<][>][^][v][top][bottom][index][help] */