您的位置:首页 > 其它

支持smil文件的MMS PDU打包方式.

2007-06-29 15:00 363 查看
mms如果不支持smil那就不能叫真正的MMS,mixed的格式对于多个附件的MMS来说不仅没有"排版"功能,
而且即使用你想一个文件一个文件"拆单了看",也不得不看一次手工播放一次,就象要手动"翻页".所以不支持
smil干脆就别玩MMS了.
但基于related格式的支持smil的PDU打包方式怎么也搜索不到,很多厂商和技术人员都故作神秘,不就是一
堆规范的实现吗?只好下了几个文档来研究,经过反复调试,其中用nowSMS的mmscomp打包出来的格式竟然
是错误的,最后多次抓包比较,总算成功了.在『别人原来的mixed方式』的基础上修改成related方式的.有需要的
就自己用去吧.(注意基础类是别人原来提供的,我只是提供了related方式的打包逻辑)
工程文件在:http://dl2.csdn.net/down4/20070706/06201955542.rar

using System;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Collections;
using System.Text;
/// <summary>
/// Lib 的摘要说明
/// </summary>

namespace MMSLib
{

public class MMessage
{
string subject = "测试";
int deliverTime = 0; // 多少秒以后开始投递
ArrayList inlineFiles = new ArrayList(); // 文件列表
ArrayList destinations = new ArrayList(); // 目标号码

static long serialNumber = 19700311L; // 流水号
FileInfo smilFile;

public void SetSubject(string subject)
{
this.subject = subject;
}
public void SetDeliverTime(int deliverTime)
{
this.deliverTime = deliverTime;
}
//
public void AddTo(string dest)
{
destinations.Add(dest);
}

public void AddFile(string file)
{

if (file.ToLower().EndsWith(".smil"))
{
if (this.smilFile != null)
throw new Exception("The smil file has existed!");
this.smilFile = new FileInfo(file);
}
inlineFiles.Add(file);
}

public void ClearTo()
{
destinations.Clear();
}

// 得到二进制编码字节
public byte[] MakeMMSContent()
{

if (this.smilFile == null) throw new Exception("The smil file not found!");

byte[] MMSContent = new byte[0];

//X-Mms-Message-Type
MMSContent = appendContent(new byte[] { 0x8C, 0x80 }, MMSContent);


//X-Mms-Transaction-ID
MMSContent = appendContent(new byte[] { 0x98 }, MMSContent);
MMSContent = appendContent(serialNumber.ToString(), MMSContent);
serialNumber++;

MMSContent = appendContent(new byte[] { 0x0 }, MMSContent);

//X-Mms-MMS-Version
MMSContent = appendContent(new byte[] { 0x8D, 0x90 }, MMSContent);

//Date
MMSContent = appendContent(new byte[] { 0x85 }, MMSContent);
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0);
int sec = (int)ts.TotalSeconds;
byte[] bySec = BitConverter.GetBytes(sec);
MMSContent = appendContent(new byte[] { (byte)bySec.Length }, MMSContent);
Array.Reverse(bySec);
MMSContent = appendContent(bySec, MMSContent);

if (deliverTime > 0)
{
MMSContent = appendContent(new byte[] { 0x87 }, MMSContent);
byte[] bfTime = BitConverter.GetBytes(deliverTime);
Array.Reverse(bfTime);
byte[] bfTimeLen = new byte[3];
bfTimeLen[0] = (byte)(bfTime.Length + 2);
bfTimeLen[1] = 0x81; // 相对时间格式
bfTimeLen[2] = (byte)bfTime.Length;
MMSContent = appendContent(bfTimeLen, MMSContent);
MMSContent = appendContent(bfTime, MMSContent);
}

//From,Len = 0x01,一个以0x81为标记的占位符,发送时自动插入发送号码.
MMSContent = appendContent(new byte[] { 0x89, 0x01, 0x81 }, MMSContent);

//To
for (int i = 0; i < destinations.Count; i++)
{
MMSContent = appendContent(new byte[] { 0x97 }, MMSContent);
MMSContent = appendContent("+86" + (string)destinations[i] + "/TYPE=PLMN", MMSContent);
//MMSContent = appendContent(new byte[] { 0x20, 0x20, 0x0 }, MMSContent);
MMSContent = appendContent(new byte[] { 0x0 }, MMSContent);
}

//subject
if (subject.Length > 0) // 使用Utf8编码
{
MMSContent = appendContent(new byte[] { 0x96 }, MMSContent);
byte[] byLen = new byte[1];
byLen[0] = (byte)(Encoding.UTF8.GetByteCount(subject) + 2);
MMSContent = appendContent(byLen, MMSContent);
MMSContent = appendContent(new byte[] { 0xEA }, MMSContent);
MMSContent = appendContent(Encoding.UTF8.GetBytes(subject), MMSContent);
MMSContent = appendContent(new byte[] { 0x0 }, MMSContent);
}

MMSContent = appendContent(new byte[] { 0x84 }, MMSContent);
int ctLen = 2 // 0xB3 ,0x89
+ "application/smil".Length
+ 3 //0x00 0x8A 0x3c
+ smilFile.Name.Length
+ 2; //0x3c,0x00

byte[] cl = uintToBytes(ctLen);

if(cl[0] >= 0x1F)
MMSContent = appendContent(new byte[] { 0x1F }, MMSContent);
MMSContent = appendContent(cl, MMSContent);
MMSContent = appendContent(new byte[] { 0xB3}, MMSContent);
//0xB3 Content-Type:application/vnd.wap.multipart.related

MMSContent = appendContent(new byte[] { 0x89 }, MMSContent);
MMSContent = appendContent(Encoding.ASCII.GetBytes("application/smil"), MMSContent);
MMSContent = appendContent(new byte[] { 0x0 }, MMSContent);

MMSContent = appendContent(new byte[] { 0x8A ,0x3C}, MMSContent);//0x8A:Start,0x3C:<
MMSContent = appendContent(Encoding.ASCII.GetBytes( smilFile.Name ), MMSContent);
MMSContent = appendContent(new byte[] { 0x3E ,0x0 }, MMSContent); //0x3E:>

byte[] byFileCount = new byte[1];
byFileCount[0] = (byte)inlineFiles.Count;
MMSContent = appendContent(byFileCount, MMSContent);

int chLen = "application/smil".Length
+ 4 //0x00 0xc0 0x22 0x3c: cid,",<
+ smilFile.Name.Length
+ 3 // 0x3E,0x00,0x8E
+ smilFile.Name.Length
+ 1; // 0x00

for (int j = 0; j < inlineFiles.Count; j++)
{
MMSContent = appendContent(GetFileContent(inlineFiles[j].ToString()), MMSContent);
}
return MMSContent;
}

// 打包文件
private byte[] GetFileContent(string FileName)
{

byte[] byHeaders = new byte[0]; // ContentType和Headers组合
byte[] byData = readFile(FileName);

string FileID = getContentId(FileName);
if (FileName.EndsWith(".txt"))
{
byHeaders = new byte[1];
byHeaders[0] = (byte)(Encoding.ASCII.GetByteCount(FileID) + 5);
byHeaders = appendContent(new byte[] { 0x83, 0x85 }, byHeaders); // Utf-8
byHeaders = appendContent(Encoding.ASCII.GetBytes(FileID), byHeaders);
byHeaders = appendContent(new byte[] { 0x00 }, byHeaders);
byHeaders = appendContent(new byte[] { 0x81, 0xEA }, byHeaders);

}
else if (FileName.EndsWith(".gif"))
{
byHeaders = new byte[] { 0x9D };
}
else if (FileName.EndsWith(".mid") || FileName.EndsWith(".midi"))
{
byHeaders = Encoding.ASCII.GetBytes("audio/midi");
byHeaders = appendContent(new byte[] { 0x00 }, byHeaders);
}
else if (FileName.EndsWith(".smil"))
{
byHeaders = Encoding.ASCII.GetBytes("application/smil");
byHeaders = appendContent(new byte[] { 0x00 }, byHeaders);
}

//加入Content-ID
byHeaders = appendContent(new byte[] { 0xC0, 0x22, 0x3C }, byHeaders);
byHeaders = appendContent(Encoding.ASCII.GetBytes(FileID), byHeaders);
byHeaders = appendContent(new byte[] { 0x3E, 0x00 }, byHeaders);

//加入Content-Location
byHeaders = appendContent(new byte[] { 0x8E }, byHeaders);
byHeaders = appendContent(Encoding.ASCII.GetBytes(FileID), byHeaders);
byHeaders = appendContent(new byte[] { 0x00 }, byHeaders);

byte[] byHeaderLen = uintToBytes(byHeaders.Length);
byte[] byDataLen = uintToBytes(byData.Length);

byte[] byMmc = new byte[byHeaderLen.Length + byDataLen.Length + byHeaders.Length + byData.Length];
Array.Copy(byHeaderLen, byMmc, byHeaderLen.Length);
Array.Copy(byDataLen, 0, byMmc, byHeaderLen.Length, byDataLen.Length);
Array.Copy(byHeaders, 0, byMmc, byHeaderLen.Length + byDataLen.Length, byHeaders.Length);
Array.Copy(byData, 0, byMmc, byHeaderLen.Length + byDataLen.Length + byHeaders.Length, byData.Length);

return byMmc;
}

private byte[] uintToBytes(int n)
{
byte[] buf = new byte[8];
int l = 0;
while (n >= 128)
{
byte b = (byte)(n & 0x7F);
n = n >> 7;
buf[l++] = b;
}
buf[l++] = (byte)n;

byte[] retBys = new byte[l];
for (int i = 0; i < l; ++i)
{
retBys[i] = (byte)(buf[l - i - 1] | 0x80);
}
retBys[l - 1] &= 0x7F;
return retBys;

}

// 读取文件
private byte[] readFile(string FileName)
{
if (FileName.EndsWith(".txt")) {

StreamReader sr = null;
try{
sr = new StreamReader(FileName, Encoding.Default);
string text = sr.ReadToEnd();
byte[] bf = Encoding.UTF8.GetBytes(text);
return bf;
}
catch {
return new byte[0];
}
finally {
if (sr != null) sr.Close();
}
}
FileStream fs = null;
try
{
fs = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // 没有设定Buffsize
byte[] bf = new byte[fs.Length];
fs.Read(bf, 0, (int)fs.Length);
return bf;
}
catch{
return new byte[0];
}
finally{
if(fs != null) fs.Close();
}
}

private string getContentId(string FileName)
{
int at = FileName.LastIndexOf("/");
if (at < 0)
at = FileName.LastIndexOf("/");
return FileName.Substring(at + 1);
}

private byte[] appendContent(byte[] srcBys, byte[] destBys)
{
Array.Resize(ref destBys, srcBys.Length + destBys.Length);
Array.Copy(srcBys,0,destBys,destBys.Length - srcBys.Length,srcBys.Length);
return destBys;
}

private byte[] appendContent(string sz, byte[] byDest)
{
return appendContent(Encoding.Default.GetBytes(sz), byDest);
}
}

