#include "mms_mm7soap.h" /* function to traverse SOAP env:Body extracting useful headers. */ #define dfltstr(e) ((e) ? ((char *)(e)) : "") #define content(n) ((n)->xmlChildrenNode ? dfltstr(((n)->xmlChildrenNode)->content) : dfltstr((n)->content)) static Octstr *parse_time(char *s) { time_t t = time(NULL); Octstr *p = octstr_create(s); int i = 0, secs = 0; octstr_strip_blanks(p); if (s && s[0] != 'P') return p; else i++; while (i < octstr_len(p)) { long n = 0; int ch; if (octstr_get_char(p, i) == 'T') { secs = 1; i++; } i = octstr_parse_long(&n, p, i, 10); if (i < 0) break; ch = octstr_get_char(p, i); i++; switch(ch) { case 'Y': /* years. approx to 365 1/4 days. */ t += (365.25*24*3600*n); break; case 'M': /* month or minutes. approx month = 30 days. */ if (secs) t += n*60; else t += 30*24*3600*n; break; case 'D': t += n*24*3600; break; case 'H': /* hours. */ t += n*3600; break; case 'S': t += n; break; default: break; } } octstr_destroy(p); return date_create_iso(t); } static int parse_header(xmlNodePtr node, List *headers, int *sigparent) { int skip = 0; int tag; char *hname; char *s = NULL; char *nvalue; Octstr *value = NULL, *tmp; if (!node || node->type != XML_ELEMENT_NODE) return -1; /* look at each node in turn, extract meaning. * we ignore some tags: senderidentification, etc because we don't need them. * we are also not strict on syntax (when receiving): we will be on sending! */ hname = (char *)node->name; nvalue = content(node); tmp = octstr_create(hname); tag = mms_string_to_mm7tag(tmp); octstr_destroy(tmp); switch(tag) { case MM7_TAG_CancelReq: case MM7_TAG_CancelRsp: case MM7_TAG_DeliverReq: case MM7_TAG_DeliverRsp: case MM7_TAG_DeliveryReportReq: case MM7_TAG_DeliveryReportRsp: case MM7_TAG_RSErrorRsp: case MM7_TAG_ReadReplyReq: case MM7_TAG_ReadReplyRsp: case MM7_TAG_ReplaceReq: case MM7_TAG_ReplaceRsp: case MM7_TAG_SubmitReq: case MM7_TAG_SubmitRsp: case MM7_TAG_VASPErrorRsp: hname = "MessageType"; value = mms_mm7tag_to_string(tag); break; case MM7_TAG_SenderIdentification: case MM7_TAG_Recipients: skip = 1; break; case MM7_TAG_To: case MM7_TAG_Cc: case MM7_TAG_Bcc: skip = 1; *sigparent = tag; /* We wait for number and stuff below. */ break; case MM7_TAG_Content: if ((s = xmlGetProp(node, "href")) != NULL) { value = octstr_create(s); xmlFree(s); } /* we keep 'cid:' bit. ignore the bit about adaptation. */ break; case MM7_TAG_Number: /* we will not normalise number here, that's for upper level. */ value = octstr_format("%s/TYPE=PLMN", nvalue); /* -- fall through. -- */ case MM7_TAG_RFC2822Address: if (!value) value = octstr_create(nvalue); hname = mms_mm7tag_to_cstr(*sigparent); /* real tag is parent. */ s = xmlGetProp(node, "displayOnly"); if (s && strcasecmp(s, "true") == 0) /* a '-' indicates don't use this to send. */ octstr_insert(value, octstr_imm("- "), 0); else octstr_insert(value, octstr_imm("+ "), 0); if (s) xmlFree(s); break; case MM7_TAG_EarliestDeliveryTime: case MM7_TAG_ExpiryDate: value = parse_time(nvalue); break; case MM7_TAG_ReplyCharging: value = octstr_imm("Requested"); if ((s = xmlGetProp(node, "replyChargingSize")) != NULL) { http_header_add(headers, "replyChargingSize", s); xmlFree(s); } if ((s = xmlGetProp(node, "replyDeadline")) != NULL) { Octstr *t = parse_time(s); http_header_add(headers, "replyDeadline", octstr_get_cstr(t)); xmlFree(s); octstr_destroy(t); } break; default: break; } if (!value) value = octstr_create(nvalue); octstr_strip_blanks(value); if (!skip && tag >= 0) http_header_add(headers, hname, octstr_get_cstr(value)); octstr_destroy(value); return 0; } static int parse_headers(xmlNodePtr start, List *h, int sigparent) { xmlNodePtr x; for (x = start; x; x = x->next) if (x->type != XML_COMMENT_NODE) { parse_header(x, h, &sigparent); parse_headers(x->xmlChildrenNode, h, sigparent); } return 0; } List *parse_soapmsg(Octstr *xml) { xmlDocPtr doc = xmlParseMemory(octstr_get_cstr(xml), octstr_len(xml)); List *h; int s = -1; if (!doc || !doc->xmlChildrenNode) return NULL; h = http_create_empty_headers(); parse_headers(doc->xmlChildrenNode, h, s); /* Free the doc! */ return h; } static void output_rcpt(char *hdr, List *hdrs, Octstr *p) { List *l = http_header_find_all(hdrs, hdr); char x[32]; int i, n; for (i = 0, n = list_len(l), x[0]=0; i < n; i++) { Octstr *h = NULL, *v = NULL; int ch, j; char *y; http_header_get(l, i, &h, &v); if (octstr_str_compare(h, x) != 0) { if (x[0]) octstr_format_append(p, "\n", x); strncpy(x, octstr_get_cstr(h), sizeof x); octstr_format_append(p, "<%S>\n", h); } octstr_destroy(h); ch = octstr_get_char(v, 0); if (ch == '-') y = " displayOnly=\"true\""; else y = ""; j = octstr_case_search(v, octstr_imm("/TYPE=PLMN"),0); if (j > 0) { Octstr *z = octstr_copy(v, 2, j-2); /* skip the initial char that is only for info purposes. */ octstr_format_append(p, "%S\n", y, z); octstr_destroy(z); } else octstr_format_append(p, "%s\n", y, octstr_get_cstr(v) + 2); /* as above... */ octstr_destroy(v); } if (x[0]) /* close it off. */ octstr_format_append(p, "\n", x); http_destroy_headers(l); } #define XMLNSMM7 "http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-3" /* Construct by hand. */ Octstr *headers_to_soapxml(List *hdrs) { Octstr *s = octstr_create("\n"); Octstr *p, *q, *fault, *mtype; int i, n; octstr_append_cstr(s, "\n" "\n"); p = http_header_value(hdrs, octstr_imm("TransactionID")); octstr_format_append(s, "%S\n", XMLNSMM7, p ? p : octstr_imm("none")); if (p) octstr_destroy(p); octstr_append_cstr(s, "\n\n"); fault = http_header_value(hdrs, octstr_imm("Fault")); if (fault) { Octstr *fc = http_header_value(hdrs, octstr_imm("faultcode")); Octstr *fs = http_header_value(hdrs, octstr_imm("faultstring")); octstr_append_cstr(s, "\n"); if (fc) { octstr_format_append(s, "%S\n", fc); octstr_destroy(fc); } if (fs) { octstr_format_append(s, "%S\n", fs); octstr_destroy(fs); } octstr_append_cstr(s, "\n"); } mtype = http_header_value(hdrs, octstr_imm("MessageType")); octstr_format_append(s, "<%S xmlns=\"%s\">\n", mtype, XMLNSMM7); /* Output the details. */ p = http_header_value(hdrs, octstr_imm("MM7Version")); octstr_format_append(s, "%S\n", p); octstr_destroy(p); p = http_header_value(hdrs, octstr_imm("VASPID")); q = http_header_value(hdrs, octstr_imm("VASID")); if (p || q) { octstr_append_cstr(s, "\n"); if (p) octstr_format_append(s, "%S\n", p); if (q) octstr_format_append(s, "%S\n", q); octstr_append_cstr(s, "\n"); if (p) octstr_destroy(p); if (q) octstr_destroy(q); } p = octstr_create(""); output_rcpt("To", hdrs, p); output_rcpt("Cc", hdrs, p); output_rcpt("Bcc", hdrs, p); if (octstr_len(p) > 0) octstr_format_append(s, "\n%S\n", p); octstr_destroy(p); /* cycle through rest of headers. */ for (i = 0, n = list_len(hdrs); i < n; i++) { Octstr *h = NULL, *v = NULL; char *zz; int tag; int skip = 0; http_header_get(hdrs, i, &h, &v); tag = mms_string_to_mm7tag(h); zz = octstr_get_cstr(h); switch(tag) { case MM7_TAG_MessageType: case MM7_TAG_To: case MM7_TAG_Cc: case MM7_TAG_Bcc: case MM7_TAG_Fault: case MM7_TAG_faultstring: case MM7_TAG_faultcode: case MM7_TAG_VASID: case MM7_TAG_VASPID: case MM7_TAG_MM7Version: case MM7_TAG_replyChargingSize: case MM7_TAG_replyDeadline: case MM7_TAG_TransactionID: case MM7_TAG_StatusCode: case MM7_TAG_StatusText: skip = 1; break; case MM7_TAG_Content: octstr_format_append(s, "\n", v); skip = 1; break; case MM7_TAG_ReplyCharging: p = http_header_value(hdrs, octstr_imm("replyChargingSize")); q = http_header_value(hdrs, octstr_imm("replyDeadline")); octstr_append_cstr(s, "\n"); skip = 1; break; case MM7_TAG_Status: p = http_header_value(hdrs, octstr_imm("StatusCode")); q = http_header_value(hdrs, octstr_imm("StatusText")); octstr_append_cstr(s, "\n"); if (p) { octstr_format_append(s, "%S\n", p); octstr_destroy(p); } if (q) { octstr_format_append(s, "%S\n", q); octstr_destroy(q); } octstr_append_cstr(s, "\n"); skip = 1; break; default: break; } if (!skip && h && v) octstr_format_append(s, "<%S>%S\n", h, v, h); if (h) octstr_destroy(h); if (v) octstr_destroy(v); } octstr_format_append(s, "\n", mtype); octstr_destroy(mtype); if (fault) { octstr_append_cstr(s, "\n"); octstr_append_cstr(s, "\n"); octstr_destroy(fault); } octstr_append_cstr(s, "\n"); octstr_append_cstr(s, "\n"); return s; }