Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xml_to_soap.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: */
        !             6: 
        !             7: 
        !             8: /*-**********************************************************************
        !             9: * TODO:                                                                 *
        !            10: *  - [SOAP-ENC:position] read sparse arrays (and write?)                *
        !            11: *  - [SOAP-ENC:offset] read partially transmitted arrays  (and write?)  *
        !            12: *  - read "flattened" multi-dimensional arrays. (don't bother writing)  *
        !            13: *                                                                       *
        !            14: * BUGS:                                                                 *
        !            15: *  - does not read schema. thus only knows soap pre-defined types.      *
        !            16: *  - references (probably) do not work. untested.                       *
        !            17: *  - does not expose SOAP-ENV:Header to application at all.             *
        !            18: *  - does not use namespaces correctly, thus:                           *
        !            19: *    - namespaces are hard-coded in comparison tokens                   *
        !            20: *    - if a sender uses another namespace identifer, it will break      *
        !            21: ************************************************************************/
        !            22: 
        !            23: 
        !            24: static const char rcsid[] = "#(@) $Id:";
        !            25: 
        !            26: #ifdef _WIN32
        !            27: #include "xmlrpc_win32.h"
        !            28: #endif
        !            29: #include <string.h>
        !            30: #include <stdlib.h>
        !            31: #include "xml_to_soap.h"
        !            32: #include "base64.h"
        !            33: 
        !            34: /* list of tokens used in vocab */
        !            35: #define TOKEN_ANY                               "xsd:ur-type"
        !            36: #define TOKEN_ARRAY          "SOAP-ENC:Array"
        !            37: #define TOKEN_ARRAY_TYPE     "SOAP-ENC:arrayType"
        !            38: #define TOKEN_BASE64         "SOAP-ENC:base64"
        !            39: #define TOKEN_BOOLEAN        "xsd:boolean"
        !            40: #define TOKEN_DATETIME       "xsd:timeInstant"
        !            41: #define TOKEN_DOUBLE         "xsd:double"
        !            42: #define TOKEN_FLOAT          "xsd:float"
        !            43: #define TOKEN_ID             "id"
        !            44: #define TOKEN_INT            "xsd:int"
        !            45: #define TOKEN_NULL           "xsi:null"
        !            46: #define TOKEN_STRING         "xsd:string"
        !            47: #define TOKEN_STRUCT                    "xsd:struct"
        !            48: #define TOKEN_TYPE           "xsi:type"
        !            49: #define TOKEN_FAULT                     "SOAP-ENV:Fault"
        !            50: #define TOKEN_MUSTUNDERSTAND "SOAP-ENV:mustUnderstand"
        !            51: #define TOKEN_ACTOR                     "SOAP-ENV:actor"
        !            52: #define TOKEN_ACTOR_NEXT                "http://schemas.xmlsoap.org/soap/actor/next"
        !            53: 
        !            54: #define TOKEN_XMLRPC_FAULTCODE   "faultCode"
        !            55: #define TOKEN_XMLRPC_FAULTSTRING "faultString"
        !            56: #define TOKEN_SOAP_FAULTCODE     "faultcode"
        !            57: #define TOKEN_SOAP_FAULTSTRING   "faultstring"
        !            58: #define TOKEN_SOAP_FAULTDETAILS  "details"
        !            59: #define TOKEN_SOAP_FAULTACTOR    "actor"
        !            60: 
        !            61: 
        !            62: /* determine if a string represents a soap type, as used in element names */
        !            63: static inline int is_soap_type(const char* soap_type) {
        !            64:        return(strstr(soap_type, "SOAP-ENC:") || strstr(soap_type, "xsd:")) ? 1 : 0;
        !            65: }
        !            66: 
        !            67: /* utility func to generate a new attribute. possibly should be in xml_element.c?? */
        !            68: static xml_element_attr* new_attr(const char* key, const char* val) {
        !            69:        xml_element_attr* attr = malloc(sizeof(xml_element_attr));
        !            70:        if (attr) {
        !            71:                attr->key = key ? strdup(key) : NULL;
        !            72:                attr->val = val ? strdup(val) : NULL;
        !            73:        }
        !            74:        return attr;
        !            75: }
        !            76: 
        !            77: struct array_info {
        !            78:        char          kids_type[128];
        !            79:        unsigned long size;
        !            80:        /* ... ? */
        !            81: };
        !            82: 
        !            83: 
        !            84: /* parses soap arrayType attribute to generate an array_info structure.
        !            85:  * TODO: should deal with sparse, flattened, & multi-dimensional arrays
        !            86:  */
        !            87: static struct array_info* parse_array_type_info(const char* array_type) {
        !            88:        struct array_info* ai = NULL;
        !            89:        if (array_type) {
        !            90:                ai = (struct array_info*)calloc(1, sizeof(struct array_info));
        !            91:                if (ai) {
        !            92:                        char buf[128], *p;
        !            93:                        snprintf(buf, sizeof(buf), "%s", array_type);
        !            94:                        p = strchr(buf, '[');
        !            95:                        if (p) {
        !            96:                                *p = 0;
        !            97:                        }
        !            98:                        strcpy(ai->kids_type, buf);
        !            99:                }
        !           100:        }
        !           101:        return ai;
        !           102: }
        !           103: 
        !           104: /* performs heuristics on an xmlrpc_vector_array to determine
        !           105:  * appropriate soap arrayType string.
        !           106:  */
        !           107: static const char* get_array_soap_type(XMLRPC_VALUE node) {
        !           108:        XMLRPC_VALUE_TYPE_EASY type = xmlrpc_type_none;
        !           109: 
        !           110:        XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
        !           111:        int loopCount = 0;
        !           112:        const char* soapType = TOKEN_ANY;
        !           113: 
        !           114:        type = XMLRPC_GetValueTypeEasy(xIter);
        !           115:        xIter = XMLRPC_VectorNext(node);
        !           116: 
        !           117:        while (xIter) {
        !           118:                /* 50 seems like a decent # of loops.  That will likely
        !           119:                 * cover most cases.  Any more and we start to sacrifice
        !           120:                 * performance.
        !           121:                 */
        !           122:                if ( (XMLRPC_GetValueTypeEasy(xIter) != type) || loopCount >= 50) {
        !           123:                        type = xmlrpc_type_none;
        !           124:                        break;
        !           125:                }
        !           126:                loopCount ++;
        !           127: 
        !           128:                xIter = XMLRPC_VectorNext(node);
        !           129:        }
        !           130:        switch (type) {
        !           131:        case xmlrpc_type_none:
        !           132:                soapType = TOKEN_ANY;
        !           133:                break;
        !           134:        case xmlrpc_type_empty:
        !           135:                soapType = TOKEN_NULL;
        !           136:                break;
        !           137:        case xmlrpc_type_int:
        !           138:                soapType = TOKEN_INT;
        !           139:                break;
        !           140:        case xmlrpc_type_double:
        !           141:                soapType = TOKEN_DOUBLE;
        !           142:                break;
        !           143:        case xmlrpc_type_boolean:
        !           144:                soapType = TOKEN_BOOLEAN;
        !           145:                break;
        !           146:        case xmlrpc_type_string:
        !           147:                soapType = TOKEN_STRING;
        !           148:                break;
        !           149:        case xmlrpc_type_base64:
        !           150:                soapType = TOKEN_BASE64;
        !           151:                break;
        !           152:        case xmlrpc_type_datetime:
        !           153:                soapType = TOKEN_DATETIME;
        !           154:                break;
        !           155:        case xmlrpc_type_struct:
        !           156:                soapType = TOKEN_STRUCT;
        !           157:                break;
        !           158:        case xmlrpc_type_array:
        !           159:                soapType = TOKEN_ARRAY;
        !           160:                break;
        !           161:        case xmlrpc_type_mixed:
        !           162:                soapType = TOKEN_STRUCT;
        !           163:                break;
        !           164:        }
        !           165:        return soapType;
        !           166: }
        !           167: 
        !           168: /* determines whether a node is a fault or not, and of which type:
        !           169:  * 0 = not a fault,
        !           170:  * 1 = xmlrpc style fault
        !           171:  * 2 = soap style fault.
        !           172:  */
        !           173: static inline int get_fault_type(XMLRPC_VALUE node) {
        !           174:        if (XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTCODE) &&
        !           175:                 XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTSTRING)) {
        !           176:                return 1;
        !           177:        }
        !           178:        else if (XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTCODE) &&
        !           179:                                XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTSTRING)) {
        !           180:                return 2;
        !           181:        }
        !           182:        return 0;
        !           183: }
        !           184: 
        !           185: /* input: an XMLRPC_VALUE representing a fault struct in xml-rpc style.
        !           186:  * output: an XMLRPC_VALUE representing a fault struct in soap style,
        !           187:  *  with xmlrpc codes mapped to soap codes, and all other values preserved.
        !           188:  *  note that the returned value is a completely new value, and must be freed.
        !           189:  *  the input value is untouched.
        !           190:  */
        !           191: static XMLRPC_VALUE gen_fault_xmlrpc(XMLRPC_VALUE node, xml_element* el_target) {
        !           192:        XMLRPC_VALUE xDup = XMLRPC_DupValueNew(node);
        !           193:        XMLRPC_VALUE xCode = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTCODE);
        !           194:        XMLRPC_VALUE xStr = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTSTRING);
        !           195: 
        !           196:        XMLRPC_SetValueID(xCode, TOKEN_SOAP_FAULTCODE, 0);
        !           197:        XMLRPC_SetValueID(xStr, TOKEN_SOAP_FAULTSTRING, 0);
        !           198: 
        !           199:        /* rough mapping of xmlrpc fault codes to soap codes */
        !           200:        switch (XMLRPC_GetValueInt(xCode)) {
        !           201:        case -32700:              /* "parse error. not well formed", */
        !           202:        case -32701:              /* "parse error. unsupported encoding" */
        !           203:        case -32702:              /* "parse error. invalid character for encoding" */
        !           204:        case -32600:              /* "server error. invalid xml-rpc.  not conforming to spec." */
        !           205:        case -32601:              /* "server error. requested method not found" */
        !           206:        case -32602:              /* "server error. invalid method parameters" */
        !           207:                XMLRPC_SetValueString(xCode, "SOAP-ENV:Client", 0);
        !           208:                break;
        !           209:        case -32603:              /* "server error. internal xml-rpc error" */
        !           210:        case -32500:              /* "application error" */
        !           211:        case -32400:              /* "system error" */
        !           212:        case -32300:              /* "transport error */
        !           213:                XMLRPC_SetValueString(xCode, "SOAP-ENV:Server", 0);
        !           214:                break;
        !           215:        }
        !           216:        return xDup;
        !           217: }
        !           218: 
        !           219: /* returns a new XMLRPC_VALUE representing a soap fault, comprised of a struct with four keys. */
        !           220: static XMLRPC_VALUE gen_soap_fault(const char* fault_code, const char* fault_string, 
        !           221:                                                                                          const char* actor, const char* details) {
        !           222:        XMLRPC_VALUE xReturn = XMLRPC_CreateVector(TOKEN_FAULT, xmlrpc_vector_struct);
        !           223:        XMLRPC_AddValuesToVector(xReturn,
        !           224:                                                                         XMLRPC_CreateValueString(TOKEN_SOAP_FAULTCODE, fault_code, 0),
        !           225:                                                                         XMLRPC_CreateValueString(TOKEN_SOAP_FAULTSTRING, fault_string, 0),
        !           226:                                                                         XMLRPC_CreateValueString(TOKEN_SOAP_FAULTACTOR, actor, 0),
        !           227:                                                                         XMLRPC_CreateValueString(TOKEN_SOAP_FAULTDETAILS, details, 0),
        !           228:                                                                         NULL);
        !           229:        return xReturn;
        !           230: }
        !           231: 
        !           232: /* translates xml soap dom to native data structures. recursive. */
        !           233: XMLRPC_VALUE xml_element_to_SOAP_REQUEST_worker(XMLRPC_REQUEST request, 
        !           234:                                                                                                                                XMLRPC_VALUE xParent,
        !           235:                                                                                                                                struct array_info* parent_array,
        !           236:                                                                                                                                XMLRPC_VALUE xCurrent, 
        !           237:                                                                                                                                xml_element* el, 
        !           238:                                                                                                                                int depth) {
        !           239:        XMLRPC_REQUEST_TYPE rtype = xmlrpc_request_none;
        !           240: 
        !           241:        /* no current element on first call */
        !           242:        if (!xCurrent) {
        !           243:                xCurrent = XMLRPC_CreateValueEmpty();
        !           244:        }
        !           245: 
        !           246:        /* increment recursion depth guage */
        !           247:        depth ++;
        !           248: 
        !           249:        /* safety first. must have a valid element */
        !           250:        if (el && el->name) {
        !           251:                const char* id = NULL;
        !           252:                const char* type = NULL, *arrayType=NULL, *actor = NULL;
        !           253:                xml_element_attr* attr_iter = Q_Head(&el->attrs);
        !           254:                int b_must_understand = 0;
        !           255:                
        !           256:                /* in soap, types may be specified in either element name -or- with xsi:type attribute. */
        !           257:                if (is_soap_type(el->name)) {
        !           258:                        type = el->name;
        !           259:                }
        !           260:                /* if our parent node, by definition a vector, is not an array, then
        !           261:                   our element name must be our key identifier. */
        !           262:                else if (XMLRPC_GetVectorType(xParent) != xmlrpc_vector_array) {
        !           263:                        id = el->name;
        !           264:                        if(!strcmp(id, "item")) {
        !           265:                        }
        !           266:                }
        !           267: 
        !           268:                /* iterate through element attributes, pick out useful stuff. */
        !           269:                while (attr_iter) {
        !           270:                        /* element's type */
        !           271:                        if (!strcmp(attr_iter->key, TOKEN_TYPE)) {
        !           272:                                type = attr_iter->val;
        !           273:                        }
        !           274:                        /* array type */
        !           275:                        else if (!strcmp(attr_iter->key, TOKEN_ARRAY_TYPE)) {
        !           276:                                arrayType = attr_iter->val;
        !           277:                        }
        !           278:                        /* must understand, sometimes present in headers. */
        !           279:                        else if (!strcmp(attr_iter->key, TOKEN_MUSTUNDERSTAND)) {
        !           280:                                b_must_understand = strchr(attr_iter->val, '1') ? 1 : 0;
        !           281:                        }
        !           282:                        /* actor, used in conjuction with must understand. */
        !           283:                        else if (!strcmp(attr_iter->key, TOKEN_ACTOR)) {
        !           284:                                actor = attr_iter->val;
        !           285:                        }
        !           286:                        attr_iter = Q_Next(&el->attrs);
        !           287:                }
        !           288: 
        !           289:                /* check if caller says we must understand something in a header. */
        !           290:                if (b_must_understand) {
        !           291:                        /* is must understand actually indended for us?
        !           292:                           BUG: spec says we should also determine if actor is our URL, but
        !           293:                                we do not have that information. */
        !           294:                        if (!actor || !strcmp(actor, TOKEN_ACTOR_NEXT)) {
        !           295:                                /* TODO: implement callbacks or other mechanism for applications
        !           296:                                   to "understand" these headers. For now, we just bail if we
        !           297:                                   get a mustUnderstand header intended for us. */
        !           298:                                XMLRPC_RequestSetError(request, 
        !           299:                                                                                          gen_soap_fault("SOAP-ENV:MustUnderstand",
        !           300:                                                                                                                                  "SOAP Must Understand Error",
        !           301:                                                                                                                                  "", ""));
        !           302:                                return xCurrent;
        !           303:                        }
        !           304:                }
        !           305: 
        !           306:                /* set id (key) if one was found. */
        !           307:                if (id) {
        !           308:                        XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
        !           309:                }
        !           310: 
        !           311:                /* according to soap spec, 
        !           312:                   depth 1 = Envelope, 2 = Header, Body & Fault, 3 = methodcall or response. */
        !           313:                if (depth == 3) {
        !           314:                        const char* methodname = el->name;
        !           315:                        char* p = NULL;
        !           316: 
        !           317:                        /* BUG: we determine request or response type using presence of "Response" in element name.
        !           318:                           According to spec, this is only recommended, not required. Apparently, implementations
        !           319:                           are supposed to know the type of action based on state, which strikes me as a bit lame.
        !           320:                           Anyway, we don't have that state info, thus we use Response as a heuristic. */
        !           321:                        rtype =
        !           322: #ifdef strcasestr
        !           323:                        strcasestr(el->name, "response") ? xmlrpc_request_response : xmlrpc_request_call;
        !           324: #else
        !           325:                        strstr(el->name, "esponse") ? xmlrpc_request_response : xmlrpc_request_call;
        !           326: #endif
        !           327:                        XMLRPC_RequestSetRequestType(request, rtype);
        !           328: 
        !           329:                        /* Get methodname.  strip xml namespace crap. */
        !           330:                        p = strchr(el->name, ':');
        !           331:                        if (p) {
        !           332:                                methodname = p + 1;
        !           333:                        }
        !           334:                        if (rtype == xmlrpc_request_call) {
        !           335:                                XMLRPC_RequestSetMethodName(request, methodname);
        !           336:                        }
        !           337:                }
        !           338: 
        !           339: 
        !           340:                /* Next, we begin to convert actual values. if no children, then must be a scalar value. */
        !           341:                if (!Q_Size(&el->children)) {
        !           342:                        if (!type && parent_array && parent_array->kids_type[0]) {
        !           343:                                type = parent_array->kids_type;
        !           344:                        }
        !           345:                        if (!type || !strcmp(type, TOKEN_STRING)) {
        !           346:                                XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
        !           347:                        }
        !           348:                        else if (!strcmp(type, TOKEN_INT)) {
        !           349:                                XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
        !           350:                        }
        !           351:                        else if (!strcmp(type, TOKEN_BOOLEAN)) {
        !           352:                                XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
        !           353:                        }
        !           354:                        else if (!strcmp(type, TOKEN_DOUBLE) ||
        !           355:                                                !strcmp(type, TOKEN_FLOAT)) {
        !           356:                                XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
        !           357:                        }
        !           358:                        else if (!strcmp(type, TOKEN_NULL)) {
        !           359:                                /* already an empty val. do nothing. */
        !           360:                        }
        !           361:                        else if (!strcmp(type, TOKEN_DATETIME)) {
        !           362:                                XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
        !           363:                        }
        !           364:                        else if (!strcmp(type, TOKEN_BASE64)) {
        !           365:                                struct buffer_st buf;
        !           366:                                base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
        !           367:                                XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
        !           368:                                buffer_delete(&buf);
        !           369:                        }
        !           370:                }
        !           371:                /* Element has children, thus a vector, or "compound type" in soap-speak. */
        !           372:                else {
        !           373:                        struct array_info* ai = NULL;
        !           374:                        xml_element* iter = (xml_element*)Q_Head(&el->children);
        !           375: 
        !           376:                        if (!type || !strcmp(type, TOKEN_STRUCT)) {
        !           377:                                XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
        !           378:                        }
        !           379:                        else if (!strcmp(type, TOKEN_ARRAY) || arrayType != NULL) {
        !           380:                                /* determine magic associated with soap array type.
        !           381:                                   this is passed down as we recurse, so our children have access to the info. */
        !           382:                                ai = parse_array_type_info(arrayType);  /* alloc'ed ai free'd below. */
        !           383:                                XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
        !           384:                        }
        !           385:                        else {
        !           386:                                /* mixed is probably closest thing we have to compound type. */
        !           387:                                XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
        !           388:                        }
        !           389:                        /* Recurse, adding values as we go.  Check for error during recursion
        !           390:                           and if found, bail.  this short-circuits us out of the recursion. */
        !           391:                        while ( iter && !XMLRPC_RequestGetError(request) ) {
        !           392:                                XMLRPC_VALUE xNext = NULL;
        !           393:                                /* top level elements don't actually represent values, so we just pass the
        !           394:                                   current value along until we are deep enough. */
        !           395:                                if ( depth <= 2 ||
        !           396:                                          (rtype == xmlrpc_request_response && depth <= 3) ) {
        !           397:                                        xml_element_to_SOAP_REQUEST_worker(request, NULL, ai, xCurrent, iter, depth);
        !           398:                                }
        !           399:                                /* ready to do some actual de-serialization. create a new empty value and
        !           400:                                   pass that along to be init'd, then add it to our current vector. */
        !           401:                                else {
        !           402:                                        xNext = XMLRPC_CreateValueEmpty();
        !           403:                                        xml_element_to_SOAP_REQUEST_worker(request, xCurrent, ai, xNext, iter, depth);
        !           404:                                        XMLRPC_AddValueToVector(xCurrent, xNext);
        !           405:                                }
        !           406:                                iter = (xml_element*)Q_Next(&el->children);
        !           407:                        }
        !           408:                        /* cleanup */
        !           409:                        if (ai) {
        !           410:                                free(ai);
        !           411:                        }
        !           412:                }
        !           413:        }
        !           414:        return xCurrent;
        !           415: }
        !           416: 
        !           417: /* Convert soap xml dom to XMLRPC_VALUE, sans request info.  untested. */
        !           418: XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el)
        !           419: {
        !           420:        return xml_element_to_SOAP_REQUEST_worker(NULL, NULL, NULL, NULL, el, 0);
        !           421: }
        !           422: 
        !           423: /* Convert soap xml dom to XMLRPC_REQUEST */
        !           424: XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el)
        !           425: {
        !           426:        if (request) {
        !           427:                return XMLRPC_RequestSetData(request, xml_element_to_SOAP_REQUEST_worker(request, NULL, NULL, NULL, el, 0));
        !           428:        }
        !           429:        return NULL;
        !           430: }
        !           431: 
        !           432: 
        !           433: /* translates data structures to soap/xml. recursive */
        !           434: xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
        !           435: #define BUF_SIZE 128
        !           436:        xml_element* elem_val = NULL;
        !           437:        if (node) {
        !           438:                int bFreeNode = 0;  /* sometimes we may need to free 'node' variable */
        !           439:                char buf[BUF_SIZE];
        !           440:                XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node);
        !           441:                char* pName = NULL, *pAttrType = NULL;
        !           442: 
        !           443:                /* create our return value element */
        !           444:                elem_val = xml_elem_new();
        !           445: 
        !           446:                switch (type) {
        !           447:                case xmlrpc_type_struct:
        !           448:                case xmlrpc_type_mixed:
        !           449:                case xmlrpc_type_array:
        !           450:                        if (type == xmlrpc_type_array) {
        !           451:                                /* array's are _very_ special in soap.
        !           452:                                   TODO: Should handle sparse/partial arrays here. */
        !           453: 
        !           454:                                /* determine soap array type. */
        !           455:                                const char* type = get_array_soap_type(node);
        !           456:                                xml_element_attr* attr_array_type = NULL;
        !           457: 
        !           458:                                /* specify array kids type and array size. */
        !           459:                                snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node));
        !           460:                                attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf);
        !           461: 
        !           462:                                Q_PushTail(&elem_val->attrs, attr_array_type);
        !           463: 
        !           464:                                pAttrType = TOKEN_ARRAY;
        !           465:                        }
        !           466:                        /* check for fault, which is a rather special case. 
        !           467:                           (can't these people design anything consistent/simple/elegant?) */
        !           468:                        else if (type == xmlrpc_type_struct) {
        !           469:                                int fault_type = get_fault_type(node);
        !           470:                                if (fault_type) {
        !           471:                                        if (fault_type == 1) {
        !           472:                                                /* gen fault from xmlrpc style fault codes              
        !           473:                                                    notice that we get a new node, which must be freed herein. */
        !           474:                                                node = gen_fault_xmlrpc(node, elem_val);
        !           475:                                                bFreeNode = 1;
        !           476:                                        }
        !           477:                                        pName = TOKEN_FAULT;
        !           478:                                }
        !           479:                        }
        !           480: 
        !           481:                        {
        !           482:                                /* recurse through sub-elements */
        !           483:                                XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
        !           484:                                while ( xIter ) {
        !           485:                                        xml_element* next_el = SOAP_to_xml_element_worker(request, xIter);
        !           486:                                        if (next_el) {
        !           487:                                                Q_PushTail(&elem_val->children, next_el);
        !           488:                                        }
        !           489:                                        xIter = XMLRPC_VectorNext(node);
        !           490:                                }
        !           491:                        }
        !           492: 
        !           493:                        break;
        !           494: 
        !           495:                        /* handle scalar types */
        !           496:                case xmlrpc_type_empty:
        !           497:                        pAttrType = TOKEN_NULL;
        !           498:                        break;
        !           499:                case xmlrpc_type_string:
        !           500:                        pAttrType = TOKEN_STRING;
        !           501:                        simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
        !           502:                        break;
        !           503:                case xmlrpc_type_int:
        !           504:                        pAttrType = TOKEN_INT;
        !           505:                        snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
        !           506:                        simplestring_add(&elem_val->text, buf);
        !           507:                        break;
        !           508:                case xmlrpc_type_boolean:
        !           509:                        pAttrType = TOKEN_BOOLEAN;
        !           510:                        snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
        !           511:                        simplestring_add(&elem_val->text, buf);
        !           512:                        break;
        !           513:                case xmlrpc_type_double:
        !           514:                        pAttrType = TOKEN_DOUBLE;
        !           515:                        snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
        !           516:                        simplestring_add(&elem_val->text, buf);
        !           517:                        break;
        !           518:                case xmlrpc_type_datetime:
        !           519:                        {
        !           520:                                time_t tt = XMLRPC_GetValueDateTime(node);
        !           521:                                struct tm *tm = localtime (&tt);
        !           522:                                pAttrType = TOKEN_DATETIME;
        !           523:                                if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) {
        !           524:                                        simplestring_add(&elem_val->text, buf);
        !           525:                                }
        !           526:                        }
        !           527:                        break;
        !           528:                case xmlrpc_type_base64:
        !           529:                        {
        !           530:                                struct buffer_st buf;
        !           531:                                pAttrType = TOKEN_BASE64;
        !           532:                                base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
        !           533:                                simplestring_addn(&elem_val->text, buf.data, buf.offset );
        !           534:                                buffer_delete(&buf);
        !           535:                        }
        !           536:                        break;
        !           537:                        break;
        !           538:                default:
        !           539:                        break;
        !           540:                }
        !           541: 
        !           542:                /* determining element's name is a bit tricky, due to soap semantics. */
        !           543:                if (!pName) {
        !           544:                        /* if the value's type is known... */
        !           545:                        if (pAttrType) {
        !           546:                                /* see if it has an id (key). If so, use that as name, and type as an attribute. */
        !           547:                                pName = (char*)XMLRPC_GetValueID(node);
        !           548:                                if (pName) {
        !           549:                                        Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType));
        !           550:                                }
        !           551: 
        !           552:                                /* otherwise, use the type as the name. */
        !           553:                                else {
        !           554:                                        pName = pAttrType;
        !           555:                                }
        !           556:                        }
        !           557:                        /* if the value's type is not known... (a rare case?) */
        !           558:                        else {
        !           559:                                /* see if it has an id (key). otherwise, default to generic "item" */
        !           560:                                pName = (char*)XMLRPC_GetValueID(node);
        !           561:                                if (!pName) {
        !           562:                                        pName = "item";
        !           563:                                }
        !           564:                        }
        !           565:                }
        !           566:                elem_val->name = strdup(pName);
        !           567: 
        !           568:                /* cleanup */
        !           569:                if (bFreeNode) {
        !           570:                        XMLRPC_CleanupValue(node);
        !           571:                }
        !           572:        }
        !           573:        return elem_val;
        !           574: }
        !           575: 
        !           576: /* convert XMLRPC_VALUE to soap xml dom.  untested. */
        !           577: xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node) {
        !           578:        return SOAP_to_xml_element_worker(NULL, node);
        !           579: }
        !           580: 
        !           581: /* convert XMLRPC_REQUEST to soap xml dom. */
        !           582: xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
        !           583:        xml_element* root = xml_elem_new();
        !           584: 
        !           585:        /* safety first. */
        !           586:        if (root) {
        !           587:                xml_element* body = xml_elem_new();
        !           588:                root->name = strdup("SOAP-ENV:Envelope");
        !           589: 
        !           590:                /* silly namespace stuff */
        !           591:                Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"));
        !           592:                Q_PushTail(&root->attrs, new_attr("xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance"));
        !           593:                Q_PushTail(&root->attrs, new_attr("xmlns:xsd", "http://www.w3.org/1999/XMLSchema"));
        !           594:                Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"));
        !           595:                Q_PushTail(&root->attrs, new_attr("xmlns:si", "http://soapinterop.org/xsd"));
        !           596:                Q_PushTail(&root->attrs, new_attr("xmlns:ns6", "http://testuri.org"));
        !           597:                Q_PushTail(&root->attrs, new_attr("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"));
        !           598: 
        !           599:                /* Q_PushHead(&root->attrs, new_attr("xmlns:ks", "http://kitchen.sink.org/soap/everything/under/sun"));
        !           600:                       JUST KIDDING!! :-)  ---->                ------------------------------------------------- */
        !           601: 
        !           602:                if (body) {
        !           603:                        /* go ahead and serialize first... */
        !           604:                        xml_element* el_serialized =  
        !           605:                        SOAP_to_xml_element_worker(request, 
        !           606:                                                                                                XMLRPC_RequestGetData(request));
        !           607: 
        !           608:                        /* check for fault, in which case, there is no intermediate element */
        !           609:                        if (el_serialized && !strcmp(el_serialized->name, TOKEN_FAULT)) {
        !           610:                                Q_PushTail(&body->children, el_serialized);
        !           611:                        }
        !           612:                        /* usual case: not a fault. Add Response element in between. */
        !           613:                        else {
        !           614:                                xml_element* rpc = xml_elem_new();
        !           615: 
        !           616:                                if (rpc) {
        !           617:                                        const char* methodname = XMLRPC_RequestGetMethodName(request);
        !           618:                                        XMLRPC_REQUEST_TYPE rtype = XMLRPC_RequestGetRequestType(request);
        !           619: 
        !           620:                                        /* if we are making a request, we want to use the methodname as is. */
        !           621:                                        if (rtype == xmlrpc_request_call) {
        !           622:                                                if (methodname) {
        !           623:                                                        rpc->name = strdup(methodname);
        !           624:                                                }
        !           625:                                        }
        !           626:                                        /* if it's a response, we append "Response". Also, given xmlrpc-epi
        !           627:                                           API/architecture, it's likely that we don't have a methodname for
        !           628:                                           the response, so we have to check that. */
        !           629:                                        else {
        !           630:                                                char buf[128];
        !           631:                                                snprintf(buf, sizeof(buf), "%s%s", 
        !           632:                                                                        methodname ? methodname : "",
        !           633:                                                                        "Response");
        !           634: 
        !           635:                                                rpc->name = strdup(buf);
        !           636:                                        }
        !           637: 
        !           638:                                        /* add serialized data to method call/response.
        !           639:                                           add method call/response to body element */
        !           640:                                        if (rpc->name) {
        !           641:                                                if(el_serialized) {
        !           642:                                                        if(Q_Size(&el_serialized->children) && rtype == xmlrpc_request_call) {
        !           643:                                                                xml_element* iter = (xml_element*)Q_Head(&el_serialized->children);
        !           644:                                                                while(iter) {
        !           645:                                                                        Q_PushTail(&rpc->children, iter);
        !           646:                                                                        iter = (xml_element*)Q_Next(&el_serialized->children);
        !           647:                                                                }
        !           648:                                                                xml_elem_free_non_recurse(el_serialized);
        !           649:                                                        }
        !           650:                                                        else {
        !           651:                                                                Q_PushTail(&rpc->children, el_serialized);
        !           652:                                                        }
        !           653:                                                }
        !           654: 
        !           655:                                                Q_PushTail(&body->children, rpc);
        !           656:                                        }
        !           657:                                        else {
        !           658:                                                /* no method name?!
        !           659:                                                   TODO: fault here...? */
        !           660:                                        }
        !           661:                                }
        !           662:                        }
        !           663:                        body->name = strdup("SOAP-ENV:Body");
        !           664:                        Q_PushTail(&root->children, body);
        !           665:                }
        !           666:        }
        !           667: 
        !           668:        return root;
        !           669: }
        !           670: 

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