/// <summary>
/// MMSender 的摘要说明。
///
/// </summary>
public class MMSender
{
// 设置参数
string sMmscUrl = "http://mmsc.monternet.com";
string sProxyUrl = "10.0.0.172:80";

public MMSender()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public void SetMMSC(string szUrl)
{
sMmscUrl = szUrl;
}
public void SetProxy(string szUrl)
{
sProxyUrl = szUrl;
}

/* 发送MMS的过程
1> 创建消息发送接口
MMSender ms = new MMSender();
2> 设置参数属性
默认属性已经是中国移动参数,因此如果是中国移动用户,以下两个操作可以不需要
ms.SetMMSC("http://mmsc.monternet.com");
ms.SetProxy("10.0.0.172:80");
3> 创建消息
MMessage mm= new MMessage();
4> 设置消息内容
mm.SetSubject("标题"); // 设置标题
mm.AddTo("13810034500"); // 添加接收号码,调用一次添加一个接收号码
mm.AddFile("FileName"); // 添加发送文件,包含文件路径,调用一次添加一个发送文件
5> 发送消息
string szReult =ms.Send(mm);

6> 继续发送其他号码
mm.ClearTo();
mm.AddTo("13812345678");
ms.Send(mm);
*/

/* 避免协议冲突的设置
<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true"/>
</settings>
</system.net>
</configuration>
*/

public string Send(MMessage mm)
{
try
{
byte[] byMM = mm.MakeMMSContent();
if (byMM.Length > 50 * 1024)
return "The package is too large!";
// 验证参数有效性
//FileStream fs = new FileStream("d:/aaa.mms", FileMode.Create);
//fs.Write(byMM, 0, byMM.Length);
//fs.Close();
//return "OK";
WebRequest wReq = WebRequest.Create(sMmscUrl);
HttpWebRequest hReq = (HttpWebRequest)wReq;
wReq.Headers.Clear();
if (sProxyUrl.Length > 0)
wReq.Proxy = new WebProxy(sProxyUrl);

wReq.ContentType = "application/vnd.wap.mms-message";
hReq.Accept = "application/vnd.wap.mms-message,text/plain,*/*";
wReq.Method = "POST";
hReq.KeepAlive = false;
hReq.UserAgent = "Nokia6681/2.0 (4.00.15) SymbianOS/8.0 Series60/2.6 Profile/MIDP-2.0 Configuration/CLDC-1.1";
// Write Post Dat

hReq.ContentLength = byMM.Length;
Stream sReq = wReq.GetRequestStream();
sReq.Write(byMM, 0, byMM.Length);
sReq.Close();
WebResponse wRes = wReq.GetResponse();
HttpWebResponse hRes = (HttpWebResponse)wRes;
if (hRes.StatusCode == HttpStatusCode.OK)
{
Stream sRes = wRes.GetResponseStream();
StreamReader sr = new StreamReader(sRes);
string szResult = sr.ReadToEnd(); // 发送结果
sr.Close();
return szResult;
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return string.Empty;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