?? mms_mm7soap.c
字號:
/*
* Mbuni - Open Source MMS Gateway
*
* MM7/SOAP message encoder/decoder and helper functions
*
* Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com
*
* Paul Bagyenda <bagyenda@dsmagic.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License, with a few exceptions granted (see LICENSE)
*/
#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))
struct MSoapMsg_t {
List *envelope; /* of http headers. */
MIMEEntity *msg; /* XXX - be sure to copy some headers to this from envelope before convert...*/
};
/* We expect ISO formatted time, or interval. */
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') {
struct universaltime tt;
if (date_parse_iso(&tt, p) >= 0)
t = date_convert_universal(&tt);
goto done;
} 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;
}
}
done:
octstr_destroy(p);
return date_format_http(t);
}
static int parse_header(xmlNodePtr node, List *headers, int *sigparent)
{
int skip = 0;
int tag;
char *hname;
unsigned 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_Recipient:
*sigparent = MM7_TAG_To; /* make it a To field. */
break;
case MM7_TAG_To:
case MM7_TAG_Cc:
case MM7_TAG_Bcc:
case MM7_TAG_Sender:
case MM7_TAG_SenderAddress:
skip = 1;
*sigparent = tag; /* We wait for number and stuff below. */
break;
case MM7_TAG_Content:
if ((s = xmlGetProp(node, (unsigned char *)"href")) != NULL) {
value = octstr_create((char *)s);
xmlFree(s);
}
/* we keep 'cid:' bit. ignore the bit about adaptation. */
break;
case MM7_TAG_ShortCode:
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 = (char *)mms_mm7tag_to_cstr(*sigparent); /* real tag is parent. */
s = xmlGetProp(node, (unsigned char *)"displayOnly");
if (s && strcasecmp((char *)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:
case MM7_TAG_TimeStamp:
case MM7_TAG_Date:
value = parse_time(nvalue);
break;
case MM7_TAG_ReplyCharging:
value = octstr_create("Requested");
if ((s = xmlGetProp(node, (unsigned char *)"replyChargingSize")) != NULL) {
http_header_add(headers, "replyChargingSize", (char *)s);
xmlFree(s);
}
if ((s = xmlGetProp(node, (unsigned char *)"replyDeadline")) != NULL) {
Octstr *t = parse_time((char *)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 && hname != NULL) {
http_header_add(headers, hname, octstr_get_cstr(value));
#if 1
info(0, "parse.soap, h=%s, v=%s!", hname, octstr_get_cstr(value));
#endif
}
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;
}
MSoapMsg_t *mm7_parse_soap(List *headers, Octstr *body)
{
MIMEEntity *mime = mime_http_to_entity(headers, body), *start = NULL;
Octstr *xml = NULL, *cloc;
xmlDocPtr doc;
MIMEEntity *msg = NULL;
List *h;
int s = -1;
MSoapMsg_t *smsg = NULL;
if (!mime)
return NULL;
/* Find the start element:
* - either the mime entity is multipart and has start param (or implicitly first element) ...
* - or entity is not multipart, so body is xml
*/
if ((start = mime_multipart_start_elem(mime)) != NULL)
xml = mime_entity_body(start);
else
xml = mime_entity_body(mime);
if (!xml)
goto done;
#if 1
info(0, "XML sent is: %s!", octstr_get_cstr(xml));
#endif
doc = xmlParseMemory(octstr_get_cstr(xml), octstr_len(xml));
if (!doc || !doc->xmlChildrenNode)
goto done;
h = http_create_empty_headers();
parse_headers(doc->xmlChildrenNode, h, s);
xmlFreeDoc(doc);
if (!h)
goto done;
cloc = http_header_value(h, octstr_imm("Content"));
if (cloc) {
/* XXXX only support content that is inline. easy to add external. */
MIMEEntity *c = NULL;
int i, n;
char *loc = octstr_get_cstr(cloc);
if (octstr_case_search(cloc, octstr_imm("cid:"), 0) == 0) /* skip 'cid:' part. */
loc += 4; /* XXX This should always be there, but some MMC don't put it there. */
for (i = 0, n = mime_entity_num_parts(mime); i<n; i++) {
MIMEEntity *x = mime_entity_get_part(mime, i);
List *headers = mime_entity_headers(x);
Octstr *y = headers ? http_header_value(headers, octstr_imm("Content-ID")) : NULL;
char *cid = (y && octstr_get_char(y, 0) == '<') ? octstr_get_cstr(y) + 1 : (y ? octstr_get_cstr(y) : "");
int cid_len = (y && octstr_get_char(y, 0) == '<') ? octstr_len(y) - 2 : (y ? octstr_len(y) : 0);
if (y &&
(strncmp(loc, cid, cid_len) == 0 ||
octstr_compare(y, cloc) == 0)) /* XXX seems wrong, but some MMC out there behave badly, so we support it */
c = mime_entity_duplicate(x);
if (y)
octstr_destroy(y);
http_destroy_headers(headers);
mime_entity_destroy(x);
if (c)
break;
}
if (c)
msg = c; /* this is already a copy. */
octstr_destroy(cloc);
} else {
/* XXX Sigh! Broken MMC don't set this parameter. Lets try to be kind to them! */
int i, n = mime_entity_num_parts(mime);
int found = 0;
for (i = 0; !found && i < n; i++) {
MIMEEntity *x = mime_entity_get_part(mime,i);
List *hx = NULL;
Octstr *xctype = NULL, *xparams = NULL;
if (!x)
goto loop;
hx = mime_entity_headers(x);
get_content_type(hx, &xctype, &xparams);
if (xctype && octstr_case_compare(xctype, octstr_imm("text/xml")) != 0) {
/* Found something that might be the body, since its not XML.
* Perhaps we compare bodies? For broken ones anyway, so no bother!
*/
found = 1;
msg = x;
}
loop:
if (x && !found) mime_entity_destroy(x);
if (hx) http_destroy_headers(hx);
octstr_destroy(xctype);
octstr_destroy(xparams);
}
}
smsg = gw_malloc(sizeof *smsg);
smsg->envelope = h;
smsg->msg = msg;
done:
if (mime)
mime_entity_destroy(mime);
if (start)
mime_entity_destroy(start);
if (xml)
octstr_destroy(xml);
return smsg;
}
static int append_address(Octstr *p, Octstr *addr_spec)
{
Octstr *v = addr_spec;
char *y;
int j, 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, "<mm7:Number%s>%S</mm7:Number>\n", y, z);
octstr_destroy(z);
} else
octstr_format_append(p, "<mm7:RFC2822Address%s>%s</mm7:RFC2822Address>\n",
y, octstr_get_cstr(v) + 2); /* as above... */
return 0;
}
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 = gwlist_len(l), x[0]=0; i < n; i++) {
Octstr *h = NULL, *v = NULL;
http_header_get(l, i, &h, &v);
if (octstr_str_compare(h, x) != 0) {
if (x[0])
octstr_format_append(p, "</mm7:%s>\n", x);
strncpy(x, octstr_get_cstr(h), sizeof x);
octstr_format_append(p, "<mm7:%S>\n", h);
}
octstr_destroy(h);
append_address(p, v); /* put the address in */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -