使用DotMSN 2.0开发MSN机器人(强烈建议别再使用dotmsn,使用MSNPSharp来开发)


发了几篇与DotMSN有关的博客后,有些朋友也在问我关于开发MSN机器人的一些问题。我也没有用过DotMSN 1.0,不知道他是什么样的,那我就用DotMSN 2.0简单介绍一下如何使用DotMSN来开发MSN机器人。在DotMSN的源码中,已经有完整的例子了,只是对一些事件没有做更详细的介绍和使用说明。

要登录MSN,要先创建一个Messenger类型的对象,并且设置好一些环境参数:

   1: messenger.Credentials.ClientID = "msmsgs@msnmsgr.com";
   2: messenger.Credentials.ClientCode = "Q1P7W2E4J9R8U3S5";
   3: messenger.Credentials.Account = parameters["Account"];
   4: messenger.Credentials.Password = parameters["Password"];
   5: messenger.Connect();

正常情况下,这几句代码后,MSN就可以正常登录了,如果你使用的是代理上网,那么你可以还需要如下的设置:

   1: if (!string.IsNullOrEmpty(parameters["ProxyHost"]))
   2: {
   3:    messenger.ConnectivitySettings.ProxyHost = parameters["ProxyHost"];
   4:    messenger.ConnectivitySettings.ProxyPort = int.Parse(parameters["ProxyPort"]);
   5:    messenger.ConnectivitySettings.ProxyType = (ProxyType)Enum.Parse(typeof(ProxyType), parameters["ProxyType"]);
   6: }

指定所使用的代理服务器和端口即可登录。

但是单单可以登录还是不够的,还需要对MSN的状态进行监控。这些就必须要通过DotMSN提供的事件来达到目的了,而根据事件的分类的不同,这些事件被分别定义在不同的类型里面:

Messenger类中定义了两个事件,分别为ConversationCreated和TransferInvitationReceived,这两个事件分别是在会话创建时和文件转输请求时触发的。TransferInvitationReceived用于处理文件传输的请求,由于需要比较复杂的处理,并且做为机器人本身并不太需要这个功能,所以这里不做详细介绍。

ConversationCreated事件

它的事件参数类型为ConversationCreatedEventArgs,它定义了一个Conversation成员对象,用于描述当前会话的上下文信息。在DotMSN中,每个会话创建实际上都创建了一个Conversation类型对象,它被维护在Messenger一个叫conversations的私有成员列表里面,当会话在一段时间内没有被激活时,DotMSN将会自动释放一些不需要的Conversation对象。所以我们根本就不要关心,如何去维护过期的会话。

Conversation对象中也定义了一些事件,这些事件是与当前会话有关的。比如,有联系人加入和离开时,收到信息时,会话关闭时,用户在打字时等等这些状态事件,这些事件是定义在Conversation的Switchboard属性中(SBMessageHandler类型),它们分别为,:

   1: public event SBChangedEventHandler AllContactsLeft;
   2: public event ContactChangedEventHandler ContactJoined;
   3: public event ContactChangedEventHandler ContactLeft;
   4: public event EmoticonDefinitionReceivedEventHandler EmoticonDefinitionReceived;
   5: public event HandlerExceptionEventHandler ExceptionOccurred;
   6: public event ErrorReceivedEventHandler ServerErrorReceived;
   7: public event SBChangedEventHandler SessionClosed;
   8: public event SBChangedEventHandler SessionEstablished;
   9: public event TextMessageReceivedEventHandler TextMessageReceived;
  10: public event UserTypingEventHandler UserTyping;
由于事件本身都比较简单,我就不详细介绍了。了解了ConversationCreated事件后,MSN机器人的功能基本就可以完成了。但是仍然还有一些事件是必须被了解的。
Nameserver属性
Messenger的Nameserver属性(NSMessageHandler类型)中,定义了一些与服务器连接状态的事件:
   1: public event HandlerExceptionEventHandler AuthenticationError;
   2: public event ListMutatedAddedEventHandler ContactAdded;
   3: public event ContactGroupChangedEventHandler ContactGroupAdded;
   4: public event ContactGroupChangedEventHandler ContactGroupChanged;
   5: public event ContactGroupChangedEventHandler ContactGroupRemoved;
   6: public event ContactChangedEventHandler ContactOffline;
   7: public event ContactChangedEventHandler ContactOnline;
   8: public event ListMutatedAddedEventHandler ContactRemoved;
   9: public event ContactStatusChangedEventHandler ContactStatusChanged;
  10: public event HandlerExceptionEventHandler ExceptionOccurred;
  11: public event MailChangedEventHandler MailboxChanged;
  12: public event MailboxStatusEventHandler MailboxStatusReceived;
  13: public event NewMailEventHandler NewMailReceived;
  14: public event PingAnswerEventHandler PingAnswer;
  15: public event ContactChangedEventHandler ReverseAdded;
  16: public event ContactChangedEventHandler ReverseRemoved;
  17: public event SBCreatedEventHandler SBCreated;
  18: public event ErrorReceivedEventHandler ServerErrorReceived;
  19: public event EventHandler SignedIn;
  20: public event SignedOffEventHandler SignedOff;
  21: public event EventHandler SynchronizationCompleted;

