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
;
//
多少秒以后开始投递
ArrayListinlineFiles
=
new
ArrayList();
//
文件列表
ArrayListdestinations
=
new
ArrayList();
//
目标号码
static
long
serialNumber
=
19700311L
;
//
流水号
FileInfosmilFile;
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(
"
Thesmilfilehasexisted!
"
);
this
.smilFile
=
new
FileInfo(file);
}
inlineFiles.Add(file);
}
public
void
ClearTo()
{
destinations.Clear();
}
//
得到二进制编码字节
public
byte
[]MakeMMSContent()
{
if
(
this
.smilFile
==
null
)
throw
new
Exception(
"
Thesmilfilenotfound!
"
);
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);
TimeSpants
=
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(newbyte[]{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
//
0x000x8A0x3c
+
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);
//
0xB3Content-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
//
0x000xc00x220x3c: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
"
)){
StreamReadersr
=
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();
}
}
FileStreamfs
=
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>创建消息发送接口
MMSenderms=newMMSender();
2>设置参数属性
默认属性已经是中国移动参数,因此如果是中国移动用户,以下两个操作可以不需要
ms.SetMMSC("
http://mmsc.monternet.com
");
ms.SetProxy("10.0.0.172:80");
3>创建消息
MMessagemm=newMMessage();
4>设置消息内容
mm.SetSubject("标题");//设置标题
mm.AddTo("13810034500");//添加接收号码,调用一次添加一个接收号码
mm.AddFile("FileName");//添加发送文件,包含文件路径,调用一次添加一个发送文件
5>发送消息
stringszReult=ms.Send(mm);
6>继续发送其他号码
mm.ClearTo();
mm.AddTo("13812345678");
ms.Send(mm);
*/
/*
避免协议冲突的设置
<configuration>
<system.net>
<settings>
<httpWebRequestuseUnsafeHeaderParsing="true"/>
</settings>
</system.net>
</configuration>
*/
public
string
Send(MMessagemm)
{
try
{
byte
[]byMM
=
mm.MakeMMSContent();
if
(byMM.Length
>
50
*
1024
)
return
"
Thepackageistoolarge!
"
;
//
验证参数有效性
//
FileStreamfs=newFileStream("d:/aaa.mms",FileMode.Create);
//
fs.Write(byMM,0,byMM.Length);
//
fs.Close();
//
return"OK";
WebRequestwReq
=
WebRequest.Create(sMmscUrl);
HttpWebRequesthReq
=
(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.0Series60/2.6Profile/MIDP-2.0Configuration/CLDC-1.1
"
;
//
WritePostDat
hReq.ContentLength
=
byMM.Length;
StreamsReq
=
wReq.GetRequestStream();
sReq.Write(byMM,
0
,byMM.Length);
sReq.Close();
WebResponsewRes
=
wReq.GetResponse();
HttpWebResponsehRes
=
(HttpWebResponse)wRes;
if
(hRes.StatusCode
==
HttpStatusCode.OK)
{
StreamsRes
=
wRes.GetResponseStream();
StreamReadersr
=
new
StreamReader(sRes);
string
szResult
=
sr.ReadToEnd();
//
发送结果
sr.Close();
return
szResult;
}
}
catch
(Exceptione)
{
throw
new
Exception(e.Message);
}
return
string
.Empty;
}
}
}