Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c, revision 1.1.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>