一些系统,需要能够发送短信,量很小,平均每日10条。 运营商平台太贵,白名单很严格,小额只能发省内; 各短信平台有各种限制,大事件前后会关闭; 飞信以前可以用WAP发,但是现在多了验证码,搞不定了; 短信猫买来还得写控制程序,价钱和时间上……
手上有两部废弃的WM手机,没有故障,只是老旧不好用!
有一个WM软件(后面有下载),它在WM手机上开启一个Http服务器,使得我们可以在PC上通过浏览器直接访问!
有收发短信的功能! 把手机WiFi性能跳到最大,关闭每x分钟限制自动关闭;软件设置自动开启服务,关闭“运行时防止休眠”(它设计上有BUG,这个会导致服务10分钟就关闭),拉到启动目录设为自动启动。
OK!就是它了,我们写个程序包装一下,伪造为Web操作收发短信!
主要代码如下: View Code
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using NewLife;
using NewLife.Linq;
using NewLife.Log;
using NewLife.Web;
namespace WMSms
{
/// <summary>手机类</summary>
class Mobile : DisposeBase
{
#region 属性
private String _Address;
/// <summary>地址</summary>
public String Address { get { return _Address; } set { _Address = value; } }
private Boolean _Logined;
/// <summary>是否已登录</summary>
public Boolean Logined { get { return _Logined; } set { _Logined = value; } }
#endregion
#region 构造
public Mobile(String address)
{
Address = address;
}
protected override void OnDispose(bool disposing)
{
base.OnDispose(disposing);
if (client != null) client.Dispose();
}
#endregion
#region 通讯基础
private WebClientX client;
void EnsureClient()
{
if (client != null) return;
client = new WebClientX(true, true);
client.Encoding = Encoding.UTF8;
ServicePointManager.Expect100Continue = false;
}
String Get(String url)
{
EnsureClient();
//return client.DownloadString(url);
var bts = client.DownloadData(url);
return Encoding.UTF8.GetString(bts);
}
String Post(String url, String data)
{
EnsureClient();
client.Headers["Referer"] = url;
client.Headers["Content-Type"] = "application/x-www-form-urlencoded";
//return client.UploadString(url, data);
var bts = Encoding.UTF8.GetBytes(data);
bts = client.UploadData(url, bts);
return Encoding.UTF8.GetString(bts);
}
String Post(String url, IDictionary<String, Object> data)
{
if (data == null) return Post(url, "");
var sb = new StringBuilder();
foreach (var item in data)
{
if (sb.Length > 0) sb.Append("&");
if (item.Value != null)
sb.AppendFormat("{0}={1}", item.Key, HttpUtility.UrlEncode("" + item.Value));
else
sb.AppendFormat("{0}=", item.Key);
}
return Post(url, sb.ToString());
}
#endregion
#region 方法
public Boolean Login(String pass)
{
if (Logined) return true;
var url = String.Format("http://{0}/authent/?returnurl=%2Ffs%2F", Address);
var html = Get(url);
url = String.Format("http://{0}/authent/?returnurl=%2Ffs%2F", Address);
var dic = new Dictionary<String, Object>();
dic.Add("user", "Admin");
dic.Add("pwd", pass);
html = Post(url, dic);
var rs = !html.IsNullOrWhiteSpace() && html.Contains("form");
Logined = rs;
return rs;
}
public Boolean SendMessage(String number, String content)
{
var url = String.Format("http://{0}/messaging/?page=newmessage", Address);
var dic = new Dictionary<String, Object>();
dic.Add("RequestDeliveryReport", "chk");
dic.Add("recipient", number);
dic.Add("recipientName", null);
dic.Add("smsbody", content);
var html = Post(url, dic);
return !html.IsNullOrWhiteSpace() && html.Contains("已发信息");
}
public Boolean Ping()
{
if (!Logined) return false;
try
{
var url = String.Format("http://{0}/fs/", Address);
var html = Get(url);
if (html.IsNullOrWhiteSpace()) return false;
// 如果回到登录页面,则标记为未登录
if (html.Contains("authent"))
{
Logined = false;
return false;
}
return html.Contains("My Device");
}
catch (Exception ex)
{
XTrace.WriteException(ex);
return false;
}
}
#endregion
#region 接收短信
public List<Message> ReceiveUnReaded()
{
var list = Receive(0);
if (list == null) return null;
list = list.Where(m => !m.Readed).ToList();
var i = 1;
var ls = list;
while (ls.Count >= 10 && !ls[ls.Count - 1].Readed)
{
ls = Receive(i++);
if (ls == null || ls.Count < 1) break;
ls = ls.Where(m => !m.Readed).ToList();
list.AddRange(ls);
if (list.Count >= 100) break;
}
return list;
}
public List<Message> ReceiveFromTime(DateTime start)
{
var list = Receive(0);
if (list == null) return null;
list = list.Where(m => m.Time > start).ToList();
var i = 1;
var ls = list;
while (ls.Count >= 10 && ls[ls.Count - 1].Time > start)
{
ls = Receive(i++);
if (ls == null || ls.Count < 1) break;
ls = ls.Where(m => m.Time > start).ToList();
list.AddRange(ls);
if (list.Count >= 100) break;
}
return list;
}
static Regex _regMsg = new Regex("<div class=\"([^\"]*)\"><span class=\"msgDesc\">从 :</span>\\s*([^<]*?)\\s*-\\s*<a href=\"\\?page=newmessage&recipient=([^&\"]*)[^\"]*\">答复</a><br/><span class=\"msgDesc\">已收到 :</span>\\s*([^<]*?)\\s*<br/>\\s*([^<]*?)\\s*</div>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public List<Message> Receive(Int32 page)
{
if (!Logined) return null;
var url = String.Format("http://{0}/messaging/", Address);
if (page > 1) url += "?page=" + page;
var html = Get(url);
if (html.IsNullOrWhiteSpace()) return null;
var list = new List<Message>();
foreach (Match m in _regMsg.Matches(html))
{
var msg = new Message();
msg.Readed = "readMsg".EqualIgnoreCase(m.Groups[1].Value);
// 名字
var name = m.Groups[2].Value.Trim();
if (!name.IsNullOrWhiteSpace())
{
name = HttpUtility.HtmlDecode(name);
var p = name.IndexOf("(");
if (p > 0) name = name.Substring(0, p).Trim();
msg.Name = name;
}
// 号码
var num = m.Groups[3].Value.Trim();
if (!num.IsNullOrWhiteSpace())
{
num = HttpUtility.UrlDecode(num);
if (num.StartsWith("+86")) num = num.Substring(3);
msg.Number = num;
}
// 时间
var dt = m.Groups[4].Value.Trim();
if (!dt.IsNullOrWhiteSpace())
{
dt = HttpUtility.HtmlDecode(dt);
var p = dt.IndexOf("(");
if (p > 0) dt = dt.Substring(0, p).Trim();
DateTime d;
if (DateTime.TryParse(dt, out d))
msg.Time = d;
else if (DateTime.TryParseExact(dt, "MM/dd/yy dddd HH:mm:ss", null, DateTimeStyles.None, out d))
msg.Time = d;
}
// 内容
var txt = m.Groups[5].Value.Trim();
if (!txt.IsNullOrWhiteSpace())
{
msg.Content = HttpUtility.HtmlDecode(txt);
}
list.Add(msg);
}
return list;
}
public class Message
{
private String _Number;
/// <summary>号码</summary>
public String Number { get { return _Number; } set { _Number = value; } }
private String _Name;
/// <summary>名称</summary>
public String Name { get { return _Name; } set { _Name = value; } }
private String _Content;
/// <summary>内容</summary>
public String Content { get { return _Content; } set { _Content = value; } }
private DateTime _Time;
/// <summary>时间</summary>
public DateTime Time { get { return _Time; } set { _Time = value; } }
private Boolean _Readed;
/// <summary>是否已读</summary>
public Boolean Readed { get { return _Readed; } set { _Readed = value; } }
}
#endregion
}
}
刚下去小店买了一张移动动感地带的卡,50块办卡返50,分5月返还每月10元,套餐每月20元包400条短信,实际上,后面每个月只需要交10元即可!
配置一下路由器,把WM手机的Http端口映射到公网,可供远程应用系统直接调用!
现在很多可用的二手WM手机只需要一百多块钱即可买到。
这个方案跟短信猫不相上下,(短信猫成品三百多块),也算是多一种选择吧!
WM软件:WiFi.rar
源代码:WMSmsSrc.rar