只要写一个XML文件,然后用WBXML编码就可以了。下面是一个Sample
<si>
<indication href="http://wap.fractalist.cn/" action="signal-high">
挑战脉动,挑战你我
</indication
</si>
这个XML的DTD定义在http://www.openmobilealliance.org/tech/dtd/si.dtd
WMXML定义在http://www.w3.org/1999/06/NOTE-wbxml-19990624/
编码后作为二进制短消息发送给用户,记得讲tp_udhi设为1就可以了
WBXML编码的代码如下:
#include <map>
#include <vector>
#include <string>
#include <time.h>
#pragma warning(disable : 4267)
#include <StringHelper.h>
#pragma warning(default : 4267)
#include <boost/cstdint.hpp>
#include <sstream>
#include <iomanip>
using boost::uint8_t;
using std::cout;
using std::endl;
using std::setw;
using std::hex;
using std::setfill;
/// <summary>
/// Series of well known constants and static uint8_t values used when encoding
/// a document to WBXML
/// </summary>
class WBXML
{
public:
static const uint8_t CHAR_NULL = 0x00;
static const uint8_t VERSION_1_1 = 0x01;
static const uint8_t VERSION_1_2 = 0x02;
static const uint8_t CHARSET_UTF_8 = 0x6A;
static const uint8_t TAGTOKEN_END = 0x01;
static const uint8_t TOKEN_INLINE_STRING_FOLLOWS = 0x03;
static const uint8_t TOKEN_OPAQUEDATA_FOLLOWS = 0xC3;
static uint8_t setTagTokenIndications(uint8_t token, bool hasAttributes, bool hasContent)
{
if (hasAttributes)
token |= 0xC0;
if (hasContent)
token |= 0x40;
return token;
}
};
/// <summary>
/// Encapsulates the Service Indication WAP Push instruction.
/// Full documentation can be found at http://www.openmobilealliance.org/tech/affiliates/wap/wap-167-serviceind-20010731-a.pdf?doc=wap-167-serviceind-20010731-a.pdf
/// </summary>
class ServiceIndication
{
public:
// Allowed values of the action attribute of the indication tag
enum Action {NotSet = -1, signal_none = 0, signal_low, signal_medium, signal_high, Delete};
// Well known DTD token
static const uint8_t DOCUMENT_DTD_ServiceIndication = 0x05; // ServiceIndication 1.0 Public Identifier
// Tag Tokens
static const uint8_t TAGTOKEN_si = 0x5;
static const uint8_t TAGTOKEN_indication = 0x6;
static const uint8_t TAGTOKEN_info = 0x7;
static const uint8_t TAGTOKEN_item = 0x8;
// Attribute Tokens
static const uint8_t ATTRIBUTESTARTTOKEN_action[5];
static const uint8_t ATTRIBUTESTARTTOKEN_created = 0xA;
static const uint8_t ATTRIBUTESTARTTOKEN_href = 0xB;
static const uint8_t ATTRIBUTESTARTTOKEN_href_http = 0xC; // http://
static const uint8_t ATTRIBUTESTARTTOKEN_href_http_www = 0xD; // http://www.
static const uint8_t ATTRIBUTESTARTTOKEN_href_https = 0xE; // https://
static const uint8_t ATTRIBUTESTARTTOKEN_href_https_www = 0xE; // https://www.
static const uint8_t ATTRIBUTESTARTTOKEN_si_expires = 0x10;
static const uint8_t ATTRIBUTESTARTTOKEN_si_id = 0x11;
static const uint8_t ATTRIBUTESTARTTOKEN_class = 0x12;
// Attribute Value Tokens
static const uint8_t ATTRIBUTEVALUETOKEN_com = 0x85; // .com/
static const uint8_t ATTRIBUTEVALUETOKEN_edu = 0x86; // .edu/
static const uint8_t ATTRIBUTEVALUETOKEN_net = 0x87; // .net/
static const uint8_t ATTRIBUTEVALUETOKEN_org = 0x88; // .org/
private:
static std::map<std::string, uint8_t> m_hrefStartTokens;
static std::map<std::string, uint8_t> m_attributeValueTokens;
static int initializeServiceIndication()
{
m_hrefStartTokens["https://www."] = ATTRIBUTESTARTTOKEN_href_https_www;
m_hrefStartTokens["http://www."] = ATTRIBUTESTARTTOKEN_href_http_www;
m_hrefStartTokens["https://"] = ATTRIBUTESTARTTOKEN_href_https;
m_hrefStartTokens["http://"] = ATTRIBUTESTARTTOKEN_href_http;
m_attributeValueTokens[".com/"] = ATTRIBUTEVALUETOKEN_com;
m_attributeValueTokens[".edu/"] = ATTRIBUTEVALUETOKEN_edu;
m_attributeValueTokens[".net/"] = ATTRIBUTEVALUETOKEN_net;
m_attributeValueTokens[".org/"] = ATTRIBUTEVALUETOKEN_org;
return 0;
}
std::string m_href;
std::string m_text;
time_t m_createdAt;
time_t m_expiresAt;
Action m_action;
public:
ServiceIndication(const std::string & href, const std::string & text, Action action) :
m_href(href), m_text(text), m_action(action)
{
static int __unused = initializeServiceIndication();
}
ServiceIndication(const std::string & href, const std::string & text, time_t createdAt, time_t expiresAt) :
m_href(href), m_text(text), m_action(Action::NotSet), m_createdAt(createdAt), m_expiresAt(expiresAt)
{
}
ServiceIndication(const std::string & href, const std::string & text, time_t createdAt, time_t expiresAt, Action action) :
m_href(href), m_text(text), m_action(action), m_createdAt(createdAt), m_expiresAt(expiresAt)
{
}
/// <summary>
/// Generates a uint8_t array comprising the encoded Service Indication
/// </summary>
/// <returns>The encoded body</returns>
//01 05 6a 00 45 c6 0c 03 77 61 702e6672616374616c6973742e636e0008 01034120574150205075736820
//746f20746865204672616374616c6973742073697465000101
//01 05 6a 00 45 c6 0b 03 68 74 74703a2f2f7761702e6672616374616c6973742e636e0008010341205741
//50205075736820746f20746865204672616374616c6973742073697465000101
std::vector<uint8_t> getWBXMLBytes() const
{
std::vector<uint8_t> vec;
vec.push_back(WBXML::VERSION_1_1);
vec.push_back(DOCUMENT_DTD_ServiceIndication);
vec.push_back(WBXML::CHARSET_UTF_8);
vec.push_back(WBXML::CHAR_NULL);
// start xml doc
vec.push_back(WBXML::SetTagTokenIndications(TAGTOKEN_si, false, true));
vec.push_back(WBXML::SetTagTokenIndications(TAGTOKEN_indication, true , true));
// href attribute
// this attribute has some well known start tokens that
// are contained within a static hashtable. Iterate through
// the table and chose the token.
size_t i = 0;
uint8_t hrefTagToken = ATTRIBUTESTARTTOKEN_href;
for(std::map<std::string, uint8_t>::const_iterator it = m_hrefStartTokens.begin(); it != m_hrefStartTokens.end(); ++it)
{
const std::string & startString = (*it).first;
if(m_href.find(startString) == 0)
{
hrefTagToken = (*it).second;
i = startString.length();
break;
}
}
vec.push_back(hrefTagToken);
writeInlineString(vec, m_href.substr(i));
/*
* Date elements removed as does not seem to be supported
* by all handsets, or I'm doing it incorrectly, or it's a version 1.2
* thing.
// created attrbute
stream.WriteByte(ATTRIBUTESTARTTOKEN_created);
WriteDate(stream, this.CreatedAt);
// si-expires attrbute
stream.WriteByte(ATTRIBUTESTARTTOKEN_si_expires);
WriteDate(stream, this.ExpiresAt);
*/
// action attibute
if (m_action != Action::NotSet)
vec.push_back(getActionToken(m_action));
// close indication element attributes
vec.push_back(WBXML::TAGTOKEN_END);
// text of indication element
writeInlineString(vec, m_text);
// close indication element
vec.push_back(WBXML::TAGTOKEN_END);
// close si element
vec.push_back(WBXML::TAGTOKEN_END);
return vec;
}
private:
/// <summary>
/// Gets the token for the action attribute
/// </summary>
/// <param name="action">Interruption level instruction to the handset</param>
/// <returns>well known uint8_t value for the action attribute</returns>
uint8_t getActionToken(Action action) const
{
return ATTRIBUTESTARTTOKEN_action[(int)action];
}
/// <summary>
/// Encodes an inline string into the stream using UTF8 encoding
/// </summary>
/// <param name="stream">The target stream</param>
/// <param name="text">The text to write</param>
void writeInlineString(std::vector<uint8_t> & vec, const std::string & text) const
{
// indicate that the follow bytes comprise a string
vec.push_back(WBXML::TOKEN_INLINE_STRING_FOLLOWS);
// write character bytes
std::string utf8Text = stringutil::w2utf8(stringutil::a2w(text));
copy(utf8Text.begin(), utf8Text.end(), back_inserter(vec));
// end is indicated by a null uint8_t
vec.push_back(WBXML::CHAR_NULL);
}
/// <summary>
/// Encodes the DateTime to the stream.
/// DateTimes are encoded as Opaque Data with each number in the string represented
/// by its 4-bit binary value
/// eg: 1999-04-30 06:40:00
/// is encoded as 199904300640.
/// Trailing zero values are not included.
/// </summary>
/// <param name="stream">Target stream</param>
/// <param name="date">DateTime to encode</param>
void writeDate(std::vector<uint8_t> & vec, time_t date) const
{
struct tm * gm = gmtime(&date);
uint8_t buffer[7];
buffer[0] = (uint8_t)( (gm->tm_year + 1900) / 100);
buffer[1] = (uint8_t)((gm->tm_year + 1900) % 100);
buffer[2] = (uint8_t)(gm->tm_mon + 1);
buffer[3] = (uint8_t)(gm->tm_mday);
uint8_t dateLength = 4;
if(gm->tm_hour != 0)
{
buffer[4] = (uint8_t)gm->tm_hour;
dateLength = 5;
}
if(gm->tm_min != 0)
{
buffer[5] = (uint8_t)gm->tm_min;
dateLength = 6;
}
if(gm->tm_sec != 0)
{
buffer[6] = (uint8_t)gm->tm_sec;
dateLength = 7;
}
// write to stream
vec.push_back(WBXML::TOKEN_OPAQUEDATA_FOLLOWS);
vec.push_back(dateLength);
copy(buffer, buffer + dateLength, back_inserter(vec));
}
};
const uint8_t ServiceIndication::ATTRIBUTESTARTTOKEN_action[5] = {0x5, 0x6, 0x7, 0x8, 0x9};
std::map<std::string, uint8_t> ServiceIndication::m_hrefStartTokens = std::map<std::string, uint8_t>();
std::map<std::string, uint8_t> ServiceIndication::m_attributeValueTokens = std::map<std::string, uint8_t>();
/// <summary>
/// Well known values used when generating WSP (Wireless Session Protocol) headers
/// </summary>
class WSP
{
public:
static const uint8_t TRANSACTIONID_CONNECTIONLESSWSP = 0x25;
static const uint8_t PDUTYPE_PUSH = 0x06;
static const uint8_t HEADER_CONTENTLENGTH = 0x8D;
static const uint8_t HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[4];
static const uint8_t HEADER_APPLICATIONTYPE = 0xaf;
static const uint8_t HEADER_APPLICATIONTYPE_x_wap_application_id_w2 = 0x82;
static const uint8_t HEADER_PUSHFLAG[2];
};
const uint8_t WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[4] = {0x03,0xAE,0x81,0xEA};
const uint8_t WSP::HEADER_PUSHFLAG[2] = {0xB4, 0x84};
/// <summary>
/// Well known values used when generating a WDP (Wireless Datagram Protocol) header
/// </summary>
class WDP
{
public:
static const uint8_t INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT = 0x05;
};
/// <summary>
/// Encapsulates an SMS WAP Push message
/// </summary>
class PushMessage
{
private:
// Ports for the WDP information element, instructing the handset which
// application to load on receving the message
static const uint8_t WDP_DESTINATIONPORT[2];
static const uint8_t WDP_SOURCEPORT[2];
ServiceIndication serviceIndication;
public:
PushMessage(const std::string & href, const std::string & text) :
serviceIndication(href, text, ServiceIndication::signal_high)
{
}
/// <summary>
/// Generates the body of the SMS message
/// </summary>
/// <returns>uint8_t array</returns>
std::vector<uint8_t> getSMSBytes() const
{
std::vector<uint8_t> vec;
getWDPHeaderBytes(vec);
#ifdef _DEBUG
cout << "getWDPHeaderBytes\n";
for(size_t i = 0; i < vec.size(); ++i)
{
cout << hex << setw(2) << setfill('0') << ((int)vec[i]);
}
cout << "\n" << endl;
size_t start = vec.size();
#endif
getPDUBytes(vec);
#ifdef _DEBUG
cout << "getPDUBytes\n";
for(size_t i = start; i < vec.size(); ++i)
{
cout << hex << setw(2) << setfill('0') << ((int)vec[i]);
}
cout << "\n" << endl;
#endif
return vec;
}
/// <summary>
/// Generates the PDU (Protocol Data Unit) comprising the encoded Service Indication
/// and the WSP (Wireless Session Protocol) headers
/// </summary>
/// <returns>uint8_t array comprising the PDU</returns>
void getPDUBytes(std::vector<uint8_t> & vec) const
{
std::vector<uint8_t> body = serviceIndication.getWBXMLBytes();
std::vector<uint8_t> header = getWSPHeaderBytes((uint8_t)body.size());
#ifdef _DEBUG
cout << "getWSPHeaderBytes\n";
for(size_t i = 0; i < header.size(); ++i)
{
cout << hex << setw(2) << setfill('0') << ((int)header[i]);
}
cout << "\n" << endl;
cout << "serviceIndication.getWBXMLBytes\n";
for(size_t i = 0; i < body.size(); ++i)
{
cout << hex << setw(2) << setfill('0') << ((int)body[i]);
}
cout << "\n" << endl;
#endif
copy(header.begin(), header.end(), back_inserter(vec));
copy(body.begin(), body.end(), back_inserter(vec));
}
/// <summary>
/// Generates the WSP (Wireless Session Protocol) headers with the well known
/// uint8_t values specfic to a Service Indication
/// </summary>
/// <param name="contentLength">the length of the encoded Service Indication</param>
/// <returns>uint8_t array comprising the headers</returns>
//25060a03ae81eaaf828dc1b484
//25060a03ae81eaaf828dc8b484
std::vector<uint8_t> getWSPHeaderBytes(uint8_t contentLength) const
{
std::vector<uint8_t> vec;
vec.push_back(WSP::TRANSACTIONID_CONNECTIONLESSWSP);
vec.push_back(WSP::PDUTYPE_PUSH);
uint8_t headerLength = sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8) / sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[0])
+ sizeof(WSP::HEADER_APPLICATIONTYPE)
+ sizeof(WSP::HEADER_APPLICATIONTYPE_x_wap_application_id_w2)
+ sizeof(WSP::HEADER_CONTENTLENGTH)
+ 1
+ sizeof(WSP::HEADER_PUSHFLAG) / sizeof(WSP::HEADER_PUSHFLAG[0]);
vec.push_back(headerLength);
copy(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8
, WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8 + sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8) / sizeof(WSP::HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[0])
, back_inserter(vec));
vec.push_back(WSP::HEADER_APPLICATIONTYPE);
vec.push_back(WSP::HEADER_APPLICATIONTYPE_x_wap_application_id_w2);
vec.push_back(WSP::HEADER_CONTENTLENGTH);
vec.push_back((uint8_t)(contentLength + 128));
copy(WSP::HEADER_PUSHFLAG
, WSP::HEADER_PUSHFLAG + sizeof(WSP::HEADER_PUSHFLAG) / sizeof(WSP::HEADER_PUSHFLAG[0])
, back_inserter(vec));
return vec;
}
/// <summary>
/// Generates the WDP (Wireless Datagram Protocol) or UDH (User Data Header) for the
/// SMS message. In the case comprising the Application Port information element
/// indicating to the handset which application to start on receipt of the message
/// </summary>
/// <returns>uint8_t array comprising the header</returns>
void getWDPHeaderBytes(std::vector<uint8_t> & vec) const
{
uint8_t headerLength = sizeof(WDP::INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT)
+ 1
+ sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0])
+ sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0]);
vec.push_back(headerLength);
vec.push_back(WDP::INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT);
vec.push_back((uint8_t)(sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0]) + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0])));
copy(WDP_DESTINATIONPORT
, WDP_DESTINATIONPORT + sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0])
, back_inserter(vec));
copy(WDP_SOURCEPORT
, WDP_SOURCEPORT + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0])
, back_inserter(vec));
}
};
const uint8_t PushMessage::WDP_DESTINATIONPORT[] = {0x0b, 0x84};
const uint8_t PushMessage::WDP_SOURCEPORT[] = {0x23, 0xf0};
- 作者: noho 2004年06月17日, 星期四 22:22
你可以使用这个链接引用该篇日志 http://publishblog.blogdriver.com/blog/tb.b?diaryID=204457