/* this complies with system.methodSignature as defined at * http://xmlrpc.usefulinc.com/doc/sysmethodsig.html */ static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input))); XMLRPC_VALUE xResponse = NULL; /* lazy loading of introspection data */ check_docs_loaded(server, userData); if(method) { server_method* sm = find_method(server, method); if(sm && sm->desc) { XMLRPC_VALUE xTypesArray = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); XMLRPC_VALUE xIter, xParams, xSig, xSigIter; const char* type; /* array of possible signatures. */ xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array); /* find first signature */ xSig = XMLRPC_VectorGetValueWithID(sm->desc, xi_token_signatures); xSigIter = XMLRPC_VectorRewind( xSig ); /* iterate through sigs */ while(xSigIter) { /* first type is the return value */ type = XMLRPC_VectorGetStringWithID(XMLRPC_VectorRewind( XMLRPC_VectorGetValueWithID(xSigIter, xi_token_returns)), xi_token_type); XMLRPC_AddValueToVector(xTypesArray, XMLRPC_CreateValueString(NULL, type ? type : type_to_str(xmlrpc_none, 0), 0)); /* the rest are parameters */ xParams = XMLRPC_VectorGetValueWithID(xSigIter, xi_token_params); xIter = XMLRPC_VectorRewind(xParams); /* iter through params, adding to types array */ while(xIter) { XMLRPC_AddValueToVector(xTypesArray, XMLRPC_CreateValueString(NULL, XMLRPC_VectorGetStringWithID(xIter, xi_token_type), 0)); xIter = XMLRPC_VectorNext(xParams); } /* add types for this signature */ XMLRPC_AddValueToVector(xResponse, xTypesArray); xSigIter = XMLRPC_VectorNext( xSig ); } } } return xResponse; }
/****f* SERVER/XMLRPC_ServerAddIntrospectionData * NAME * XMLRPC_ServerAddIntrospectionData * SYNOPSIS * int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) * FUNCTION * updates server with additional introspection data * INPUTS * server - target server * desc - introspection data, should be a struct generated by * XMLRPC_IntrospectionCreateDescription () * RESULT * int - 1 if success, else 0 * NOTES * - function will fail if neither typeList nor methodList key is present in struct. * - if method or type already exists, it will be replaced. * - desc is never freed by the server. caller is responsible for cleanup. * BUGS * - horribly slow lookups. prime candidate for hash improvements. * - uglier and more complex than I like to see for API functions. * SEE ALSO * XMLRPC_ServerAddIntrospectionData () * XMLRPC_ServerRegisterIntrospectionCallback () * XMLRPC_CleanupValue () * SOURCE */ int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) { int bSuccess = 0; if(server && desc) { XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList"); XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList"); XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); if(xNewMethods) { XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods); while(xMethod) { const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name); server_method* sm = find_method(server, name); if(sm) { if(sm->desc) { XMLRPC_CleanupValue(sm->desc); } sm->desc = XMLRPC_CopyValue(xMethod); bSuccess = 1; } xMethod = XMLRPC_VectorNext(xNewMethods); } } if(xNewTypes) { if(!xServerTypes) { if(!server->xIntrospection) { server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); } XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes); bSuccess = 1; } else { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes); while(xIter) { /* get rid of old values */ XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name)); if(xPrev) { XMLRPC_VectorRemoveValue(xServerTypes, xPrev); } XMLRPC_AddValueToVector(xServerTypes, xIter); bSuccess = 1; xIter = XMLRPC_VectorNext(xNewTypes); } } } } return bSuccess; }
XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)); XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_array); if (xArray) { XMLRPC_VALUE xMethodIter = XMLRPC_VectorRewind(xArray); while (xMethodIter) { XMLRPC_REQUEST request = XMLRPC_RequestNew(); if(request) { const char* methodName = XMLRPC_VectorGetStringWithID(xMethodIter, "methodName"); XMLRPC_VALUE params = XMLRPC_VectorGetValueWithID(xMethodIter, "params"); if(methodName && params) { XMLRPC_VALUE xRandomArray = XMLRPC_CreateVector(0, xmlrpc_vector_array); XMLRPC_RequestSetMethodName(request, methodName); XMLRPC_RequestSetData(request, params); XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); XMLRPC_AddValueToVector(xRandomArray, XMLRPC_ServerCallMethod(server, request, userData)); XMLRPC_AddValueToVector(xReturn, xRandomArray); } XMLRPC_RequestFree(request, 1); } xMethodIter = XMLRPC_VectorNext(xArray); } } return xReturn; }
/* iterates through a list of structs and finds the one with key "name" matching * needle. slow, would benefit from a struct key hash. */ static inline XMLRPC_VALUE find_named_value(XMLRPC_VALUE list, const char* needle) { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(list); while(xIter) { const char* name = XMLRPC_VectorGetStringWithID(xIter, xi_token_name); if(name && !strcmp(name, needle)) { return xIter; } xIter = XMLRPC_VectorNext(list); } return NULL; }
/* this complies with system.methodHelp as defined at * http://xmlrpc.usefulinc.com/doc/sysmethhelp.html */ static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) { const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input))); XMLRPC_VALUE xResponse = NULL; /* lazy loading of introspection data */ check_docs_loaded(server, userData); if(method) { server_method* sm = find_method(server, method); if(sm && sm->desc) { const char* help = XMLRPC_VectorGetStringWithID(sm->desc, xi_token_purpose); /* returns a documentation string, or empty string */ xResponse = XMLRPC_CreateValueString(NULL, help ? help : xi_token_empty, 0); } } return xResponse; }