File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / xmlrpc / libxmlrpc / xmlrpc_introspection.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:48:05 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>