Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c, revision 1.1
1.1 ! misho 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>