这些事件,监听了各种网络事件,和MSN自身的事件通知,比如ReverseAdded是当有添加自己为好友请求发生时触发的。

除了这些事件外,还有一些关于如何发送信息,如何向好友发送当前处理打字状态,如何保持连接等这些主题,都会在下面的例子中有所描述。或者你去查阅一下DotMSN的接口也可以很容易的找到答案。

示例:
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.Timers;
   5:  
   6: using XihSolutions.DotMSN;
   7:  
   8: namespace MSNRobot
   9: {
  10:     class Program
  11:     {
  12:         static Messenger messenger = new Messenger();
  13:         static Timer timer;
  14:  
  15:         static void Main(string[] args)
  16:         {
  17:             // by default this example will emulate the official microsoft windows messenger client
  18:             messenger.Credentials.ClientID = "msmsgs@msnmsgr.com";
  19:             messenger.Credentials.ClientCode = "Q1P7W2E4J9R8U3S5";
  20:             messenger.Nameserver.PingAnswer += new PingAnswerEventHandler(Nameserver_PingAnswer);
  21:             messenger.NameserverProcessor.ConnectionEstablished += new EventHandler(NameserverProcessor_ConnectionEstablished);
  22:             messenger.Nameserver.SignedIn += new EventHandler(Nameserver_SignedIn);
  23:             messenger.Nameserver.SignedOff += new SignedOffEventHandler(Nameserver_SignedOff);
  24:             messenger.NameserverProcessor.ConnectionException += new XihSolutions.DotMSN.Core.ProcessorExceptionEventHandler(NameserverProcessor_ConnectionException);
  25:             messenger.Nameserver.ExceptionOccurred += new XihSolutions.DotMSN.Core.HandlerExceptionEventHandler(Nameserver_ExceptionOccurred);
  26:             messenger.Nameserver.AuthenticationError += new XihSolutions.DotMSN.Core.HandlerExceptionEventHandler(Nameserver_AuthenticationError);
  27:             messenger.Nameserver.ServerErrorReceived += new XihSolutions.DotMSN.Core.ErrorReceivedEventHandler(Nameserver_ServerErrorReceived);
  28:             messenger.ConversationCreated += new ConversationCreatedEventHandler(messenger_ConversationCreated);
  29:             messenger.TransferInvitationReceived += new XihSolutions.DotMSN.DataTransfer.MSNSLPInvitationReceivedEventHandler(messenger_TransferInvitationReceived);
  30:             messenger.Nameserver.ReverseAdded += new ContactChangedEventHandler(Nameserver_ReverseAdded);
  31:  
  32:             //messenger.ConnectivitySettings.ProxyHost = "192.168.7.62";
  33:             //messenger.ConnectivitySettings.ProxyPort = 1080;
  34:             //messenger.ConnectivitySettings.ProxyType = ProxyType.Socks5;
  35:  
  36:             messenger.Credentials.Account = "";
  37:             messenger.Credentials.Password = "";
  38:  
  39:             timer = new Timer(3000);
  40:             timer.Enabled = true;
  41:             timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
  42:             WL("Connecting to server");
  43:             try
  44:             {
  45:                 messenger.Connect();
  46:             }
  47:             catch (Exception e)
  48:             {
  49:  
  50:                 WL(e.Message);
  51:             }
  52:             RL();
  53:  
  54:         }
  55:         static void timer_Elapsed(object sender, ElapsedEventArgs e)
  56:         {
  57:             SendPing();
  58:         }
  59:         static private void ReConnect()
  60:         {
  61:             try
  62:             {
  63:                 timer.Stop();
  64:                 WL("Disconnecting");
  65:                 messenger.Disconnect();
  66:                 WL("Reconnecting");
  67:                 messenger.Connect();
  68:             }
  69:             catch (Exception e)
  70:             {
  71:                 System.Threading.Thread.Sleep(3000);
  72:                 ReConnect();
  73:             }
  74:  
  75:         }
  76:  
  77:         static void Nameserver_ReverseAdded(object sender, ContactEventArgs e)
  78:         {
  79:             Console.WriteLine("Nameserver_ReverseAdded");
  80:             messenger.Nameserver.AddContactToList(e.Contact, MSNLists.AllowedList);
  81:             e.Contact.OnAllowedList = true;
  82:             e.Contact.OnForwardList = true;
  83:         }
  84:  
  85:         static void messenger_TransferInvitationReceived(object sender, XihSolutions.DotMSN.DataTransfer.MSNSLPInvitationEventArgs e)
  86:         {
  87:             WL("messenger_TransferInvitationReceived");
  88:         }
  89:  
  90:         static void messenger_ConversationCreated(object sender, ConversationCreatedEventArgs e)
  91:         {
  92:             e.Conversation.Switchboard.TextMessageReceived += new TextMessageReceivedEventHandler(Switchboard_TextMessageReceived);
  93:             e.Conversation.Switchboard.ContactJoined += new ContactChangedEventHandler(Switchboard_ContactJoined);
  94:             e.Conversation.Switchboard.ContactLeft += new ContactChangedEventHandler(Switchboard_ContactLeft);
  95:             e.Conversation.Switchboard.SessionClosed += new SBChangedEventHandler(Switchboard_SessionClosed);
  96:             e.Conversation.Switchboard.UserTyping += new UserTypingEventHandler(Switchboard_UserTyping);
  97:         }
  98:  
  99:         static void Switchboard_UserTyping(object sender, ContactEventArgs e)
 100:         {
 101:             WL(e.Contact.Name + "is typing");
 102:             //发送打字状态
 103:             ((XihSolutions.DotMSN.SBMessageHandler)sender).SendTypingMessage();
 104:         }
 105:  
 106:         static void Switchboard_SessionClosed(object sender, EventArgs e)
 107:         {
 108:             WL("session closed");
 109:         }
 110:  
 111:         static void Switchboard_ContactLeft(object sender, ContactEventArgs e)
 112:         {
 113:             WL("{0} left", e.Contact.Name);
 114:         }
 115:  
 116:         static void Switchboard_ContactJoined(object sender, ContactEventArgs e)
 117:         {
 118:             WL("{0} joined.", e.Contact.Name);
 119:         }
 120:  
 121:         static void Switchboard_TextMessageReceived(object sender, TextMessageEventArgs e)
 122:         {
 123:             WL("{0} says : {1}", e.Sender, e.Message);
 124:             XihSolutions.DotMSN.SBMessageHandler handler = (XihSolutions.DotMSN.SBMessageHandler)sender;
 125:             handler.SendTextMessage(new TextMessage(string.Format("您好,你跟我说:{0}", e.Message.Text)));
 126:         }
 127:  
 128:         static void Nameserver_ServerErrorReceived(object sender, MSNErrorEventArgs e)
 129:         {
 130:             WL("Nameserver_ServerErrorReceived");
 131:         }
 132:  
 133:         static void Nameserver_AuthenticationError(object sender, ExceptionEventArgs e)
 134:         {
 135:             WL("Nameserver_AuthenticationError");
 136:         }
 137:  
 138:         static void Nameserver_ExceptionOccurred(object sender, ExceptionEventArgs e)
 139:         {
 140:             WL("Nameserver_ExceptionOccurred");
 141:         }
 142:  
 143:         static void NameserverProcessor_ConnectionException(object sender, ExceptionEventArgs e)
 144:         {
 145:             WL("NameserverProcessor_ConnectionException");
 146:         }
 147:  
 148:         static void Nameserver_SignedOff(object sender, SignedOffEventArgs e)
 149:         {
 150:             WL("Nameserver_SignedOff");
 151:             ReConnect();
 152:         }
 153:  
 154:         static void Nameserver_SignedIn(object sender, EventArgs e)
 155:         {
 156:             messenger.Owner.Status = PresenceStatus.Online;
 157:             messenger.Owner.NotifyPrivacy = NotifyPrivacy.AutomaticAdd;
 158:             WL("Nameserver_SignedIn");
 159:             foreach (Contact contact in messenger.ContactList.Forward)
 160:             {
 161:                 WL(contact.Name);
 162:             }
 163:             foreach (Contact contact in messenger.ContactList.Allowed)
 164:             {
 165:                 WL(contact.Name);
 166:             }
 167:             foreach (Contact contact in messenger.ContactList.BlockedList)
 168:             {
 169:                 WL(contact.Name);
 170:             }
 171:             messenger.Nameserver.SetPrivacyMode(PrivacyMode.AllExceptBlocked);
 172:             timer.Start();
 173:         }
 174:         static void Nameserver_PingAnswer(object sender, PingAnswerEventArgs e)
 175:         {
 176:             WL(e.SecondsToWait.ToString());
 177:             WL("Nameserver_PingAnswer");
 178:         }
 179:         static void SendPing()
 180:         {
 181:             messenger.NameserverProcessor.SendMessage(new PingMessage());
 182:         }
 183:         static void NameserverProcessor_ConnectionEstablished(object sender, EventArgs e)
 184:         {
 185:             WL("NameserverProcessor_ConnectionEstablished");
 186:         }
 187:  
 188:  
 189:         #region Helper methods
 190:  
 191:         private static void WL(object text, params object[] args)
 192:         {
 193:             Console.WriteLine(text.ToString(), args);
 194:         }
 195:  
 196:         private static void RL()
 197:         {
 198:             Console.ReadLine();
 199:         }
 200:  
 201:         private static void Break()
 202:         {
 203:             System.Diagnostics.Debugger.Break();
 204:         }
 205:  
 206:         #endregion
 207:     }
 208:     public class PingMessage : XihSolutions.DotMSN.Core.NSMessage
 209:     {
 210:         public override byte[] GetBytes()
 211:         {
 212:  
 213:             return System.Text.Encoding.UTF8.GetBytes("PNG\r\n");
 214:         }
 215:     }
 216: }

例子下载,本文所使用的例子在MSNRobot工程中。2008/1/17 更新例子下载,解决出现的"您的主机中的软件放弃了一个已建立的连接"异常

阿不