📄 mms_msg.c
字号:
/*
* Mbuni - Open Source MMS Gateway
*
* MMS 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 <time.h>
#include <ctype.h>
#include "mms_msg.h"
#include "mms_util.h"
struct MmsMsg {
int message_type;
Octstr *msgId;
List *headers; /* Of type HTTPHeader. */
mms_encoding enc;
unsigned char ismultipart;
union {
List *l;
Octstr *s;
} body; /* list of MIMEEntity (for multipart), text otherwise.*/
};
#define SIZHINT 47
static int encode_msgheaders(Octstr *os, List *hdrs);
static int decode_msgheaders(ParseContext *context, List *hdr, Octstr *from, int stop_on_ctype);
static inline void pack_short_integer(Octstr *s, int ch)
{
unsigned long c = ((unsigned)ch)&0x7f;
wsp_pack_short_integer(s, c);
}
#if 0
static void encode_uint(Octstr *os, unsigned int l)
{
char xbuf[5];
int i = 0;
do {
xbuf[i++] = l&0x7f;
l>>=7;
} while (i < 5 && l);
while (--i > 0) {
xbuf[i] |= 0x80;
octstr_append_data(os, &xbuf[i], 1);
}
octstr_append_data(os, &xbuf[0], 1);
}
#endif
int mms_validate_address(Octstr *s)
{
int i = octstr_search_char(s, '/', 0);
int l = octstr_len(s);
if (octstr_search_char(s, '@', 0) > 0)
return 0;
else if (i >= 0)
if (octstr_case_search(s, octstr_imm("PLMN"), 0) + 4 == l ||
octstr_case_search(s, octstr_imm("IPv4"), 0) + 4 == l ||
octstr_case_search(s, octstr_imm("IPv6"), 0) + 4 == l)
return 0;
else
return -1;
else
return -1;
}
static int decode_multipart(ParseContext *context, List *body)
{
int i=0, n;
n = parse_get_uintvar(context);
for (i = 0; i<n && parse_octets_left(context) > 0 ; i++) {
int dlen, hlen;
MIMEEntity *x = mime_entity_create();
List *headers;
Octstr *hs;
Octstr *content;
Octstr *content_type;
hlen = parse_get_uintvar(context);
dlen = parse_get_uintvar(context);
parse_limit(context, hlen);
hs = parse_get_octets(context, parse_octets_left(context));
headers = wsp_headers_unpack(hs, 1);
octstr_destroy(hs);
strip_boundary_element(headers,NULL);
mime_replace_headers(x, headers);
parse_skip_to_limit(context);
parse_pop_limit(context);
content_type = http_header_value(headers, octstr_imm("Content-Type"));
content = parse_get_octets(context, dlen);
http_destroy_headers(headers);
if (!content || !content_type) {
int pleft = parse_octets_left(context);
warning(0, "Parse error reading mime body [hlen=%d, dlen=%d, left=%d]!",
hlen,dlen, pleft);
mime_entity_destroy(x);
if (content_type)
octstr_destroy(content_type);
if (content)
octstr_destroy(content);
return -1;
}
if (octstr_case_compare(content_type,
octstr_imm("application/vnd.wap.multipart.related")) == 0 ||
octstr_case_compare(content_type,
octstr_imm("application/vnd.wap.multipart.alternative")) == 0 ||
octstr_case_compare(content_type,
octstr_imm("application/vnd.wap.multipart.mixed")) == 0) { /* Body is multipart. */
ParseContext *p = parse_context_create(content);
List *ml = gwlist_create();
int res = decode_multipart(p, ml);
parse_context_destroy(p);
if (res == 0) {
/* Put body parts into mime object. */
int j, m = gwlist_len(ml);
for (j = 0; j < m; j++)
mime_entity_add_part(x, gwlist_get(ml,i));
}
gwlist_destroy(ml, (gwlist_item_destructor_t *)mime_entity_destroy);
if (res < 0) {
if (content_type)
octstr_destroy(content_type);
if (content)
octstr_destroy(content);
return -1;
}
} else
mime_entity_set_body(x,content);
octstr_destroy(content);
octstr_destroy(content_type);
gwlist_append(body, x);
}
return 0;
}
static int encode_multipart(Octstr *os, List *body)
{
int i, j, n, m;
n = gwlist_len(body);
octstr_append_uintvar(os, n);
i = 0;
while (i<n) {
Octstr *mhdr, *mbody = octstr_create("");
MIMEEntity *x = gwlist_get(body, i);
List *headers = mime_entity_headers(x);
Octstr *s;
strip_boundary_element(headers,NULL);
mhdr = wsp_headers_pack(headers, 1, WSP_1_3);
http_destroy_headers(headers);
if ((m = mime_entity_num_parts(x)) > 0) { /* This is a multi-part,
* go down further.
*/
List *l = gwlist_create();
for (j = 0; j < m; j++)
gwlist_append(l, mime_entity_get_part(x, j));
encode_multipart(mbody, l);
gwlist_destroy(l, (gwlist_item_destructor_t *)mime_entity_destroy);
} else if ((s = mime_entity_body(x)) != NULL) {
octstr_append(mbody, s);
octstr_destroy(s);
}
octstr_append_uintvar(os, octstr_len(mhdr));
octstr_append_uintvar(os, octstr_len(mbody));
octstr_append(os, mhdr);
octstr_append(os, mbody);
octstr_destroy(mhdr);
octstr_destroy(mbody);
i++;
}
return 0;
}
static int decode_msgbody(ParseContext *context, MmsMsg *msg)
{
int res = 0;
if (msg->ismultipart) {
msg->body.l = gwlist_create();
res = decode_multipart(context, msg->body.l);
} else
msg->body.s = parse_get_rest(context);
return res;
}
static void encode_msgbody(Octstr *os, MmsMsg *msg)
{
if (msg->ismultipart)
encode_multipart(os, msg->body.l);
else
octstr_append(os, msg->body.s);
}
/* If ret < 0 then we need to get a field value, else we use what's passed. */
static Octstr *decode_encoded_string_value(int ret, ParseContext *context, unsigned char *hname)
{
int val;
int ret2;
Octstr *res = NULL;
ret2 = (ret < 0) ? wsp_field_value(context, &val) : ret;
if (ret2 == WSP_FIELD_VALUE_DATA) { /* expect charset text. */
long charset; /* Get it and ignore it. */
wsp_secondary_field_value(context, &charset);
res = parse_get_nul_string(context); /* XXX Currently we ignore charset */
if (ret < 0) {
parse_skip_to_limit(context);
parse_pop_limit(context);
}
} else if (ret2 != WSP_FIELD_VALUE_NUL_STRING) {
warning(0, "Faulty header value for %s! [ret=%d,ret2=%d]\n", hname,ret,ret2);
res = octstr_imm("");
} else
res = parse_get_nul_string(context);
return res;
}
/* Decodes it, adds to 'unpacked' which is the header list.
* returns the first value token got when parsing value --
* useful for unpacking msg type
*/
static int mms_unpack_well_known_field(List *unpacked, int field_type,
ParseContext *context,
Octstr *xfrom, int msgtype)
{
int val, ret;
unsigned char *hname = NULL;
Octstr *decoded = NULL;
unsigned char *ch = NULL;
ret = wsp_field_value(context, &val);
if (parse_error(context)) {
warning(0, "Faulty header [code = %d], skipping remaining headers.", field_type);
parse_skip_to_limit(context);
return -1;
}
hname = mms_header_to_cstr(field_type);
if (ret == WSP_FIELD_VALUE_NUL_STRING)
decoded = parse_get_nul_string(context);
switch (field_type) {
case MMS_HEADER_TO:
case MMS_HEADER_CC:
case MMS_HEADER_BCC:
if (ret == WSP_FIELD_VALUE_DATA)
decoded = decode_encoded_string_value(ret, context, hname);
if (mms_validate_address(decoded))
warning(0, "Faulty address [%s] format in field %s!",
octstr_get_cstr(decoded), hname);
break;
case MMS_HEADER_SUBJECT:
case MMS_HEADER_RETRIEVE_TEXT:
case MMS_HEADER_STORE_STATUS_TEXT:
if (ret == WSP_FIELD_VALUE_DATA)
decoded = decode_encoded_string_value(ret, context, hname);
break;
case MMS_HEADER_RESPONSE_TEXT:
if (msgtype == MMS_MSGTYPE_MBOX_DELETE_REQ &&
ret == WSP_FIELD_VALUE_DATA) {
int ret2;
decoded = wsp_unpack_integer_value(context);
ret2= wsp_field_value(context, &val);
octstr_append(decoded, decode_encoded_string_value(ret2, context, hname));
if (ret2 == WSP_FIELD_VALUE_DATA) { /* we need to skip to end of inner value-data. */
parse_skip_to_limit(context);
parse_pop_limit(context);
}
} else if (ret == WSP_FIELD_VALUE_DATA)
decoded = decode_encoded_string_value(ret, context, hname);
break;
case MMS_HEADER_TRANSACTION_ID:
case MMS_HEADER_MESSAGE_ID:
case MMS_HEADER_REPLY_CHARGING_ID:
if (ret != WSP_FIELD_VALUE_NUL_STRING)
warning(0, "Unexpected field value type %d for header %s\n",
ret, hname);
break;
/* MMS v1.2 mandates slightly different format,
* when used in m-mbox-delete.conf
*/
case MMS_HEADER_CONTENT_LOCATION:
if (ret == WSP_FIELD_VALUE_DATA) {
Octstr *t;
decoded = wsp_unpack_integer_value(context);
t = parse_get_nul_string(context);
octstr_append(decoded, t);
octstr_destroy(t);
} else if (ret != WSP_FIELD_VALUE_NUL_STRING)
warning(0, "Unexpected field value type %d for header %s\n",
ret, hname);
break;
case MMS_HEADER_MMS_VERSION:
if (ret == WSP_FIELD_VALUE_ENCODED)
decoded = wsp_unpack_version_value(val);
break;
/* integer/octet values */
case MMS_HEADER_DELIVERY_REPORT:
case MMS_HEADER_REPORT_ALLOWED:
case MMS_HEADER_READ_REPORT:
case MMS_HEADER_DISTRIBUTION_INDICATOR:
case MMS_HEADER_QUOTAS:
case MMS_HEADER_STORE:
case MMS_HEADER_STORED:
case MMS_HEADER_TOTALS:
ch = mms_reports_to_cstr(val);
break;
case MMS_HEADER_MESSAGE_TYPE:
ch = mms_message_type_to_cstr(val);
break;
case MMS_HEADER_PRIORITY:
ch = mms_priority_to_cstr(val);
break;
case MMS_HEADER_READ_STATUS:
ch = mms_read_status_to_cstr(val);
break;
case MMS_HEADER_REPLY_CHARGING:
ch = mms_reply_charging_to_cstr(val);
break;
case MMS_HEADER_RESPONSE_STATUS:
if (ret == WSP_FIELD_VALUE_DATA) {
unsigned char *x;
int val;
decoded = wsp_unpack_integer_value(context);
wsp_field_value(context, &val);
x = mms_response_status_to_cstr(val|0x80);
octstr_append_cstr(decoded, (char *)x);
} else
ch = mms_response_status_to_cstr(val|0x80);
break;
case MMS_HEADER_RETRIEVE_STATUS:
ch = mms_retrieve_status_to_cstr(val|0x80);
break;
case MMS_HEADER_STATUS:
ch = mms_status_to_cstr(val);
break;
case MMS_HEADER_SENDER_VISIBILITY:
ch = mms_visibility_to_cstr(val);
break;
case MMS_HEADER_MESSAGE_CLASS:
if (ret != WSP_FIELD_VALUE_NUL_STRING)
ch = mms_message_class_to_cstr(val);
break;
case MMS_HEADER_DATE: /* Date values. */
parse_skip(context, -1);
decoded = wsp_unpack_date_value(context);
break;
case MMS_HEADER_MESSAGE_SIZE:
case MMS_HEADER_REPLY_CHARGING_SIZE:
case MMS_HEADER_START:
case MMS_HEADER_LIMIT:
case MMS_HEADER_MESSAGE_COUNT:
parse_skip(context, -1);
decoded = wsp_unpack_integer_value(context);
break;
case MMS_HEADER_CONTENT_TYPE:
if (ret == WSP_FIELD_VALUE_ENCODED)
ch = wsp_content_type_to_cstr(val);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -