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>