PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/MSNPSHARP_DEV/MSNPSharp/NSMessageHandler.MSNP21.cs

http://msnp-sharp.googlecode.com/
C# | 1927 lines | 1373 code | 384 blank | 170 comment | 317 complexity | 0724eb27bab0f61a6387a37595e18c21 MD5 | raw file
  1. #region
  2. /*
  3. Copyright (c) 2002-2012, Bas Geertsema, Xih Solutions
  4. (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice, Andy Phan, Chang Liu.
  5. All rights reserved. http://code.google.com/p/msnp-sharp/
  6. Redistribution and use in source and binary forms, with or without
  7. modification, are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright notice,
  9. this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. * Neither the names of Bas Geertsema or Xih Solutions nor the names of its
  14. contributors may be used to endorse or promote products derived from this
  15. software without specific prior written permission.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
  17. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  20. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  26. THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #endregion
  29. using System;
  30. using System.IO;
  31. using System.Net;
  32. using System.Xml;
  33. using System.Web;
  34. using System.Text;
  35. using System.Drawing;
  36. using System.Diagnostics;
  37. using System.Collections.Generic;
  38. namespace MSNPSharp
  39. {
  40. using MSNPSharp.Core;
  41. using MSNPSharp.P2P;
  42. using MSNPSharp.Apps;
  43. partial class NSMessageHandler
  44. {
  45. #region Public Events
  46. /// <summary>
  47. /// Occurs when any contact changes status.
  48. /// </summary>
  49. public event EventHandler<ContactStatusChangedEventArgs> ContactStatusChanged;
  50. protected internal virtual void OnContactStatusChanged(ContactStatusChangedEventArgs e)
  51. {
  52. if (ContactStatusChanged != null)
  53. ContactStatusChanged(this, e);
  54. }
  55. /// <summary>
  56. /// Occurs when any contact goes from offline status to another status.
  57. /// </summary>
  58. public event EventHandler<ContactStatusChangedEventArgs> ContactOnline;
  59. protected internal virtual void OnContactOffline(ContactStatusChangedEventArgs e)
  60. {
  61. if (ContactOffline != null)
  62. ContactOffline(this, e);
  63. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  64. e.Contact.ToString() + " goes to " + e.NewStatus + " from " + e.OldStatus + (e.Via == null ? String.Empty : " via=" + e.Via.ToString()) + "\r\n", GetType().Name);
  65. }
  66. /// <summary>
  67. /// Occurs when any contact goes from any status to offline status.
  68. /// </summary>
  69. public event EventHandler<ContactStatusChangedEventArgs> ContactOffline;
  70. protected internal virtual void OnContactOnline(ContactStatusChangedEventArgs e)
  71. {
  72. if (ContactOnline != null)
  73. ContactOnline(this, e);
  74. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  75. e.Contact.ToString() + " goes to " + e.NewStatus + " from " + e.OldStatus + (e.Via == null ? String.Empty : " via=" + e.Via.ToString()) + "\r\n", GetType().Name);
  76. }
  77. /// <summary>
  78. /// Occurs when a user is typing.
  79. /// </summary>
  80. public event EventHandler<TypingArrivedEventArgs> TypingMessageReceived;
  81. protected virtual void OnTypingMessageReceived(TypingArrivedEventArgs e)
  82. {
  83. if (TypingMessageReceived != null)
  84. TypingMessageReceived(this, e);
  85. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  86. "TYPING: " + e.OriginalSender.ToString() + (e.Sender == e.OriginalSender ? String.Empty : ";by=" + e.Sender.ToString()));
  87. }
  88. /// <summary>
  89. /// Occurs when we receive a nudge message by a user.
  90. /// </summary>
  91. public event EventHandler<NudgeArrivedEventArgs> NudgeReceived;
  92. protected virtual void OnNudgeReceived(NudgeArrivedEventArgs e)
  93. {
  94. if (NudgeReceived != null)
  95. NudgeReceived(this, e);
  96. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  97. "NUDGE: " + e.OriginalSender + (e.Sender == e.OriginalSender ? String.Empty : ";by=" + e.Sender.ToString()));
  98. }
  99. /// <summary>
  100. /// Occurs when we receive a text message from a user.
  101. /// </summary>
  102. public event EventHandler<TextMessageArrivedEventArgs> TextMessageReceived;
  103. protected virtual void OnTextMessageReceived(TextMessageArrivedEventArgs e)
  104. {
  105. if (TextMessageReceived != null)
  106. TextMessageReceived(this, e);
  107. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  108. "TEXT MESSAGE: " + e.OriginalSender.ToString() + (e.Sender == e.OriginalSender ? String.Empty : ";by=" + e.Sender.ToString()) + "\r\n" + e.TextMessage.ToDebugString());
  109. }
  110. /// <summary>
  111. /// Fired when a contact sends a emoticon definition.
  112. /// </summary>
  113. public event EventHandler<EmoticonDefinitionEventArgs> EmoticonDefinitionReceived;
  114. protected virtual void OnEmoticonDefinitionReceived(EmoticonDefinitionEventArgs e)
  115. {
  116. if (EmoticonDefinitionReceived != null)
  117. EmoticonDefinitionReceived(this, e);
  118. }
  119. /// <summary>
  120. /// Fired when a contact sends a wink definition.
  121. /// </summary>
  122. public event EventHandler<WinkEventArgs> WinkDefinitionReceived;
  123. protected virtual void OnWinkDefinitionReceived(WinkEventArgs e)
  124. {
  125. if (WinkDefinitionReceived != null)
  126. WinkDefinitionReceived(this, e);
  127. }
  128. /// <summary>
  129. /// Occurs when a multiparty chat created remotely. Owner is joined automatically by the library.
  130. /// </summary>
  131. public event EventHandler<MultipartyCreatedEventArgs> MultipartyCreatedRemotely;
  132. protected virtual void OnMultipartyCreatedRemotely(MultipartyCreatedEventArgs e)
  133. {
  134. if (MultipartyCreatedRemotely != null)
  135. MultipartyCreatedRemotely(this, e);
  136. }
  137. /// <summary>
  138. /// Occurs when a contact joined the group chat.
  139. /// </summary>
  140. public event EventHandler<GroupChatParticipationEventArgs> JoinedGroupChat;
  141. protected virtual void OnJoinedGroupChat(GroupChatParticipationEventArgs e)
  142. {
  143. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  144. e.Contact + " joined group chat " + e.Via.ToString(), GetType().Name);
  145. if (JoinedGroupChat != null)
  146. JoinedGroupChat(this, e);
  147. }
  148. /// <summary>
  149. /// Occurs when a contact left the group chat.
  150. /// </summary>
  151. public event EventHandler<GroupChatParticipationEventArgs> LeftGroupChat;
  152. protected virtual void OnLeftGroupChat(GroupChatParticipationEventArgs e)
  153. {
  154. if (LeftGroupChat != null)
  155. LeftGroupChat(this, e);
  156. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  157. e.Contact + " left group chat " + e.Via.ToString(), GetType().Name);
  158. }
  159. /// <summary>
  160. /// Occurs after the user on another end point closed the IM window.
  161. /// </summary>
  162. public event EventHandler<CloseIMWindowEventArgs> RemoteEndPointCloseIMWindow;
  163. protected virtual void OnRemoteEndPointCloseIMWindow(CloseIMWindowEventArgs e)
  164. {
  165. if (RemoteEndPointCloseIMWindow != null)
  166. RemoteEndPointCloseIMWindow(this, e);
  167. if (e.Sender != null && e.SenderEndPoint != null)
  168. {
  169. string partiesString = string.Empty;
  170. foreach (Contact party in e.Parties)
  171. {
  172. partiesString += party.ToString() + "\r\n";
  173. }
  174. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose,
  175. "User at End Point: " + e.SenderEndPoint.ToString() + " has closed the IM window.\r\n" +
  176. "Parties in the conversation: \r\n" +
  177. partiesString);
  178. }
  179. }
  180. #endregion
  181. #region MULTIPARTY
  182. #region CreateMultiparty
  183. internal class MultipartyObject
  184. {
  185. public event EventHandler<MultipartyCreatedEventArgs> MultipartyCreatedLocally;
  186. public int TransactionID;
  187. public List<string> InviteQueueHash;
  188. public Contact MultiParty;
  189. public MultipartyObject(int transId, List<string> inviteQueueHash, Contact multiParty,
  190. EventHandler<MultipartyCreatedEventArgs> onCreated)
  191. {
  192. TransactionID = transId;
  193. InviteQueueHash = new List<string>(inviteQueueHash);
  194. MultiParty = multiParty;
  195. if (onCreated != null)
  196. MultipartyCreatedLocally += onCreated;
  197. }
  198. internal void OnMultipartyCreatedLocally(object sender, MultipartyCreatedEventArgs e)
  199. {
  200. if (MultipartyCreatedLocally != null)
  201. {
  202. MultipartyCreatedLocally(sender, e);
  203. MultipartyCreatedLocally -= OnMultipartyCreatedLocally;
  204. }
  205. }
  206. };
  207. /// <summary>
  208. /// Creates a new multiparty (Group chat)
  209. /// </summary>
  210. /// <param name="inviteQueue">Contacts to be invited (don't add yourself)</param>
  211. /// <param name="onCreated">The handler to be executed when multiparty created (must be provided)</param>
  212. /// <exception cref="ArgumentNullException">inviteQueue or event handler is null</exception>
  213. /// <exception cref="InvalidOperationException">At least 2 contacts is required except you and contacts must support multiparty</exception>
  214. /// <returns>Transaction ID</returns>
  215. public int CreateMultiparty(List<Contact> inviteQueue, EventHandler<MultipartyCreatedEventArgs> onCreated)
  216. {
  217. if (inviteQueue == null || inviteQueue.Count == 0)
  218. throw new ArgumentNullException("inviteQueue");
  219. if (onCreated == null)
  220. throw new ArgumentNullException("onCreated");
  221. List<string> newQueue = new List<string>();
  222. foreach (Contact c in inviteQueue)
  223. {
  224. if (c != null &&
  225. !c.IsSibling(Owner) &&
  226. !newQueue.Contains(c.SiblingString) &&
  227. c.SupportsMultiparty)
  228. {
  229. newQueue.Add(c.SiblingString);
  230. }
  231. }
  232. if (newQueue.Count < 2)
  233. throw new InvalidOperationException("At least 2 contacts is required except you and contacts must support multiparty.");
  234. NSMessageProcessor nsmp = (NSMessageProcessor)MessageProcessor;
  235. int transId = nsmp.IncreaseTransactionID();
  236. lock (multiParties)
  237. multiParties[transId] = new MultipartyObject(transId, newQueue, null, onCreated);
  238. string to = ((int)IMAddressInfoType.TemporaryGroup).ToString() + ":" + Guid.Empty.ToString("D").ToLowerInvariant() + "@" + Contact.DefaultHostDomain;
  239. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  240. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  241. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  242. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  243. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/circle";
  244. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/multiparty+xml";
  245. mmMessage.InnerBody = new byte[0];
  246. NSMessage putPayload = new NSMessage("PUT");
  247. putPayload.InnerMessage = mmMessage;
  248. nsmp.SendMessage(putPayload, transId);
  249. return transId;
  250. }
  251. #endregion
  252. #region GetMultiparty
  253. public Contact GetMultiparty(string tempGroupAddress)
  254. {
  255. if (!String.IsNullOrEmpty(tempGroupAddress))
  256. {
  257. lock (multiParties)
  258. {
  259. foreach (MultipartyObject group in multiParties.Values)
  260. {
  261. if (group.MultiParty != null && group.MultiParty.Account == tempGroupAddress)
  262. return group.MultiParty;
  263. }
  264. }
  265. }
  266. return null;
  267. }
  268. internal MultipartyObject GetMultipartyObject(string tempGroupAddress)
  269. {
  270. if (!String.IsNullOrEmpty(tempGroupAddress))
  271. {
  272. lock (multiParties)
  273. {
  274. foreach (MultipartyObject group in multiParties.Values)
  275. {
  276. if (group.MultiParty != null && group.MultiParty.Account == tempGroupAddress)
  277. return group;
  278. }
  279. }
  280. }
  281. return null;
  282. }
  283. #endregion
  284. #region InviteContactToMultiparty
  285. public void InviteContactToMultiparty(Contact contact, Contact group)
  286. {
  287. string to = ((int)group.ClientType).ToString() + ":" + group.Account;
  288. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  289. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  290. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  291. mmMessage.RoutingHeaders[MIMERoutingHeaders.To][MIMERoutingHeaders.Path] = "IM";
  292. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  293. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/circle";
  294. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/multiparty+xml";
  295. string xml = "<circle><roster><id>IM</id><user><id>" + ((int)contact.ClientType).ToString() + ":" + contact.Account + "</id></user></roster></circle>";
  296. mmMessage.InnerBody = Encoding.UTF8.GetBytes(xml);
  297. NSMessage putPayload = new NSMessage("PUT");
  298. putPayload.InnerMessage = mmMessage;
  299. MessageProcessor.SendMessage(putPayload);
  300. }
  301. #region LeaveMultiparty
  302. public void LeaveMultiparty(Contact group)
  303. {
  304. string to = ((int)group.ClientType).ToString() + ":" + group.Account;
  305. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  306. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  307. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  308. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  309. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/circle/roster(IM)/user(" + from + ")";
  310. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/circles+xml";
  311. mmMessage.InnerBody = new byte[0];
  312. NSMessage delPayload = new NSMessage("DEL");
  313. delPayload.InnerMessage = mmMessage;
  314. MessageProcessor.SendMessage(delPayload);
  315. lock (multiParties)
  316. {
  317. int delTransId = 0;
  318. foreach (MultipartyObject g in multiParties.Values)
  319. {
  320. if (g.MultiParty != null && g.MultiParty.Account == group.Account)
  321. {
  322. delTransId = g.TransactionID;
  323. break;
  324. }
  325. }
  326. if (delTransId != 0)
  327. multiParties.Remove(delTransId);
  328. }
  329. }
  330. #endregion
  331. #endregion
  332. #region JoinMultiparty
  333. internal void JoinMultiparty(Contact group)
  334. {
  335. if (group.ClientType == IMAddressInfoType.Circle || group.ClientType == IMAddressInfoType.TemporaryGroup)
  336. {
  337. string to = ((int)group.ClientType).ToString() + ":" + group.Account;
  338. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  339. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  340. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  341. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  342. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/circle";
  343. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/circles+xml";
  344. string xml = "<circle><roster><id>IM</id><user><id>1:" + Owner.Account + "</id></user></roster></circle>";
  345. mmMessage.InnerBody = Encoding.UTF8.GetBytes(xml);
  346. NSMessage putPayload = new NSMessage("PUT");
  347. putPayload.InnerMessage = mmMessage;
  348. MessageProcessor.SendMessage(putPayload);
  349. OnJoinedGroupChat(new GroupChatParticipationEventArgs(Owner, group));
  350. }
  351. }
  352. #endregion
  353. #endregion
  354. #region MESSAGING
  355. #region SendTypingMessage
  356. protected internal virtual void SendTypingMessage(Contact remoteContact)
  357. {
  358. string to = ((int)remoteContact.ClientType).ToString() + ":" + remoteContact.Account;
  359. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  360. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  361. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = NSMessageHandler.MachineGuid.ToString("B").ToLowerInvariant();
  362. if (remoteContact.ClientType == IMAddressInfoType.Circle)
  363. {
  364. mmMessage.RoutingHeaders[MIMERoutingHeaders.To][MIMERoutingHeaders.Path] = "IM";
  365. }
  366. if (remoteContact.Via != null)
  367. {
  368. mmMessage.RoutingHeaders[MIMERoutingHeaders.To]["via"] =
  369. ((int)remoteContact.Via.ClientType).ToString() + ":" + remoteContact.Via.Account;
  370. }
  371. mmMessage.ContentKeyVersion = "2.0";
  372. mmMessage.ContentHeaders[MIMEContentHeaders.MessageType] = MessageTypes.ControlTyping;
  373. mmMessage.InnerBody = new byte[0];
  374. NSMessage sdgPayload = new NSMessage("SDG");
  375. sdgPayload.InnerMessage = mmMessage;
  376. MessageProcessor.SendMessage(sdgPayload);
  377. }
  378. #endregion
  379. #region SendNudge
  380. protected internal virtual void SendNudge(Contact remoteContact)
  381. {
  382. string to = ((int)remoteContact.ClientType).ToString() + ":" + remoteContact.Account;
  383. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  384. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  385. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = NSMessageHandler.MachineGuid.ToString("B").ToLowerInvariant();
  386. if (remoteContact.ClientType == IMAddressInfoType.Circle)
  387. {
  388. mmMessage.RoutingHeaders[MIMERoutingHeaders.To][MIMERoutingHeaders.Path] = "IM";
  389. }
  390. if (remoteContact.Via != null)
  391. {
  392. mmMessage.RoutingHeaders[MIMERoutingHeaders.To]["via"] =
  393. ((int)remoteContact.Via.ClientType).ToString() + ":" + remoteContact.Via.Account;
  394. }
  395. mmMessage.ContentKeyVersion = "2.0";
  396. mmMessage.ContentHeaders[MIMEContentHeaders.MessageType] = MessageTypes.Nudge;
  397. mmMessage.InnerBody = Encoding.ASCII.GetBytes("\r\n");
  398. NSMessage sdgPayload = new NSMessage("SDG");
  399. sdgPayload.InnerMessage = mmMessage;
  400. MessageProcessor.SendMessage(sdgPayload);
  401. }
  402. #endregion
  403. #region SendTextMessage
  404. protected internal virtual void SendTextMessage(Contact remoteContact, TextMessage textMessage)
  405. {
  406. textMessage.PrepareMessage();
  407. string to = ((int)remoteContact.ClientType).ToString() + ":" + remoteContact.Account;
  408. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  409. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  410. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = NSMessageHandler.MachineGuid.ToString("B").ToLowerInvariant();
  411. if (remoteContact.ClientType == IMAddressInfoType.Circle)
  412. {
  413. mmMessage.RoutingHeaders[MIMERoutingHeaders.To][MIMERoutingHeaders.Path] = "IM";
  414. }
  415. else if (remoteContact.Online)
  416. {
  417. mmMessage.RoutingHeaders[MIMERoutingHeaders.ServiceChannel] = "IM/Online";
  418. }
  419. else
  420. {
  421. mmMessage.RoutingHeaders[MIMERoutingHeaders.ServiceChannel] = "IM/Offline";
  422. }
  423. if (remoteContact.Via != null)
  424. {
  425. mmMessage.RoutingHeaders[MIMERoutingHeaders.To]["via"] =
  426. ((int)remoteContact.Via.ClientType).ToString() + ":" + remoteContact.Via.Account;
  427. }
  428. mmMessage.ContentKeyVersion = "2.0";
  429. mmMessage.ContentHeaders[MIMEContentHeaders.MessageType] = MessageTypes.Text;
  430. mmMessage.ContentHeaders[MIMEHeaderStrings.X_MMS_IM_Format] = textMessage.GetStyleString();
  431. mmMessage.InnerBody = Encoding.UTF8.GetBytes(textMessage.Text);
  432. NSMessage sdgPayload = new NSMessage("SDG");
  433. sdgPayload.InnerMessage = mmMessage;
  434. MessageProcessor.SendMessage(sdgPayload);
  435. }
  436. protected internal virtual void SendOIMMessage(Contact remoteContact, TextMessage textMessage)
  437. {
  438. SendTextMessage(remoteContact, textMessage);
  439. }
  440. #endregion
  441. #region SendMobileMessage
  442. /// <summary>
  443. /// Sends a mobile message to the specified remote contact. This only works when
  444. /// the remote contact has it's mobile device enabled and has MSN-direct enabled.
  445. /// </summary>
  446. /// <param name="receiver"></param>
  447. /// <param name="text"></param>
  448. protected internal virtual void SendMobileMessage(Contact receiver, string text)
  449. {
  450. TextMessage txtMsg = new TextMessage(text);
  451. string to = ((int)receiver.ClientType).ToString() + ":" + ((receiver.ClientType == IMAddressInfoType.Telephone) ? "tel:" + receiver.Account : receiver.Account);
  452. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  453. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  454. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  455. mmMessage.RoutingHeaders[MIMERoutingHeaders.ServiceChannel] = "IM/Mobile";
  456. mmMessage.ContentKeyVersion = "2.0";
  457. mmMessage.ContentHeaders[MIMEContentHeaders.MessageType] = MessageTypes.Text;
  458. mmMessage.ContentHeaders[MIMEContentHeaders.MSIMFormat] = txtMsg.GetStyleString();
  459. mmMessage.InnerBody = Encoding.UTF8.GetBytes(txtMsg.Text);
  460. NSMessage sdgPayload = new NSMessage("SDG");
  461. sdgPayload.InnerMessage = mmMessage;
  462. MessageProcessor.SendMessage(sdgPayload);
  463. }
  464. #endregion
  465. #region SendEmoticonDefinitions
  466. protected internal virtual void SendEmoticonDefinitions(Contact remoteContact, List<Emoticon> emoticons, EmoticonType icontype)
  467. {
  468. EmoticonMessage emoticonMessage = new EmoticonMessage(emoticons, icontype);
  469. string to = ((int)remoteContact.ClientType).ToString() + ":" + remoteContact.Account;
  470. string from = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  471. MultiMimeMessage mmMessage = new MultiMimeMessage(to, from);
  472. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  473. mmMessage.ContentKeyVersion = "2.0";
  474. mmMessage.ContentHeaders[MIMEContentHeaders.MessageType] = MessageTypes.CustomEmoticon;
  475. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = icontype == EmoticonType.AnimEmoticon ? "text/x-mms-animemoticon" : "text/x-mms-emoticon";
  476. mmMessage.InnerBody = emoticonMessage.GetBytes();
  477. NSMessage sdgPayload = new NSMessage("SDG");
  478. sdgPayload.InnerMessage = mmMessage;
  479. MessageProcessor.SendMessage(sdgPayload);
  480. }
  481. #endregion
  482. #endregion
  483. #region PRESENCE
  484. #region SignoutFrom
  485. internal void SignoutFrom(Guid endPointID)
  486. {
  487. string me = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  488. MultiMimeMessage mmMessage = new MultiMimeMessage(me, me);
  489. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = MachineGuid.ToString("B").ToLowerInvariant();
  490. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  491. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/user";
  492. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/user+xml";
  493. string xml = "<user><sep n=\"IM\" epid=\"" + endPointID.ToString("B").ToLowerInvariant() + "\"/></user>";
  494. mmMessage.InnerBody = Encoding.UTF8.GetBytes(xml);
  495. NSMessage delPayload = new NSMessage("DEL");
  496. delPayload.InnerMessage = mmMessage;
  497. MessageProcessor.SendMessage(delPayload);
  498. // We will receive NFY DEL for normal users
  499. if (endPointID == MachineGuid && messageProcessor.Connected)
  500. messageProcessor.Disconnect();
  501. }
  502. #endregion
  503. #region SetScreenName & SetPersonalMessage
  504. /// <summary>
  505. /// Sets the contactlist owner's screenname. After receiving confirmation from the server
  506. /// this will set the Owner object's name which will in turn raise the NameChange event.
  507. /// </summary>
  508. internal void SetScreenName(string newName)
  509. {
  510. if (Owner == null)
  511. throw new MSNPSharpException("Not a valid owner");
  512. if (string.IsNullOrEmpty(newName))
  513. {
  514. newName = Owner.Account;
  515. }
  516. PersonalMessage pm = Owner.PersonalMessage;
  517. pm.FriendlyName = newName;
  518. SetPersonalMessage(pm);
  519. }
  520. /// <summary>
  521. /// Sets personal message.
  522. /// </summary>
  523. internal void SetPersonalMessage(PersonalMessage newPSM)
  524. {
  525. if (Owner == null)
  526. throw new MSNPSharpException("Not a valid owner");
  527. if (Owner.Status != PresenceStatus.Offline)
  528. {
  529. SetPresenceStatus(
  530. Owner.Status,
  531. Owner.LocalEndPointIMCapabilities, Owner.LocalEndPointIMCapabilitiesEx,
  532. Owner.LocalEndPointPECapabilities, Owner.LocalEndPointPECapabilitiesEx,
  533. Owner.EpName, newPSM, true);
  534. }
  535. }
  536. /// <summary>
  537. /// Sets the scene image and scheme context.
  538. /// </summary>
  539. internal void SetSceneData(SceneImage scimg, Color sccolor)
  540. {
  541. if (Owner == null)
  542. throw new MSNPSharpException("Not a valid owner");
  543. PersonalMessage pm = Owner.PersonalMessage;
  544. pm.ColorScheme = sccolor;
  545. pm.Scene = scimg.IsDefaultImage ? String.Empty : scimg.ContextPlain;
  546. SetPresenceStatus(Owner.Status,
  547. Owner.LocalEndPointIMCapabilities, Owner.LocalEndPointIMCapabilitiesEx,
  548. Owner.LocalEndPointPECapabilities, Owner.LocalEndPointPECapabilitiesEx,
  549. Owner.EpName, pm, true);
  550. }
  551. #endregion
  552. #region SetPresenceStatus
  553. /// <summary>
  554. /// Set the status of the contact list owner (the client).
  555. /// </summary>
  556. /// <remarks>You can only set the status _after_ SignedIn event. Otherwise you won't receive online notifications from other clients or the connection is closed by the server.</remarks>
  557. internal void SetPresenceStatus(
  558. PresenceStatus newStatus,
  559. ClientCapabilities newLocalIMCaps, ClientCapabilitiesEx newLocalIMCapsex,
  560. ClientCapabilities newLocalPECaps, ClientCapabilitiesEx newLocalPECapsex,
  561. string newEPName,
  562. PersonalMessage newPSM,
  563. bool forcePEservice)
  564. {
  565. if (IsSignedIn == false)
  566. throw new MSNPSharpException("Can't set status. You must wait for the SignedIn event before you can set an initial status.");
  567. if (newStatus == PresenceStatus.Offline)
  568. {
  569. SignoutFrom(MachineGuid);
  570. return;
  571. }
  572. bool setAll = (Owner.Status == PresenceStatus.Offline);
  573. if (setAll || forcePEservice ||
  574. newStatus != Owner.Status ||
  575. newLocalIMCaps != Owner.LocalEndPointIMCapabilities ||
  576. newLocalIMCapsex != Owner.LocalEndPointIMCapabilitiesEx ||
  577. newLocalPECaps != Owner.LocalEndPointPECapabilities ||
  578. newLocalPECapsex != Owner.LocalEndPointPECapabilitiesEx ||
  579. newEPName != Owner.EpName)
  580. {
  581. XmlDocument xmlDoc = new XmlDocument();
  582. XmlElement userElement = xmlDoc.CreateElement("user");
  583. // s.IM (Status, CurrentMedia)
  584. if (setAll || forcePEservice ||
  585. newStatus != Owner.Status)
  586. {
  587. XmlElement service = xmlDoc.CreateElement("s");
  588. service.SetAttribute("n", ServiceShortNames.IM.ToString());
  589. service.InnerXml =
  590. "<Status>" + ParseStatus(newStatus) + "</Status>" +
  591. "<CurrentMedia>" + MSNHttpUtility.XmlEncode(newPSM.CurrentMedia) + "</CurrentMedia>";
  592. userElement.AppendChild(service);
  593. // Don't call Owner.Status = newStatus.
  594. }
  595. // s.PE (UserTileLocation, FriendlyName, PSM, Scene, ColorScheme)
  596. if (setAll ||
  597. forcePEservice)
  598. {
  599. XmlElement service = xmlDoc.CreateElement("s");
  600. service.SetAttribute("n", ServiceShortNames.PE.ToString());
  601. service.InnerXml = newPSM.Payload;
  602. userElement.AppendChild(service);
  603. // Don't set owner.PersonalMessage here. It is replaced (with a new reference) when NFY PUT received.
  604. }
  605. // sep.IM (Capabilities)
  606. if (setAll ||
  607. newLocalIMCaps != Owner.LocalEndPointIMCapabilities ||
  608. newLocalIMCapsex != Owner.LocalEndPointIMCapabilitiesEx)
  609. {
  610. ClientCapabilities localIMCaps = setAll ? ClientCapabilities.DefaultIM : newLocalIMCaps;
  611. ClientCapabilitiesEx localIMCapsEx = setAll ? ClientCapabilitiesEx.DefaultIM : newLocalIMCapsex;
  612. XmlElement sep = xmlDoc.CreateElement("sep");
  613. sep.SetAttribute("n", ServiceShortNames.IM.ToString());
  614. XmlElement capabilities = xmlDoc.CreateElement("Capabilities");
  615. capabilities.InnerText = ((long)localIMCaps).ToString() + ":" + ((long)localIMCapsEx).ToString();
  616. sep.AppendChild(capabilities);
  617. userElement.AppendChild(sep);
  618. // Don't call Owner.LocalEndPointIMCapabilities. It is recursive call to this method.
  619. }
  620. // sep.PE (Capabilities)
  621. if (setAll ||
  622. newLocalPECaps != Owner.LocalEndPointPECapabilities ||
  623. newLocalPECapsex != Owner.LocalEndPointPECapabilitiesEx)
  624. {
  625. ClientCapabilities localPECaps = setAll ? ClientCapabilities.DefaultPE : newLocalPECaps;
  626. ClientCapabilitiesEx localPECapsEx = setAll ? ClientCapabilitiesEx.DefaultPE : newLocalPECapsex;
  627. XmlElement sep = xmlDoc.CreateElement("sep");
  628. sep.SetAttribute("n", ServiceShortNames.PE.ToString());
  629. XmlElement VER = xmlDoc.CreateElement("VER");
  630. VER.InnerText = Credentials.ClientInfo.MessengerClientName + ":" + Credentials.ClientInfo.MessengerClientBuildVer;
  631. sep.AppendChild(VER);
  632. XmlElement TYP = xmlDoc.CreateElement("TYP");
  633. TYP.InnerText = "1";
  634. sep.AppendChild(TYP);
  635. XmlElement capabilities = xmlDoc.CreateElement("Capabilities");
  636. capabilities.InnerText = ((long)localPECaps).ToString() + ":" + ((long)localPECapsEx).ToString();
  637. sep.AppendChild(capabilities);
  638. userElement.AppendChild(sep);
  639. // Don't call Owner.LocalEndPointPECapabilities. It is recursive call to this method.
  640. }
  641. // sep.PD (EpName, State)
  642. if (setAll ||
  643. newEPName != Owner.EpName ||
  644. newStatus != Owner.Status)
  645. {
  646. XmlElement sep = xmlDoc.CreateElement("sep");
  647. sep.SetAttribute("n", ServiceShortNames.PD.ToString());
  648. XmlElement clientType = xmlDoc.CreateElement("ClientType");
  649. clientType.InnerText = "1";
  650. sep.AppendChild(clientType);
  651. XmlElement epName = xmlDoc.CreateElement("EpName");
  652. epName.InnerText = MSNHttpUtility.XmlEncode(newEPName);
  653. sep.AppendChild(epName);
  654. XmlElement idle = xmlDoc.CreateElement("Idle");
  655. idle.InnerText = ((newStatus == PresenceStatus.Idle) ? "true" : "false");
  656. sep.AppendChild(idle);
  657. XmlElement state = xmlDoc.CreateElement("State");
  658. state.InnerText = ParseStatus(newStatus);
  659. sep.AppendChild(state);
  660. userElement.AppendChild(sep);
  661. // Don't set Owner.EpName. It is recursive call to this method.
  662. }
  663. if (userElement.HasChildNodes)
  664. {
  665. string xml = userElement.OuterXml;
  666. string me = ((int)Owner.ClientType).ToString() + ":" + Owner.Account;
  667. MultiMimeMessage mmMessage = new MultiMimeMessage(me, me);
  668. mmMessage.RoutingHeaders[MIMERoutingHeaders.From][MIMERoutingHeaders.EPID] = NSMessageHandler.MachineGuid.ToString("B").ToLowerInvariant();
  669. mmMessage.Stream = 1;
  670. mmMessage.ReliabilityHeaders[MIMEReliabilityHeaders.Flags] = "ACK";
  671. mmMessage.ContentKey = MIMEContentHeaders.Publication;
  672. mmMessage.ContentHeaders[MIMEContentHeaders.URI] = "/user";
  673. mmMessage.ContentHeaders[MIMEContentHeaders.ContentType] = "application/user+xml";
  674. mmMessage.InnerBody = System.Text.Encoding.UTF8.GetBytes(xml);
  675. NSMessage nsMessage = new NSMessage("PUT");
  676. nsMessage.InnerMessage = mmMessage;
  677. MessageProcessor.SendMessage(nsMessage);
  678. }
  679. }
  680. }
  681. #endregion
  682. #endregion
  683. #region COMMAND HANDLERS (PUT, DEL, NFY, SDG)
  684. #region OnPUTReceived
  685. /// <summary>
  686. /// Called when a PUT command message has been received.
  687. /// </summary>
  688. /// <param name="message"></param>
  689. protected virtual void OnPUTReceived(NSMessage message)
  690. {
  691. bool ok = message.CommandValues.Count > 0 && message.CommandValues[0].ToString() == "OK";
  692. if (multiParties.ContainsKey(message.TransactionID))
  693. {
  694. if (ok == false || message.InnerBody == null || message.InnerBody.Length == 0)
  695. {
  696. lock (multiParties)
  697. multiParties.Remove(message.TransactionID);
  698. return;
  699. }
  700. MultiMimeMessage mmMessage = new MultiMimeMessage(message.InnerBody);
  701. string[] tempGroup = mmMessage.From.Value.Split(':');
  702. IMAddressInfoType addressType = (IMAddressInfoType)int.Parse(tempGroup[0]);
  703. if (addressType == IMAddressInfoType.TemporaryGroup)
  704. {
  705. Contact group = new Contact(tempGroup[1].ToLowerInvariant(), IMAddressInfoType.TemporaryGroup, this);
  706. group.ContactList = new ContactList(new Guid(tempGroup[1].ToLowerInvariant().Split('@')[0]), null, group, this);
  707. MultipartyObject mpo = multiParties[message.TransactionID];
  708. mpo.TransactionID = message.TransactionID;
  709. mpo.MultiParty = group;
  710. JoinMultiparty(group);
  711. List<string> copy = new List<string>(mpo.InviteQueueHash);
  712. foreach (string siblingHash in copy)
  713. {
  714. string[] addressTypeAndAccount = siblingHash.Split(new char[] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries);
  715. Contact contact = ContactList.GetContactWithCreate(addressTypeAndAccount[1], (IMAddressInfoType)Enum.Parse(typeof(IMAddressInfoType), addressTypeAndAccount[0].ToString()));
  716. InviteContactToMultiparty(contact, group);
  717. }
  718. mpo.OnMultipartyCreatedLocally(this, new MultipartyCreatedEventArgs(group));
  719. group.SetStatus(PresenceStatus.Online);
  720. Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "MultipartyCreated: " + group.Account);
  721. }
  722. else
  723. {
  724. lock (multiParties)
  725. multiParties.Remove(message.TransactionID);
  726. }
  727. }
  728. }
  729. #endregion
  730. #region OnDELReceived
  731. /// <summary>
  732. /// Called when a DEL command message has been received.
  733. /// </summary>
  734. /// <param name="message"></param>
  735. protected virtual void OnDELReceived(NSMessage message)
  736. {
  737. bool ok = message.CommandValues.Count > 0 && message.CommandValues[0].ToString() == "OK";
  738. if (ok)
  739. {
  740. Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "DEL command accepted", GetType().Name);
  741. }
  742. }
  743. #endregion
  744. #region OnNFYReceived
  745. private void OnNFYPUTReceived(MultiMimeMessage multiMimeMessage, RoutingInfo routingInfo)
  746. {
  747. switch (multiMimeMessage.ContentHeaders[MIMEContentHeaders.ContentType].Value)
  748. {
  749. #region user xml
  750. case "application/user+xml":
  751. {
  752. if (multiMimeMessage.ContentHeaders[MIMEHeaderStrings.NotifType].Value == "Sync")
  753. {
  754. if (routingInfo.SenderGateway != null && routingInfo.SenderGateway.ClientType == IMAddressInfoType.Circle)
  755. {
  756. JoinMultiparty(routingInfo.SenderGateway);
  757. }
  758. //Sync the contact in contact list with the contact in gateway.
  759. // TODO: Set the NSMessagehandler.ContactList contact to the gateway
  760. // TODO: triger the ContactOnline event for the gateway contact.
  761. //Just wait for my fix.
  762. }
  763. if (multiMimeMessage.InnerBody == null || multiMimeMessage.InnerBody.Length == 0)
  764. return; //No xml content.
  765. if (multiMimeMessage.ContentHeaders[MIMEHeaderStrings.NotifType].Value == "Full")
  766. {
  767. //This is an initial NFY
  768. }
  769. XmlDocument xmlDoc = new XmlDocument();
  770. xmlDoc.LoadXml(Encoding.UTF8.GetString(multiMimeMessage.InnerBody));
  771. XmlNodeList services = xmlDoc.SelectNodes("//user/s");
  772. XmlNodeList serviceEndPoints = xmlDoc.SelectNodes("//user/sep");
  773. if (services.Count > 0)
  774. {
  775. foreach (XmlNode service in services)
  776. {
  777. ServiceShortNames serviceEnum = (ServiceShortNames)Enum.Parse(typeof(ServiceShortNames), service.Attributes["n"].Value);
  778. switch (serviceEnum)
  779. {
  780. case ServiceShortNames.IM:
  781. {
  782. foreach (XmlNode node in service.ChildNodes)
  783. {
  784. switch (node.Name)
  785. {
  786. case "Status":
  787. if (routingInfo.FromOwner && IsSignedIn == false)
  788. {
  789. // We have already signed in another place, but not here...
  790. // Don't set status... This place will set the status later.
  791. return;
  792. }
  793. PresenceStatus oldStatus = routingInfo.Sender.Status;
  794. PresenceStatus newStatus = ParseStatus(node.InnerText);
  795. routingInfo.Sender.SetStatus(newStatus);
  796. OnContactStatusChanged(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  797. OnContactOnline(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  798. break;
  799. case "CurrentMedia":
  800. //MSNP21TODO: UBX implementation
  801. break;
  802. }
  803. }
  804. break;
  805. }
  806. case ServiceShortNames.PE:
  807. {
  808. // Create a new reference to fire PersonalMessageChanged event.
  809. PersonalMessage personalMessage = new PersonalMessage(service.ChildNodes);
  810. if (!String.IsNullOrEmpty(personalMessage.Payload) &&
  811. routingInfo.Sender.PersonalMessage != personalMessage)
  812. {
  813. // FriendlyName
  814. if (!String.IsNullOrEmpty(personalMessage.FriendlyName))
  815. {
  816. //Only Windows Live Messenger Contact has friendly name.
  817. routingInfo.Sender.SetName(personalMessage.FriendlyName);
  818. }
  819. // UserTileLocation
  820. if (!String.IsNullOrEmpty(personalMessage.UserTileLocation) && routingInfo.Sender.UserTileLocation != personalMessage.UserTileLocation)
  821. {
  822. routingInfo.Sender.UserTileLocation = personalMessage.UserTileLocation;
  823. routingInfo.Sender.FireDisplayImageContextChangedEvent(personalMessage.UserTileLocation);
  824. }
  825. // Scene
  826. if (!String.IsNullOrEmpty(personalMessage.Scene))
  827. {
  828. if (routingInfo.Sender.SceneContext != personalMessage.Scene)
  829. {
  830. routingInfo.Sender.SceneContext = personalMessage.Scene;
  831. routingInfo.Sender.FireSceneImageContextChangedEvent(personalMessage.Scene);
  832. }
  833. }
  834. // ColorScheme
  835. if (personalMessage.ColorScheme != Color.Empty)
  836. {
  837. if (routingInfo.Sender.ColorScheme != personalMessage.ColorScheme)
  838. {
  839. routingInfo.Sender.ColorScheme = personalMessage.ColorScheme;
  840. routingInfo.Sender.OnColorSchemeChanged();
  841. }
  842. }
  843. // This must be final...
  844. routingInfo.Sender.PersonalMessage = personalMessage;
  845. }
  846. break;
  847. }
  848. case ServiceShortNames.PF:
  849. {
  850. // Profile Annotation, it is AB.Me.annotations/Live.Profile.Expression.LastChanged
  851. // <user><s n="PF" ts="2011-04-16T06:00:58Z"></s></user>
  852. if (routingInfo.FromOwner)
  853. {
  854. DateTime ts = WebServiceDateTimeConverter.ConvertToDateTime(service.Attributes["ts"].Value);
  855. }
  856. break;
  857. }
  858. }
  859. }
  860. }
  861. if (serviceEndPoints.Count > 0)
  862. {
  863. foreach (XmlNode serviceEndPoint in serviceEndPoints)
  864. {
  865. ServiceShortNames serviceEnum = (ServiceShortNames)Enum.Parse(typeof(ServiceShortNames), serviceEndPoint.Attributes["n"].Value);
  866. Guid epid = serviceEndPoint.Attributes["epid"] == null ? Guid.Empty : new Guid(serviceEndPoint.Attributes["epid"].Value);
  867. if (!routingInfo.Sender.EndPointData.ContainsKey(epid))
  868. {
  869. lock (routingInfo.Sender.SyncObject)
  870. routingInfo.Sender.EndPointData.Add(epid, routingInfo.FromOwner ? new PrivateEndPointData(routingInfo.Sender.Account, epid) : new EndPointData(routingInfo.Sender.Account, epid));
  871. }
  872. switch (serviceEnum)
  873. {
  874. case ServiceShortNames.IM:
  875. {
  876. foreach (XmlNode node in serviceEndPoint.ChildNodes)
  877. {
  878. switch (node.Name)
  879. {
  880. case "Capabilities":
  881. ClientCapabilities cap = ClientCapabilities.None;
  882. ClientCapabilitiesEx capEx = ClientCapabilitiesEx.None;
  883. string[] caps = node.InnerText.Split(':');
  884. if (caps.Length > 1)
  885. {
  886. capEx = (ClientCapabilitiesEx)long.Parse(caps[1]);
  887. }
  888. cap = (ClientCapabilities)long.Parse(caps[0]);
  889. routingInfo.Sender.EndPointData[epid].IMCapabilities = cap;
  890. routingInfo.Sender.EndPointData[epid].IMCapabilitiesEx = capEx;
  891. break;
  892. }
  893. }
  894. break;
  895. }
  896. case ServiceShortNames.PE:
  897. {
  898. foreach (XmlNode node in serviceEndPoint.ChildNodes)
  899. {
  900. switch (node.Name)
  901. {
  902. case "Capabilities":
  903. ClientCapabilities cap = ClientCapabilities.None;
  904. ClientCapabilitiesEx capEx = ClientCapabilitiesEx.None;
  905. string[] caps = node.InnerText.Split(':');
  906. if (caps.Length > 1)
  907. {
  908. capEx = (ClientCapabilitiesEx)long.Parse(caps[1]);
  909. }
  910. cap = (ClientCapabilities)long.Parse(caps[0]);
  911. routingInfo.Sender.EndPointData[epid].PECapabilities = cap;
  912. routingInfo.Sender.EndPointData[epid].PECapabilitiesEx = capEx;
  913. break;
  914. }
  915. }
  916. routingInfo.Sender.SetChangedPlace(new PlaceChangedEventArgs(routingInfo.Sender.EndPointData[epid], PlaceChangedReason.SignedIn));
  917. break;
  918. }
  919. case ServiceShortNames.PD:
  920. {
  921. PrivateEndPointData privateEndPoint = routingInfo.Sender.EndPointData[epid] as PrivateEndPointData;
  922. foreach (XmlNode node in serviceEndPoint.ChildNodes)
  923. {
  924. switch (node.Name)
  925. {
  926. case "ClientType":
  927. privateEndPoint.ClientType = node.InnerText;
  928. break;
  929. case "EpName":
  930. privateEndPoint.Name = node.InnerText;
  931. break;
  932. case "Idle":
  933. privateEndPoint.Idle = bool.Parse(node.InnerText);
  934. break;
  935. case "State":
  936. privateEndPoint.State = ParseStatus(node.InnerText);
  937. break;
  938. }
  939. }
  940. Owner.SetChangedPlace(new PlaceChangedEventArgs(privateEndPoint, PlaceChangedReason.SignedIn));
  941. break;
  942. }
  943. }
  944. }
  945. }
  946. }
  947. break;
  948. #endregion
  949. #region circles xml
  950. case "application/circles+xml":
  951. {
  952. if (routingInfo.SenderType == IMAddressInfoType.Circle)
  953. {
  954. Contact circle = ContactList.GetCircle(routingInfo.SenderAccount);
  955. if (circle == null)
  956. {
  957. Trace.WriteLineIf(Settings.TraceSwitch.TraceError,
  958. "[OnNFYReceived] Cannot complete the operation since circle not found: " + multiMimeMessage.From.ToString());
  959. return;
  960. }
  961. if (multiMimeMessage.InnerBody == null || multiMimeMessage.InnerBody.Length == 0 ||
  962. "<circle></circle>" == Encoding.UTF8.GetString(multiMimeMessage.InnerBody))
  963. {
  964. // No xml content and full notify... Circle goes online...
  965. if (multiMimeMessage.ContentHeaders[MIMEHeaderStrings.NotifType].Value == "Full")
  966. {
  967. PresenceStatus oldStatus = circle.Status;
  968. PresenceStatus newStatus = PresenceStatus.Online;
  969. circle.SetStatus(newStatus);
  970. // The contact changed status
  971. OnContactStatusChanged(new ContactStatusChangedEventArgs(circle, oldStatus, newStatus));
  972. // The contact goes online
  973. OnContactOnline(new ContactStatusChangedEventArgs(circle, oldStatus, newStatus));
  974. }
  975. return;
  976. }
  977. XmlDocument xmlDoc = new XmlDocument();
  978. xmlDoc.LoadXml(Encoding.UTF8.GetString(multiMimeMessage.InnerBody));
  979. XmlNodeList ids = xmlDoc.SelectNodes("//circle/roster/user/id");
  980. if (ids.Count == 0)
  981. {
  982. return; //I hate indent.
  983. }
  984. foreach (XmlNode node in ids)
  985. {
  986. IMAddressInfoType accountAddressType;
  987. string account;
  988. IMAddressInfoType viaAccountAddressType;
  989. string viaAccount;
  990. string fullAccount = node.InnerText;
  991. if (false == Contact.ParseFullAccount(fullAccount,
  992. out accountAddressType, out account,
  993. out viaAccountAddressType, out viaAccount))
  994. {
  995. continue;
  996. }
  997. if (account == Owner.Account)
  998. continue;
  999. if (circle.ContactList.HasContact(account, accountAddressType))
  1000. {
  1001. Contact contact = circle.ContactList.GetContact(account, accountAddressType);
  1002. OnJoinedGroupChat(new GroupChatParticipationEventArgs(contact, circle));
  1003. }
  1004. }
  1005. }
  1006. else if (routingInfo.SenderType == IMAddressInfoType.TemporaryGroup)
  1007. {
  1008. MultipartyObject mpo = GetMultipartyObject(routingInfo.SenderAccount);
  1009. Contact group = null;
  1010. if (mpo == null)
  1011. {
  1012. // Created remotely.
  1013. NSMessageProcessor nsmp = (NSMessageProcessor)MessageProcessor;
  1014. int transId = nsmp.IncreaseTransactionID();
  1015. group = new Contact(routingInfo.SenderAccount, IMAddressInfoType.TemporaryGroup, this);
  1016. group.ContactList = new ContactList(new Guid(routingInfo.SenderAccount.Split('@')[0]), null, group, this);
  1017. mpo = new MultipartyObject(transId, new List<string>(), group, null);
  1018. lock (multiParties)
  1019. multiParties[transId] = mpo;
  1020. OnMultipartyCreatedRemotely(new MultipartyCreatedEventArgs(group));
  1021. group.SetStatus(PresenceStatus.Online);
  1022. }
  1023. else
  1024. {
  1025. group = mpo.MultiParty;
  1026. }
  1027. if (multiMimeMessage.InnerBody == null || multiMimeMessage.InnerBody.Length == 0)
  1028. {
  1029. // No xml content and full notify... Circle goes online...
  1030. if (multiMimeMessage.ContentHeaders[MIMEHeaderStrings.NotifType].Value == "Full")
  1031. {
  1032. PresenceStatus oldStatus = group.Status;
  1033. PresenceStatus newStatus = PresenceStatus.Online;
  1034. group.SetStatus(newStatus);
  1035. // The contact changed status
  1036. OnContactStatusChanged(new ContactStatusChangedEventArgs(group, oldStatus, newStatus));
  1037. // The contact goes online
  1038. OnContactOnline(new ContactStatusChangedEventArgs(group, oldStatus, newStatus));
  1039. }
  1040. return;
  1041. }
  1042. // Join multiparty if state is Pending
  1043. XmlDocument xmlDoc = new XmlDocument();
  1044. xmlDoc.LoadXml(Encoding.UTF8.GetString(multiMimeMessage.InnerBody));
  1045. XmlNodeList rosters = xmlDoc.SelectNodes("//circle/roster/user");
  1046. foreach (XmlNode roster in rosters)
  1047. {
  1048. string state = (roster["state"] == null) ? string.Empty : roster["state"].InnerText;
  1049. string[] fullAccount = roster["id"].InnerText.Split(':');
  1050. IMAddressInfoType addressType = (IMAddressInfoType)int.Parse(fullAccount[0]);
  1051. string memberAccount = fullAccount[1].ToLowerInvariant();
  1052. // Me contact
  1053. if ("pending" == state.ToLowerInvariant() &&
  1054. addressType == Owner.ClientType &&
  1055. memberAccount == Owner.Account)
  1056. {
  1057. JoinMultiparty(group);
  1058. }
  1059. else
  1060. {
  1061. Contact part = group.ContactList.GetContactWithCreate(memberAccount, addressType);
  1062. Contact real = ContactList.GetContactWithCreate(memberAccount, addressType);
  1063. part.SetStatus(real.Status);
  1064. OnJoinedGroupChat(new GroupChatParticipationEventArgs(part, group));
  1065. if (mpo.InviteQueueHash.Contains(part.SiblingString))
  1066. mpo.InviteQueueHash.Remove(part.SiblingString);
  1067. }
  1068. }
  1069. }
  1070. }
  1071. break;
  1072. #endregion
  1073. #region network xml
  1074. case "application/network+xml":
  1075. {
  1076. if (routingInfo.Sender.ClientType == IMAddressInfoType.RemoteNetwork &&
  1077. routingInfo.Sender.Account == RemoteNetworkGateways.FaceBookGatewayAccount)
  1078. {
  1079. string status = Encoding.UTF8.GetString(multiMimeMessage.InnerBody);
  1080. PresenceStatus oldStatus = routingInfo.Sender.Status;
  1081. PresenceStatus newStatus = PresenceStatus.Unknown;
  1082. if (status.Contains("SignedIn"))
  1083. newStatus = PresenceStatus.Online;
  1084. else if (status.Contains("SignedOut"))
  1085. newStatus = PresenceStatus.Offline;
  1086. if (newStatus != PresenceStatus.Unknown)
  1087. {
  1088. routingInfo.Sender.SetStatus(newStatus);
  1089. // The contact changed status
  1090. OnContactStatusChanged(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  1091. if (newStatus == PresenceStatus.Online)
  1092. OnContactOnline(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  1093. else
  1094. OnContactOffline(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  1095. }
  1096. }
  1097. }
  1098. break;
  1099. #endregion
  1100. }
  1101. }
  1102. private void OnNFYDELReceived(MultiMimeMessage multiMimeMessage, RoutingInfo routingInfo)
  1103. {
  1104. switch (multiMimeMessage.ContentHeaders[MIMEContentHeaders.ContentType].Value)
  1105. {
  1106. #region user xml
  1107. case "application/user+xml":
  1108. {
  1109. if (multiMimeMessage.InnerBody == null || multiMimeMessage.InnerBody.Length == 0)
  1110. return; //No xml content.
  1111. if (multiMimeMessage.ContentHeaders[MIMEHeaderStrings.NotifType].Value == "Full")
  1112. {
  1113. //This is an initial NFY
  1114. }
  1115. XmlDocument xmlDoc = new XmlDocument();
  1116. xmlDoc.LoadXml(Encoding.UTF8.GetString(multiMimeMessage.InnerBody));
  1117. XmlNodeList services = xmlDoc.SelectNodes("//user/s");
  1118. XmlNodeList serviceEndPoints = xmlDoc.SelectNodes("//user/sep");
  1119. if (serviceEndPoints.Count > 0)
  1120. {
  1121. foreach (XmlNode serviceEndPoint in serviceEndPoints)
  1122. {
  1123. ServiceShortNames serviceEnum = (ServiceShortNames)Enum.Parse(typeof(ServiceShortNames), serviceEndPoint.Attributes["n"].Value);
  1124. Guid epid = serviceEndPoint.Attributes["epid"] == null ? Guid.Empty : new Guid(serviceEndPoint.Attributes["epid"].Value);
  1125. switch (serviceEnum)
  1126. {
  1127. case ServiceShortNames.IM:
  1128. case ServiceShortNames.PD:
  1129. {
  1130. if (routingInfo.Sender.EndPointData.ContainsKey(epid))
  1131. {
  1132. routingInfo.Sender.SetChangedPlace(new PlaceChangedEventArgs(routingInfo.Sender.EndPointData[epid], PlaceChangedReason.SignedOut));
  1133. }
  1134. if (routingInfo.FromOwner && epid == MachineGuid &&
  1135. messageProcessor != null && messageProcessor.Connected)
  1136. {
  1137. // Just disconnect
  1138. messageProcessor.Disconnect();
  1139. }
  1140. break;
  1141. }
  1142. }
  1143. }
  1144. }
  1145. if (services.Count > 0)
  1146. {
  1147. foreach (XmlNode service in services)
  1148. {
  1149. ServiceShortNames serviceEnum = (ServiceShortNames)Enum.Parse(typeof(ServiceShortNames), service.Attributes["n"].Value);
  1150. switch (serviceEnum)
  1151. {
  1152. case ServiceShortNames.IM:
  1153. {
  1154. PresenceStatus oldStatus = routingInfo.Sender.Status;
  1155. PresenceStatus newStatus = PresenceStatus.Offline;
  1156. routingInfo.Sender.SetStatus(newStatus);
  1157. OnContactStatusChanged(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  1158. OnContactOffline(new ContactStatusChangedEventArgs(routingInfo.Sender, routingInfo.SenderGateway, oldStatus, newStatus));
  1159. break;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. }
  1165. break;
  1166. #endregion
  1167. #region circles xml
  1168. case "application/circles+xml":
  1169. {
  1170. Contact circle = null;
  1171. Contact group = null;
  1172. if (routingInfo.SenderType == IMAddressInfoType.Circle)
  1173. {
  1174. circle = ContactList.GetCircle(routingInfo.SenderAccount);
  1175. if (circle == null)
  1176. {
  1177. Trace.WriteLineIf(Settings.TraceSwitch.TraceError,
  1178. "[OnNFYReceived] Cannot complete the operation since circle not found: " + multiMimeMessage.From.ToString());
  1179. return;
  1180. }
  1181. }
  1182. else if (routingInfo.SenderType == IMAddressInfoType.TemporaryGroup)
  1183. {
  1184. group = GetMultiparty(routingInfo.SenderAccount);
  1185. if (group == null)
  1186. {
  1187. Trace.WriteLineIf(Settings.TraceSwitch.TraceError,
  1188. "[OnNFYReceived] temp group not found: " + multiMimeMessage.From.ToString());
  1189. return;
  1190. }
  1191. }
  1192. else
  1193. {
  1194. Trace.WriteLineIf(Settings.TraceSwitch.TraceError,
  1195. "[OnNFYReceived] sender is not circle nor temp group: " + multiMimeMessage.From.ToString());
  1196. return;
  1197. }
  1198. if (multiMimeMessage.ContentHeaders.ContainsKey(MIMEHeaderStrings.Uri))
  1199. {
  1200. string xpathUri = multiMimeMessage.ContentHeaders[MIMEHeaderStrings.Uri].ToString();
  1201. if (xpathUri.Contains("/circle/roster(IM)/user"))
  1202. {
  1203. string typeAccount = xpathUri.Substring("/circle/roster(IM)/user".Length);
  1204. typeAccount = typeAccount.Substring(typeAccount.IndexOf("(") + 1);
  1205. typeAccount = typeAccount.Substring(0, typeAccount.IndexOf(")"));
  1206. string[] member = typeAccount.Split(':');
  1207. string memberAccount = member[1];
  1208. IMAddressInfoType memberNetwork = (IMAddressInfoType)int.Parse(member[0]);
  1209. Contact c = null;
  1210. if (circle != null)
  1211. {
  1212. if (!circle.ContactList.HasContact(memberAccount, memberNetwork))
  1213. return;
  1214. c = circle.ContactList.GetContact(memberAccount, memberNetwork);
  1215. OnLeftGroupChat(new GroupChatParticipationEventArgs(c, circle));
  1216. }
  1217. if (group != null)
  1218. {
  1219. if (!group.ContactList.HasContact(memberAccount, memberNetwork))
  1220. return;
  1221. c = group.ContactList.GetContact(memberAccount, memberNetwork);
  1222. group.ContactList.Remove(memberAccount, memberNetwork);
  1223. OnLeftGroupChat(new GroupChatParticipationEventArgs(c, group));
  1224. }
  1225. }
  1226. else
  1227. {
  1228. Contact goesOfflineGroup = null;
  1229. if (circle != null)
  1230. goesOfflineGroup = circle;
  1231. else if (group != null)
  1232. goesOfflineGroup = group;
  1233. // Group goes offline...
  1234. if (goesOfflineGroup != null)
  1235. {
  1236. PresenceStatus oldStatus = goesOfflineGroup.Status;
  1237. PresenceStatus newStatus = PresenceStatus.Offline;
  1238. goesOfflineGroup.SetStatus(newStatus);
  1239. // the contact changed status
  1240. OnContactStatusChanged(new ContactStatusChangedEventArgs(goesOfflineGroup, routingInfo.SenderGateway, oldStatus, newStatus));
  1241. // the contact goes offline
  1242. OnContactOffline(new ContactStatusChangedEventArgs(goesOfflineGroup, routingInfo.SenderGateway, oldStatus, newStatus));
  1243. }
  1244. }
  1245. }
  1246. }
  1247. break;
  1248. #endregion
  1249. #region network xml
  1250. case "application/network+xml":
  1251. {
  1252. }
  1253. break;
  1254. #endregion
  1255. }
  1256. }
  1257. /// <summary>
  1258. /// Called when a NFY command has been received.
  1259. /// <code>
  1260. /// NFY [TransactionID] [Operation: PUT|DEL] [Payload Length]\r\n[Payload Data]
  1261. /// </code>
  1262. /// </summary>
  1263. /// <param name="message"></param>
  1264. protected virtual void OnNFYReceived(NSMessage message)
  1265. {
  1266. NetworkMessage networkMessage = message as NetworkMessage;
  1267. if (networkMessage.InnerBody == null || networkMessage.InnerBody.Length == 0)
  1268. return;
  1269. //PUT or DEL
  1270. string command = message.CommandValues[0].ToString();
  1271. MultiMimeMessage multiMimeMessage = new MultiMimeMessage(networkMessage.InnerBody);
  1272. if (!(multiMimeMessage.ContentHeaders.ContainsKey(MIMEContentHeaders.ContentType)))
  1273. return;
  1274. RoutingInfo routingInfo = RoutingInfo.FromMultiMimeMessage(multiMimeMessage, this);
  1275. if (routingInfo == null)
  1276. {
  1277. Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnNFYReceived] Get Rounting Info Error.");
  1278. return;
  1279. }
  1280. if (command == "PUT")
  1281. {
  1282. OnNFYPUTReceived(multiMimeMessage, routingInfo);
  1283. }
  1284. else if (command == "DEL")
  1285. {
  1286. OnNFYDELReceived(multiMimeMessage, routingInfo);
  1287. }
  1288. }
  1289. #endregion
  1290. #region OnSDGReceived
  1291. protected virtual NetworkMessage ParseSDGMessage(NSMessage nsMessage)
  1292. {
  1293. MultiMimeMessage multiMimeMessage = new MultiMimeMessage();
  1294. multiMimeMessage.CreateFromParentMessage(nsMessage);
  1295. if (multiMimeMessage.ContentHeaders.ContainsKey(MIMEContentHeaders.MessageType))
  1296. {
  1297. switch (multiMimeMessage.ContentHeaders[MIMEContentHeaders.MessageType].ToString())
  1298. {
  1299. default:
  1300. Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning,
  1301. "[OnSDGReceived] Cannot parse this type of SDG message: \r\n" + multiMimeMessage.ContentHeaders[MIMEContentHeaders.MessageType].ToString() +
  1302. "\r\n\r\nMessage Body: \r\n\r\n" + multiMimeMessage.ToDebugString());
  1303. break;
  1304. case MessageTypes.Nudge:
  1305. case MessageTypes.ControlTyping:
  1306. case MessageTypes.Wink:
  1307. case MessageTypes.SignalCloseIMWindow:
  1308. // Pure Text body, nothing to parse.
  1309. ParseSDGTextPayloadMessage(multiMimeMessage);
  1310. break;
  1311. case MessageTypes.Text:
  1312. // Set the TextMessage as its InnerMessage.
  1313. ParseSDGTextMessage(multiMimeMessage);
  1314. break;
  1315. case MessageTypes.CustomEmoticon:
  1316. // Set the EmoticonMessage as its InnerMessage.
  1317. ParseSDGCustomEmoticonMessage(multiMimeMessage);
  1318. break;
  1319. case MessageTypes.SignalP2P:
  1320. // Add the SLPMessage as its InnerMessage.
  1321. ParseSDGP2PSignalMessage(multiMimeMessage);
  1322. break;
  1323. case MessageTypes.Data:
  1324. //OnSDGDataMessageReceived(multiMimeMessage, sender, by, routingInfo);
  1325. break;
  1326. }
  1327. }
  1328. return nsMessage;
  1329. }
  1330. //This is actually another OnMSGxxx
  1331. /// <summary>
  1332. /// Called when a SDG command has been received.
  1333. /// <remarks>Indicates that someone send us a message.</remarks>
  1334. /// <code>
  1335. /// SDG 0 [Payload Length]\r\n[Payload Data]
  1336. /// </code>
  1337. /// </summary>
  1338. /// <param name="message"></param>
  1339. protected virtual void OnSDGReceived(NSMessage message)
  1340. {
  1341. if (message.InnerBody == null || (message.InnerMessage is MultiMimeMessage) == false)
  1342. {
  1343. // This is not an SDG MultiMimeMessage message
  1344. return;
  1345. }
  1346. MultiMimeMessage multiMimeMessage = message.InnerMessage as MultiMimeMessage;
  1347. #region Get the Routing Info
  1348. RoutingInfo routingInfo = RoutingInfo.FromMultiMimeMessage(multiMimeMessage, this);
  1349. if (routingInfo == null)
  1350. {
  1351. Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnSDGReceived] Get Rounting Info Error.");
  1352. return;
  1353. }
  1354. Contact sender = null; // via=fb, circle or temporary group
  1355. Contact originalSender = null; // invidiual sender, 1 on 1 chat
  1356. if (routingInfo.ReceiverType == IMAddressInfoType.Circle ||
  1357. routingInfo.ReceiverType == IMAddressInfoType.TemporaryGroup)
  1358. {
  1359. sender = routingInfo.Receiver;
  1360. if (sender == null)
  1361. {
  1362. Trace.WriteLineIf(Settings.TraceSwitch.TraceError,
  1363. "[OnSDGReceived] Error: Cannot find group: " + multiMimeMessage.To.ToString());
  1364. return;
  1365. }
  1366. originalSender = routingInfo.Sender;
  1367. }
  1368. // External Network
  1369. if (originalSender == null && routingInfo.SenderGateway != null)
  1370. {
  1371. originalSender = routingInfo.SenderGateway;
  1372. sender = routingInfo.Sender;
  1373. }
  1374. if (originalSender == null)
  1375. {
  1376. sender = routingInfo.Sender;
  1377. originalSender = sender;
  1378. }
  1379. #endregion
  1380. if (multiMimeMessage.ContentHeaders.ContainsKey(MIMEContentHeaders.MessageType))
  1381. {
  1382. switch (multiMimeMessage.ContentHeaders[MIMEContentHeaders.MessageType].ToString())
  1383. {
  1384. default:
  1385. Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning,
  1386. "[OnSDGReceived] UNHANDLED MESSAGE TYPE: \r\n" + multiMimeMessage.ContentHeaders[MIMEContentHeaders.MessageType].ToString() +
  1387. "\r\n\r\nMessage Body: \r\n\r\n" + multiMimeMessage.ToDebugString());
  1388. break;
  1389. case MessageTypes.Nudge:
  1390. OnNudgeReceived(new NudgeArrivedEventArgs(sender, originalSender, routingInfo));
  1391. break;
  1392. case MessageTypes.ControlTyping:
  1393. OnTypingMessageReceived(new TypingArrivedEventArgs(sender, originalSender, routingInfo));
  1394. break;
  1395. case MessageTypes.Text:
  1396. OnSDGTextMessageReceived(multiMimeMessage, sender, originalSender, routingInfo);
  1397. break;
  1398. case MessageTypes.CustomEmoticon:
  1399. OnSDGCustomEmoticonReceived(multiMimeMessage, sender, originalSender, routingInfo);
  1400. break;
  1401. case MessageTypes.Wink:
  1402. OnSDGWinkReceived(multiMimeMessage, sender, originalSender, routingInfo);
  1403. break;
  1404. case MessageTypes.SignalP2P:
  1405. OnSDGP2PSignalReceived(multiMimeMessage, sender, originalSender, routingInfo);
  1406. break;
  1407. case MessageTypes.SignalCloseIMWindow:
  1408. OnSDGCloseIMWindowReceived(multiMimeMessage, routingInfo);
  1409. break;
  1410. case MessageTypes.Data:
  1411. OnSDGDataMessageReceived(multiMimeMessage, sender, originalSender, routingInfo);
  1412. break;
  1413. }
  1414. }
  1415. }
  1416. #region Process SDG Messages
  1417. //Note: Don't make these function protected.
  1418. private void OnSDGCloseIMWindowReceived(MultiMimeMessage multiMimeMessage, RoutingInfo routingInfo)
  1419. {
  1420. string partiesString = (multiMimeMessage.InnerMessage as TextPayloadMessage).Text;
  1421. if (string.IsNullOrEmpty(partiesString))
  1422. return;
  1423. string[] parties = partiesString.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
  1424. IMAddressInfoType addressInfo = IMAddressInfoType.None;
  1425. string account = string.Empty;
  1426. List<Contact> partiesList = new List<Contact>(0);
  1427. for (int i = 0; i < parties.Length; i++)
  1428. {
  1429. Contact.ParseFullAccount(parties[i], out addressInfo, out account);
  1430. Contact party = ContactList.GetContact(account, addressInfo);
  1431. if (party != null)
  1432. partiesList.Add(party);
  1433. }
  1434. EndPointData senderEndPoint = null;
  1435. EndPointData receiverEndPoint = null;
  1436. if (routingInfo.Sender != null)
  1437. {
  1438. if (routingInfo.Sender.EndPointData.ContainsKey(routingInfo.SenderEndPointID))
  1439. senderEndPoint = routingInfo.Sender.EndPointData[routingInfo.SenderEndPointID];
  1440. }
  1441. if (routingInfo.Receiver != null)
  1442. {
  1443. if (routingInfo.Receiver.EndPointData.ContainsKey(routingInfo.ReceiverEndPointID))
  1444. receiverEndPoint = routingInfo.Receiver.EndPointData[routingInfo.ReceiverEndPointID];
  1445. }
  1446. OnRemoteEndPointCloseIMWindow(new CloseIMWindowEventArgs(routingInfo.Sender, senderEndPoint,
  1447. routingInfo.Receiver, receiverEndPoint,
  1448. partiesList.ToArray()));
  1449. }
  1450. private MultiMimeMessage ParseSDGTextPayloadMessage(MultiMimeMessage multiMimeMessage)
  1451. {
  1452. TextPayloadMessage textPayloadMessage = new TextPayloadMessage();
  1453. textPayloadMessage.CreateFromParentMessage(multiMimeMessage);
  1454. return multiMimeMessage;
  1455. }
  1456. private void OnSDGWinkReceived(MultiMimeMessage multiMimeMessage, Contact sender, Contact originalSender, RoutingInfo routingInfo)
  1457. {
  1458. Wink wink = new Wink();
  1459. wink.SetContext((multiMimeMessage.InnerMessage as TextPayloadMessage).Text);
  1460. OnWinkDefinitionReceived(new WinkEventArgs(originalSender, wink, routingInfo));
  1461. }
  1462. private MultiMimeMessage ParseSDGCustomEmoticonMessage(MultiMimeMessage multiMimeMessage)
  1463. {
  1464. EmoticonMessage emoticonMessage = new EmoticonMessage();
  1465. emoticonMessage.CreateFromParentMessage(multiMimeMessage);
  1466. emoticonMessage.EmoticonType = multiMimeMessage.ContentHeaders[MIMEContentHeaders.ContentType] == "text/x-mms-animemoticon" ?
  1467. EmoticonType.AnimEmoticon : EmoticonType.StaticEmoticon;
  1468. return multiMimeMessage;
  1469. }
  1470. private void OnSDGCustomEmoticonReceived(MultiMimeMessage multiMimeMessage, Contact sender, Contact originalSender, RoutingInfo routingInfo)
  1471. {
  1472. EmoticonMessage emoticonMessage = multiMimeMessage.InnerMessage as EmoticonMessage;
  1473. foreach (Emoticon emoticon in emoticonMessage.Emoticons)
  1474. {
  1475. OnEmoticonDefinitionReceived(new EmoticonDefinitionEventArgs(originalSender, originalSender, routingInfo, emoticon));
  1476. }
  1477. }
  1478. private MultiMimeMessage ParseSDGTextMessage(MultiMimeMessage multiMimeMessage)
  1479. {
  1480. TextMessage txtMessage = new TextMessage();
  1481. txtMessage.CreateFromParentMessage(multiMimeMessage);
  1482. return multiMimeMessage;
  1483. }
  1484. private void OnSDGTextMessageReceived(MultiMimeMessage multiMimeMessage, Contact sender, Contact by, RoutingInfo routingInfo)
  1485. {
  1486. TextMessage txtMessage = multiMimeMessage.InnerMessage as TextMessage;
  1487. OnTextMessageReceived(new TextMessageArrivedEventArgs(sender, txtMessage, by, routingInfo));
  1488. }
  1489. private MultiMimeMessage ParseSDGP2PSignalMessage(MultiMimeMessage multiMimeMessage)
  1490. {
  1491. SLPMessage slpMessage = SLPMessage.Parse(multiMimeMessage.InnerBody);
  1492. slpMessage.CreateFromParentMessage(multiMimeMessage);
  1493. return multiMimeMessage;
  1494. }
  1495. private void OnSDGP2PSignalReceived(MultiMimeMessage multiMimeMessage, Contact sender, Contact by, RoutingInfo routingInfo)
  1496. {
  1497. //SLPMessage slpMessage = SLPMessage.Parse(multiMimeMessage.InnerBody);
  1498. SLPMessage slpMessage = multiMimeMessage.InnerMessage as SLPMessage;
  1499. if (slpMessage != null)
  1500. {
  1501. if (slpMessage.ContentType == "application/x-msnmsgr-transreqbody" ||
  1502. slpMessage.ContentType == "application/x-msnmsgr-transrespbody" ||
  1503. slpMessage.ContentType == "application/x-msnmsgr-transdestaddrupdate")
  1504. {
  1505. P2PSession.ProcessDirectInvite(slpMessage, this, null);
  1506. }
  1507. }
  1508. }
  1509. private MultiMimeMessage ParseSDGDataMessage(MultiMimeMessage multiMimeMessage, Contact sender, Contact by)
  1510. {
  1511. return multiMimeMessage;
  1512. }
  1513. private void OnSDGDataMessageReceived(MultiMimeMessage multiMimeMessage, Contact sender, Contact by, RoutingInfo routingInfo)
  1514. {
  1515. Guid senderEPID = routingInfo.SenderEndPointID;
  1516. P2PVersion p2pVer = senderEPID == Guid.Empty ? P2PVersion.P2PV1 : P2PVersion.P2PV2;
  1517. string[] offsets = multiMimeMessage.ContentHeaders.ContainsKey(MIMEContentHeaders.BridgingOffsets) ?
  1518. multiMimeMessage.ContentHeaders[MIMEContentHeaders.BridgingOffsets].ToString().Split(',') :
  1519. new string[] { "0" };
  1520. List<long> offsetList = new List<long>();
  1521. foreach (string os in offsets)
  1522. {
  1523. offsetList.Add(long.Parse(os));
  1524. }
  1525. P2PMessage p2pData = new P2PMessage(p2pVer);
  1526. P2PMessage[] p2pDatas = p2pData.CreateFromOffsets(offsetList.ToArray(), multiMimeMessage.InnerBody);
  1527. if (multiMimeMessage.ContentHeaders.ContainsKey(MIMEContentHeaders.Pipe))
  1528. {
  1529. SDGBridge.PackageNo = ushort.Parse(multiMimeMessage.ContentHeaders[MIMEContentHeaders.Pipe]);
  1530. }
  1531. foreach (P2PMessage m in p2pDatas)
  1532. {
  1533. SDGBridge.ProcessP2PMessage(sender, senderEPID, m);
  1534. }
  1535. }
  1536. #endregion
  1537. #endregion
  1538. #endregion
  1539. }
  1540. };